From 9c06451739d5e4ff065425a90b68d795f90e95d1 Mon Sep 17 00:00:00 2001 From: Will Schurman Date: Mon, 7 Oct 2024 15:47:39 -0700 Subject: [PATCH 1/2] feat: add ability to set custom comment content --- __tests__/comment-upserter.test.ts | 78 ++++++++++++++++++++++++++---- __tests__/fixtures/codemention.yml | 3 ++ __tests__/runner.test.ts | 2 +- src/comment-upserter.ts | 58 ++++++++++++++-------- src/configuration.ts | 12 +++++ src/runner.ts | 19 ++++---- 6 files changed, 132 insertions(+), 40 deletions(-) diff --git a/__tests__/comment-upserter.test.ts b/__tests__/comment-upserter.test.ts index 1673397..c6411fe 100644 --- a/__tests__/comment-upserter.test.ts +++ b/__tests__/comment-upserter.test.ts @@ -3,7 +3,7 @@ import {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods' import {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types.d' import {EqualMatchingInjectorConfig, It, Mock, Times} from 'moq.ts' -import {CommentUpserterImpl, HEADER} from '../src/comment-upserter' +import {CommentUpserterImpl, DEFAULT_COMMENT_PREAMBLE, HEADER} from '../src/comment-upserter' import {Repo} from '../src/github-types' describe('CommentUpserterImpl', () => { @@ -35,13 +35,6 @@ describe('CommentUpserterImpl', () => { } ] - const commentBody = - HEADER + - [ - '| db/migrate/\\*\\* | @cto, @dba |', - '| .github/\\*\\*
spec/\\*.rb | @ci |' - ].join('\n') - const stubListComments = (comments: string[]): void => { const listResponse = { data: comments.map((comment, index) => ({id: index + 1, body: comment})) @@ -74,6 +67,16 @@ describe('CommentUpserterImpl', () => { }) it('creates a comment', async () => { + const expectedCommentBody = + HEADER + + [ + DEFAULT_COMMENT_PREAMBLE, + '| File Patterns | Mentions |', + '| - | - |', + '| db/migrate/\\*\\* | @cto, @dba |', + '| .github/\\*\\*
spec/\\*.rb | @ci |' + ].join('\n') + issuesMock .setup(instance => instance.createComment(It.IsAny())) .returnsAsync( @@ -88,7 +91,42 @@ describe('CommentUpserterImpl', () => { instance.createComment({ ...repo, issue_number: pullNumber, - body: commentBody + body: expectedCommentBody + }) + ) + }) + + it('creates a comment with custom comment content', async () => { + const customContent = { + preamble: 'Added you as a subscriber.', + epilogue: '> [CodeMention](https://github.com/tobyhs/codemention)' + } + const expectedCommentBody = + HEADER + + [ + customContent.preamble, + '| File Patterns | Mentions |', + '| - | - |', + '| db/migrate/\\*\\* | @cto, @dba |', + '| .github/\\*\\*
spec/\\*.rb | @ci |', + `\n${customContent.epilogue}` + ].join('\n') + + issuesMock + .setup(instance => instance.createComment(It.IsAny())) + .returnsAsync( + new Mock< + RestEndpointMethodTypes['issues']['createComment']['response'] + >().object() + ) + + await upserter.upsert(repo, pullNumber, rules, customContent) + + issuesMock.verify(instance => + instance.createComment({ + ...repo, + issue_number: pullNumber, + body: expectedCommentBody }) ) }) @@ -97,6 +135,16 @@ describe('CommentUpserterImpl', () => { describe('when a codemention comment exists', () => { describe('and the comment is different', () => { it('updates the comment', async () => { + const expectedCommentBody = + HEADER + + [ + DEFAULT_COMMENT_PREAMBLE, + '| File Patterns | Mentions |', + '| - | - |', + '| db/migrate/\\*\\* | @cto, @dba |', + '| .github/\\*\\*
spec/\\*.rb | @ci |' + ].join('\n') + const existingComment = HEADER + '| config/brakeman.yml | @security |' stubListComments(['First', existingComment]) @@ -114,7 +162,7 @@ describe('CommentUpserterImpl', () => { instance.updateComment({ ...repo, comment_id: 2, - body: commentBody + body: expectedCommentBody }) ) }) @@ -122,6 +170,16 @@ describe('CommentUpserterImpl', () => { describe('and the comment is the same', () => { it('does not update the comment', async () => { + const commentBody = + HEADER + + [ + DEFAULT_COMMENT_PREAMBLE, + '| File Patterns | Mentions |', + '| - | - |', + '| db/migrate/\\*\\* | @cto, @dba |', + '| .github/\\*\\*
spec/\\*.rb | @ci |' + ].join('\n') + stubListComments(['First', commentBody]) await upserter.upsert(repo, pullNumber, rules) diff --git a/__tests__/fixtures/codemention.yml b/__tests__/fixtures/codemention.yml index e831230..5d8f069 100644 --- a/__tests__/fixtures/codemention.yml +++ b/__tests__/fixtures/codemention.yml @@ -1,3 +1,6 @@ +commentConfiguration: + preamble: 'testing preamble' + epilogue: 'testing epilogue' rules: - patterns: ['config/**'] mentions: ['sysadmin'] diff --git a/__tests__/runner.test.ts b/__tests__/runner.test.ts index 911a0ab..c1aa8ea 100644 --- a/__tests__/runner.test.ts +++ b/__tests__/runner.test.ts @@ -97,7 +97,7 @@ describe('Runner', () => { } ] commentUpserterMock.verify(instance => - instance.upsert(repo, prNumber, matchingRules) + instance.upsert(repo, prNumber, matchingRules, {preamble: 'testing preamble', epilogue: 'testing epilogue'}) ) }) }) diff --git a/src/comment-upserter.ts b/src/comment-upserter.ts index 37c7ec8..80de554 100644 --- a/src/comment-upserter.ts +++ b/src/comment-upserter.ts @@ -2,15 +2,13 @@ import * as core from '@actions/core' import {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types.d' import markdownEscape from 'markdown-escape' -import {MentionRule} from './configuration' +import {CommentConfiguration, MentionRule} from './configuration' import {Repo} from './github-types' -export const HEADER = [ - '', - '[CodeMention](https://github.com/tobyhs/codemention):\n', - '| File Patterns | Mentions |', - '| - | - |\n' -].join('\n') +export const HEADER = '' + +export const DEFAULT_COMMENT_PREAMBLE = + '[CodeMention](https://github.com/tobyhs/codemention):' /** * @see {@link upsert} @@ -22,8 +20,14 @@ export interface CommentUpserter { * @param repo - repository that the pull request is in * @param pullNumber - number that identifies the pull request * @param rules - mention rules to use in the comment + * @param commentContent - comment content to print above matching rules table */ - upsert(repo: Repo, pullNumber: number, rules: MentionRule[]): Promise + upsert( + repo: Repo, + pullNumber: number, + rules: MentionRule[], + commentConfiguration?: CommentConfiguration + ): Promise } export class CommentUpserterImpl implements CommentUpserter { @@ -36,7 +40,8 @@ export class CommentUpserterImpl implements CommentUpserter { async upsert( repo: Repo, pullNumber: number, - rules: MentionRule[] + rules: MentionRule[], + commentConfiguration?: CommentConfiguration ): Promise { const issuesApi = this.octokitRest.issues const listResponse = await issuesApi.listComments({ @@ -47,7 +52,7 @@ export class CommentUpserterImpl implements CommentUpserter { const existingComment = listResponse.data.find( c => c.body !== undefined && c.body.startsWith(HEADER) ) - const commentBody = this.createCommentBody(rules) + const commentBody = this.createCommentBody(rules, commentConfiguration) if (existingComment === undefined) { if (rules.length > 0) { @@ -76,18 +81,31 @@ export class CommentUpserterImpl implements CommentUpserter { /** * @param rules - mention rules to use in the comment + * @param commentContent - comment content to print above matching rules table * @returns text to be used in a GitHub pull request comment body */ - private createCommentBody(rules: MentionRule[]): string { - const body = rules - .map(rule => { - const patterns = rule.patterns - .map(pattern => markdownEscape(pattern, ['slashes'])) - .join('
') - const mentions = rule.mentions.map(name => `@${name}`).join(', ') - return `| ${patterns} | ${mentions} |` - }) + private createCommentBody( + rules: MentionRule[], + commentConfiguration?: CommentConfiguration + ): string { + const mentionsTableRows = rules.map(rule => { + const patterns = rule.patterns + .map(pattern => markdownEscape(pattern, ['slashes'])) + .join('
') + const mentions = rule.mentions.map(name => `@${name}`).join(', ') + return `| ${patterns} | ${mentions} |` + }) + const content = [ + commentConfiguration?.preamble ?? DEFAULT_COMMENT_PREAMBLE, + '| File Patterns | Mentions |', + '| - | - |', + ...mentionsTableRows, + commentConfiguration?.epilogue + ? `\n${commentConfiguration.epilogue}` // need two line breaks to finish table before epilogue + : undefined + ] + .filter(elem => elem !== undefined) .join('\n') - return `${HEADER}${body}` + return `${HEADER}${content}` } } diff --git a/src/configuration.ts b/src/configuration.ts index 6dca500..f6f77b0 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -9,10 +9,22 @@ export interface MentionRule { mentions: string[] } +/** + * A set of configuration items for the comment posted by the bot + */ +export interface CommentConfiguration { + /** Comment content to print above matching rules table */ + preamble?: string + /** Comment content to print below matching rules table */ + epilogue?: string +} + /** * Configuration for the GitHub Action */ export interface Configuration { /** Rules for mentioning */ rules: MentionRule[] + /** Configuration for comment */ + commentConfiguration?: CommentConfiguration } diff --git a/src/runner.ts b/src/runner.ts index 01196c4..b8a1165 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -36,17 +36,18 @@ export default class Runner { return } - const configuration = await this.configurationReader.read( - repo, - pullRequest.base.sha - ) - const filesChanged = await this.filesChangedReader.read( - repo, - pullRequest.number - ) + const [configuration, filesChanged] = await Promise.all([ + this.configurationReader.read(repo, pullRequest.base.sha), + this.filesChangedReader.read(repo, pullRequest.number) + ]) const matchingRules = configuration.rules.filter( rule => micromatch(filesChanged, rule.patterns).length > 0 ) - await this.commentUpserter.upsert(repo, pullRequest.number, matchingRules) + await this.commentUpserter.upsert( + repo, + pullRequest.number, + matchingRules, + configuration.commentConfiguration + ) } } From 67625b633f4e6a0a3ebaf599959bf7a67de6ad84 Mon Sep 17 00:00:00 2001 From: Will Schurman Date: Mon, 7 Oct 2024 18:44:32 -0700 Subject: [PATCH 2/2] Address comment --- src/comment-upserter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comment-upserter.ts b/src/comment-upserter.ts index 80de554..823ad68 100644 --- a/src/comment-upserter.ts +++ b/src/comment-upserter.ts @@ -20,7 +20,7 @@ export interface CommentUpserter { * @param repo - repository that the pull request is in * @param pullNumber - number that identifies the pull request * @param rules - mention rules to use in the comment - * @param commentContent - comment content to print above matching rules table + * @param commentConfiguration - comment configuration for the upserted comment */ upsert( repo: Repo, @@ -81,7 +81,7 @@ export class CommentUpserterImpl implements CommentUpserter { /** * @param rules - mention rules to use in the comment - * @param commentContent - comment content to print above matching rules table + * @param commentConfiguration - comment configuration for the upserted comment * @returns text to be used in a GitHub pull request comment body */ private createCommentBody(