Skip to content

Commit

Permalink
feat: add configuration to exclude author from mentions
Browse files Browse the repository at this point in the history
  • Loading branch information
wschurman committed Oct 18, 2024
1 parent 6bf157a commit c45db8a
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 61 deletions.
65 changes: 33 additions & 32 deletions __tests__/comment-upserter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ 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, DEFAULT_COMMENT_PREAMBLE, FOOTER} from '../src/comment-upserter'
import {
CommentUpserterImpl,
DEFAULT_COMMENT_PREAMBLE,
FOOTER
} from '../src/comment-upserter'
import {Repo} from '../src/github-types'

describe('CommentUpserterImpl', () => {
Expand Down Expand Up @@ -67,16 +71,15 @@ describe('CommentUpserterImpl', () => {
})

it('creates a comment', async () => {
const expectedCommentBody =
[
DEFAULT_COMMENT_PREAMBLE,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
FOOTER
].join('\n')
const expectedCommentBody = [
DEFAULT_COMMENT_PREAMBLE,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
FOOTER
].join('\n')

issuesMock
.setup(instance => instance.createComment(It.IsAny()))
Expand All @@ -102,17 +105,16 @@ describe('CommentUpserterImpl', () => {
preamble: 'Added you as a subscriber.',
epilogue: '> [CodeMention](https://github.com/tobyhs/codemention)'
}
const expectedCommentBody =
[
customContent.preamble,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
customContent.epilogue,
FOOTER
].join('\n')
const expectedCommentBody = [
customContent.preamble,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
customContent.epilogue,
FOOTER
].join('\n')

issuesMock
.setup(instance => instance.createComment(It.IsAny()))
Expand All @@ -138,19 +140,19 @@ describe('CommentUpserterImpl', () => {
describe('and the comment is different', () => {
describe('and the comment has the sentinel at the start', () => {
it('updates the comment', async () => {
const expectedCommentBody =
[
const expectedCommentBody = [
DEFAULT_COMMENT_PREAMBLE,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
FOOTER,
FOOTER
].join('\n')

// previous version of the action put the sentinel comment at the start
const existingComment = FOOTER + '| config/brakeman.yml | @security |'
const existingComment =
FOOTER + '| config/brakeman.yml | @security |'
stubListComments(['First', existingComment])

issuesMock
Expand All @@ -175,18 +177,18 @@ describe('CommentUpserterImpl', () => {

describe('and the comment has the sentinel at the end', () => {
it('updates the comment', async () => {
const expectedCommentBody =
[
const expectedCommentBody = [
DEFAULT_COMMENT_PREAMBLE,
'| File Patterns | Mentions |',
'| - | - |',
'| db/migrate/\\*\\* | @cto, @dba |',
'| .github/\\*\\*<br>spec/\\*.rb | @ci |',
'',
FOOTER,
FOOTER
].join('\n')

const existingComment = '| config/brakeman.yml | @security |' + FOOTER
const existingComment =
'| config/brakeman.yml | @security |' + FOOTER
stubListComments(['First', existingComment])

issuesMock
Expand All @@ -212,8 +214,7 @@ describe('CommentUpserterImpl', () => {

describe('and the comment is the same', () => {
it('does not update the comment', async () => {
const commentBody =
[
const commentBody = [
DEFAULT_COMMENT_PREAMBLE,
'| File Patterns | Mentions |',
'| - | - |',
Expand Down
2 changes: 1 addition & 1 deletion __tests__/fixtures/codemention.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ commentConfiguration:
epilogue: 'testing epilogue'
rules:
- patterns: ['config/**']
mentions: ['sysadmin']
mentions: ['sysadmin', 'testlogin']
- patterns: ['db/migrate/**']
mentions: ['cto', 'dba']
- patterns: ['.github/**', 'spec/*.rb']
Expand Down
115 changes: 88 additions & 27 deletions __tests__/runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,43 @@ import {Repo} from '../src/github-types'
import Runner from '../src/runner'

describe('Runner', () => {
let configurationReader: ConfigurationReader
let filesChangedReader: FilesChangedReader
let commentUpserterMock: Mock<CommentUpserter>
let runner: Runner

let repo: Repo
let context: Context
const prNumber = 123
const baseSha = 'bfc5b2d29cfa2db8ce40f6c60bc9629490fe1225'
let pullRequest: PullRequest
const configuration: Configuration = yaml.load(
fs.readFileSync(path.join(__dirname, 'fixtures', 'codemention.yml'), 'utf8')
) as Configuration

beforeEach(() => {
repo = {owner: 'tobyhs', repo: 'codemention'}
pullRequest = {
function setUpDependencies({
draft,
prNumber,
baseSha,
excludeAuthor
}: {
draft: boolean
prNumber: number
baseSha: string
excludeAuthor?: boolean
}) {
const repo = {owner: 'tobyhs', repo: 'codemention'}
const pullRequest = {
number: prNumber,
base: {sha: baseSha},
draft: false
draft,
user: {
login: 'testlogin'
}
} as PullRequest
context = {
const context = {
repo,
payload: {pull_request: pullRequest}
} as unknown as Context

configurationReader = new Mock<ConfigurationReader>({
const configuration: Configuration = yaml.load(
fs.readFileSync(
path.join(__dirname, 'fixtures', 'codemention.yml'),
'utf8'
)
) as Configuration

if (excludeAuthor) {
configuration.excludeAuthor = true
}

const configurationReader = new Mock<ConfigurationReader>({
injectorConfig: new EqualMatchingInjectorConfig()
})
.setup(async instance => instance.read(repo, baseSha))
Expand All @@ -51,31 +61,40 @@ describe('Runner', () => {
'config/application.rb',
'.github/workflows/codemention.yml'
]
filesChangedReader = new Mock<FilesChangedReader>({
const filesChangedReader = new Mock<FilesChangedReader>({
injectorConfig: new EqualMatchingInjectorConfig()
})
.setup(async instance => instance.read(repo, prNumber))
.returnsAsync(filesChanged)
.object()

commentUpserterMock = new Mock<CommentUpserter>({
const commentUpserterMock = new Mock<CommentUpserter>({
injectorConfig: new EqualMatchingInjectorConfig()
})
commentUpserterMock
.setup(instance => instance.upsert(It.IsAny(), It.IsAny(), It.IsAny()))
.returns(Promise.resolve())

runner = new Runner(
const runner = new Runner(
configurationReader,
filesChangedReader,
commentUpserterMock.object()
)
})

return {repo, runner, context, commentUpserterMock}
}

describe('.run', () => {
describe('when the pull request is a draft', () => {
it('does not upsert a comment', async () => {
pullRequest.draft = true
const prNumber = 123
const baseSha = 'bfc5b2d29cfa2db8ce40f6c60bc9629490fe1225'
const {runner, context, commentUpserterMock} = setUpDependencies({
draft: true,
prNumber,
baseSha
})

await runner.run(context)
commentUpserterMock.verify(
instance => instance.upsert(It.IsAny(), It.IsAny(), It.IsAny()),
Expand All @@ -85,20 +104,62 @@ describe('Runner', () => {
})

it('runs main logic of the GitHub action', async () => {
const prNumber = 123
const baseSha = 'bfc5b2d29cfa2db8ce40f6c60bc9629490fe1225'
const {repo, runner, context, commentUpserterMock} = setUpDependencies({
draft: false,
prNumber,
baseSha
})

await runner.run(context)
const matchingRules = [
{
patterns: ['config/**'],
mentions: ['sysadmin']
mentions: ['sysadmin', 'testlogin']
},
{
patterns: ['.github/**', 'spec/*.rb'],
mentions: ['ci']
}
]
commentUpserterMock.verify(instance =>
instance.upsert(repo, prNumber, matchingRules, {preamble: 'testing preamble', epilogue: 'testing epilogue'})
instance.upsert(repo, prNumber, matchingRules, {
preamble: 'testing preamble',
epilogue: 'testing epilogue'
})
)
})

describe('when excludeAuthor configuration is specified', () => {
it('does not include the author in the comment', async () => {
const prNumber = 123
const baseSha = 'bfc5b2d29cfa2db8ce40f6c60bc9629490fe1225'
const {repo, runner, context, commentUpserterMock} = setUpDependencies({
draft: false,
prNumber,
baseSha,
excludeAuthor: true
})

await runner.run(context)
const matchingRules = [
{
patterns: ['config/**'],
mentions: ['sysadmin']
},
{
patterns: ['.github/**', 'spec/*.rb'],
mentions: ['ci']
}
]
commentUpserterMock.verify(instance =>
instance.upsert(repo, prNumber, matchingRules, {
preamble: 'testing preamble',
epilogue: 'testing epilogue'
})
)
})
})
})
})
2 changes: 2 additions & 0 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ export interface Configuration {
rules: MentionRule[]
/** Configuration for comment */
commentConfiguration?: CommentConfiguration
/** Whether to exclude PR author from mentions */
excludeAuthor?: boolean
}
13 changes: 12 additions & 1 deletion src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import micromatch from 'micromatch'
import {CommentUpserter} from './comment-upserter'
import {ConfigurationReader} from './configuration-reader'
import {FilesChangedReader} from './files-changed-reader'
import {MentionRule} from './configuration'

/**
* @see {@link run}
Expand Down Expand Up @@ -43,10 +44,20 @@ export default class Runner {
const matchingRules = configuration.rules.filter(
rule => micromatch(filesChanged, rule.patterns).length > 0
)
const filteredRules = configuration.excludeAuthor
? matchingRules
.map((rule: MentionRule) => ({
...rule,
mentions: rule.mentions.filter(
mention => mention !== pullRequest.user.login
)
}))
.filter(rule => rule.mentions.length > 0)
: matchingRules
await this.commentUpserter.upsert(
repo,
pullRequest.number,
matchingRules,
filteredRules,
configuration.commentConfiguration
)
}
Expand Down

0 comments on commit c45db8a

Please sign in to comment.