Skip to content

Commit

Permalink
feat: Support 'issue_comment' event as trigger for actions (#754)
Browse files Browse the repository at this point in the history
  • Loading branch information
andekande committed Jun 18, 2024
1 parent 3beeb24 commit 196099e
Show file tree
Hide file tree
Showing 22 changed files with 203 additions and 32 deletions.
2 changes: 1 addition & 1 deletion __fixtures__/unit/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ module.exports = {
},
requestReviewers: jest.fn().mockReturnValue(options.requestReviewers || 'request review success'),
merge: jest.fn().mockReturnValue(options.merge || 'merged'),
get: jest.fn()
get: jest.fn().mockReturnValue({ data: { head: { ref: 'test', sha: 'sha1' } } })
},
paginate: jest.fn(async (fn, cb) => {
return fn.then(cb)
Expand Down
33 changes: 25 additions & 8 deletions __tests__/unit/actions/assign.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
const Assign = require('../../../lib/actions/assign')
const Helper = require('../../../__fixtures__/unit/helper')

test.each([
undefined,
'pull_request',
'issues',
'issue_comment'
])('check that assign is called for %s events', async (eventName) => {
const settings = {
assignees: []
}

const assign = new Assign()
const context = createMockContext(eventName)

await assign.afterValidate(context, settings)
expect(context.octokit.issues.addAssignees.mock.calls.length).toBe(1)
})

test('check that assignees are added when afterValidate is called with proper parameter', async () => {
const settings = {
assignees: ['testuser1', 'testuser2']
}

const comment = new Assign()
const assign = new Assign()
const context = createMockContext()

await comment.afterValidate(context, settings)
await assign.afterValidate(context, settings)
expect(context.octokit.issues.addAssignees.mock.calls.length).toBe(1)
expect(context.octokit.issues.addAssignees.mock.calls[0][0].assignees[0]).toBe('testuser1')
expect(context.octokit.issues.addAssignees.mock.calls[0][0].assignees[1]).toBe('testuser2')
Expand All @@ -20,10 +37,10 @@ test('check that creator is added when assignee is @author', async () => {
assignees: ['@author']
}

const comment = new Assign()
const assign = new Assign()
const context = createMockContext()

await comment.afterValidate(context, settings)
await assign.afterValidate(context, settings)
expect(context.octokit.issues.addAssignees.mock.calls.length).toBe(1)
expect(context.octokit.issues.addAssignees.mock.calls[0][0].assignees[0]).toBe('creator')
})
Expand All @@ -33,7 +50,7 @@ test('check only authorized users are added as assignee ', async () => {
assignees: ['testuser1', 'testuser2']
}

const comment = new Assign()
const assign = new Assign()
const context = createMockContext()

context.octokit.issues.checkUserCanBeAssigned = (input) => {
Expand All @@ -45,14 +62,14 @@ test('check only authorized users are added as assignee ', async () => {
})
}

await comment.afterValidate(context, settings)
await assign.afterValidate(context, settings)
expect(context.octokit.issues.addAssignees.mock.calls.length).toBe(1)
expect(context.octokit.issues.addAssignees.mock.calls[0][0].assignees[0]).toBe('testuser1')
expect(context.octokit.issues.addAssignees.mock.calls[0][0].assignees[1]).toBeUndefined()
})

const createMockContext = () => {
const context = Helper.mockContext()
const createMockContext = (eventName = undefined) => {
const context = Helper.mockContext({ eventName })

context.octokit.issues.addAssignees = jest.fn()
return context
Expand Down
37 changes: 33 additions & 4 deletions __tests__/unit/actions/checks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,43 @@ const MetaData = require('../../../lib/metaData')
const Checks = require('../../../lib/actions/checks')
const Helper = require('../../../__fixtures__/unit/helper')

test('run', async () => {
test.each([
undefined,
'pull_request',
'pull_request_review',
'issue_comment'
])('that checks is called for %s events', async (eventName) => {
const checks = new Checks()
const context = createMockContext(eventName)
const result = {}
const settings = {
payload: {},
state: 'completed',
status: 'success'
}

const name = undefined

checks.checkRunResult = new Map()

checks.checkRunResult.set(name, {
data: {
id: '3'
}
})

await checks.afterValidate(context, settings, name, result)
expect(context.octokit.checks.update.mock.calls.length).toBe(1)
})

test('that run calls create api', async () => {
const checks = new Checks()
const context = createMockContext()
await checks.run({ context, payload: {} })
expect(context.octokit.checks.create.mock.calls.length).toBe(1)
})

test('check that checks created when doPostAction is called with proper parameter', async () => {
test('that checks created when doPostAction is called with proper parameter', async () => {
const checks = new Checks()
const context = createMockContext()
const settings = { name: 'test' }
Expand Down Expand Up @@ -183,8 +212,8 @@ test('that correct name is used afterValidate payload', async () => {
expect(MetaData.exists(output.text)).toBe(true)
})

const createMockContext = () => {
const context = Helper.mockContext()
const createMockContext = (eventName = undefined) => {
const context = Helper.mockContext({ eventName })
context.payload.action = 'actionName'
context.octokit.checks.create = jest.fn()
context.octokit.checks.update = jest.fn()
Expand Down
22 changes: 22 additions & 0 deletions __tests__/unit/actions/close.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
const Close = require('../../../lib/actions/close')
const Helper = require('../../../__fixtures__/unit/helper')

test.each([
undefined,
'pull_request',
'issues',
'issue_comment',
'schedule'
])('check that close is called for %s events', async (eventName) => {
const close = new Close()
const context = Helper.mockContext({ eventName: eventName })
const schedulerResult = {
validationSuites: [{
schedule: {
issues: [{ number: 1, user: { login: 'scheduler' } }],
pulls: []
}
}]
}

await close.afterValidate(context, {}, '', schedulerResult)
expect(context.octokit.issues.update.mock.calls.length).toBe(1)
})

test('check that issue is closed', async () => {
const close = new Close()
const context = Helper.mockContext()
Expand Down
28 changes: 24 additions & 4 deletions __tests__/unit/actions/comment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ const result = {
}]
}

test.each([
undefined,
'pull_request',
'issues',
'issue_comment',
'schedule'
])('check that comment is called for %s events', async (eventName) => {
const comment = new Comment()
const context = createMockContext([], eventName)
const schedulerResult = { ...result }
schedulerResult.validationSuites = [{
schedule: {
issues: [{ number: 1, user: { login: 'scheduler' } }],
pulls: []
}
}]

await comment.afterValidate(context, settings, '', schedulerResult)
expect(context.octokit.issues.createComment.mock.calls.length).toBe(1)
})

test('check that comment created when afterValidate is called with proper parameter', async () => {
const comment = new Comment()
const context = createMockContext()
Expand All @@ -34,8 +55,7 @@ test('check that comment created when afterValidate is called with proper parame

test('that comment is created three times when result contain three issues found to be acted on', async () => {
const comment = new Comment()
const context = createMockContext([], 'repository')
context.eventName = 'schedule'
const context = createMockContext([], 'schedule', 'repository')
const schedulerResult = { ...result }
schedulerResult.validationSuites = [{
schedule: {
Expand Down Expand Up @@ -236,8 +256,8 @@ test('error handling includes removing old error comments and creating new error
expect(context.octokit.issues.createComment.mock.calls[0][0].body).toBe('creator , do something!')
})

const createMockContext = (listComments, event = undefined) => {
const context = Helper.mockContext({ listComments, event })
const createMockContext = (listComments, eventName = undefined, event = undefined) => {
const context = Helper.mockContext({ listComments, eventName, event })

context.octokit.issues.createComment = jest.fn()
context.octokit.issues.deleteComment = jest.fn()
Expand Down
25 changes: 25 additions & 0 deletions __tests__/unit/actions/labels.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@ const Labels = require('../../../lib/actions/labels')
const Helper = require('../../../__fixtures__/unit/helper')
const UnSupportedSettingError = require('../../../lib/errors/unSupportedSettingError')

test.each([
undefined,
'pull_request',
'issues',
'issue_comment',
'schedule'
])('check that close is called for %s events', async (eventName) => {
const labels = new Labels()
const context = createMockContext([], eventName)
const settings = {
add: ['a label']
}
const schedulerResult = {
validationSuites: [{
schedule: {
issues: [{ number: 1, user: { login: 'scheduler' } }],
pulls: []
}
}]
}

await labels.afterValidate(context, settings, '', schedulerResult)
expect(context.octokit.issues.setLabels.mock.calls.length).toBe(1)
})

test('check that replace replaces existing labels', async () => {
const labels = new Labels()
const context = createMockContext(['drop_label'])
Expand Down
36 changes: 36 additions & 0 deletions __tests__/unit/configuration/transformers/v2Config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,42 @@ test('pass, fail, error defaults will load when pull_request is mixed with other
expect(transformed.mergeable[0].error).toEqual(constants.DEFAULT_PR_ERROR)
})

test('pass, fail, error defaults will load when issue_comment event is specified.', () => {
const config = `
version: 2
mergeable:
- when: issue_comment.*
validate:
- do: lastComment
must_exclude:
regex: 'wip|work in progress'
`
const transformed = V2Config.transform(yaml.safeLoad(config))

expect(transformed.mergeable[0].pass).toEqual(constants.DEFAULT_PR_PASS)
expect(transformed.mergeable[0].fail).toEqual(constants.DEFAULT_PR_FAIL)
expect(transformed.mergeable[0].error).toEqual(constants.DEFAULT_PR_ERROR)
})

test('pass, fail, error defaults will load when pull_request_review event is specified.', () => {
const config = `
version: 2
mergeable:
- when: pull_request_review.*
validate:
- do: payload
review:
state:
must_exclude:
regex: 'changes_requested'
`
const transformed = V2Config.transform(yaml.safeLoad(config))

expect(transformed.mergeable[0].pass).toEqual(constants.DEFAULT_PR_PASS)
expect(transformed.mergeable[0].fail).toEqual(constants.DEFAULT_PR_FAIL)
expect(transformed.mergeable[0].error).toEqual(constants.DEFAULT_PR_ERROR)
})

test('only pass, fail defaults ignore recipes that are not for pull_requests', () => {
const config = `
version: 2
Expand Down
4 changes: 3 additions & 1 deletion docs/actions/assign.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Assign
^^^^^^^^

You can assign specific people to a pull request or issue.

::

- do: assign
Expand All @@ -9,4 +11,4 @@ Assign
Supported Events:
::

'pull_request.*', 'issues.*'
'pull_request.*', 'issues.*', 'issue_comment.*'
6 changes: 4 additions & 2 deletions docs/actions/check.rst → docs/actions/checks.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Check
Checks
^^^^^^^^

You can add check runs to a pull request to enforce that it can only be merged once all checks returned with success.

.. note::
The logic for whether checks will be added by default is as follows:
1. If no action is provided in either pass, fail or error , add `checks` as default (to be backward compatible)
Expand Down Expand Up @@ -74,4 +76,4 @@ The `pull_request.closed` event is not supported since it does not have meaningf

::

'pull_request.assigned', 'pull_request.auto_merge_disabled', 'pull_request.auto_merge_enabled', 'pull_request.converted_to_draft', 'pull_request.demilestoned', 'pull_request.dequeued', 'pull_request.edited', 'pull_request.enqueued', 'pull_request.labeled', 'pull_request.locked', 'pull_request.milestoned', 'pull_request.opened', 'pull_request.push_synchronize', 'pull_request.ready_for_review', 'pull_request.reopened', 'pull_request.review_request_removed', 'pull_request.review_requested', 'pull_request.synchronize', 'pull_request.unassigned', 'pull_request.unlabeled', 'pull_request.unlocked', 'pull_request_review.dismissed', 'pull_request_review.edited', 'pull_request_review.submitted'
'pull_request.assigned', 'pull_request.auto_merge_disabled', 'pull_request.auto_merge_enabled', 'pull_request.converted_to_draft', 'pull_request.demilestoned', 'pull_request.dequeued', 'pull_request.edited', 'pull_request.enqueued', 'pull_request.labeled', 'pull_request.locked', 'pull_request.milestoned', 'pull_request.opened', 'pull_request.push_synchronize', 'pull_request.ready_for_review', 'pull_request.reopened', 'pull_request.review_request_removed', 'pull_request.review_requested', 'pull_request.synchronize', 'pull_request.unassigned', 'pull_request.unlabeled', 'pull_request.unlocked', 'pull_request_review.dismissed', 'pull_request_review.edited', 'pull_request_review.submitted', 'issue_comment.*'
4 changes: 3 additions & 1 deletion docs/actions/close.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
Close
^^^^^^^^

You can close a pull request or issue.

::

- do: close

Supported Events:
::

'schedule.repository', 'pull_request.*', 'issues.*'
'schedule.repository', 'pull_request.*', 'issues.*', 'issue_comment.*'
4 changes: 3 additions & 1 deletion docs/actions/comment.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Comment
^^^^^^^^

You can add a comment to a pull request or issue.

::

- do: comment
Expand All @@ -12,4 +14,4 @@ Comment
Supported Events:
::

'schedule.repository', 'pull_request.*', 'issues.*'
'schedule.repository', 'pull_request.*', 'issues.*', 'issue_comment.*'
2 changes: 1 addition & 1 deletion docs/actions/labels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ Note that the glob functionality is powered by the minimatch library. Please see
Supported Events:
::

'schedule.repository', 'pull_request.*', 'issues.*'
'schedule.repository', 'pull_request.*', 'issues.*', 'issue_comment.*'
4 changes: 3 additions & 1 deletion docs/actions/merge.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Merge
^^^^^^^^

You can merge a pull request and specify the merge method used.

::

- do: merge
Expand All @@ -14,4 +16,4 @@ Merge
Supported Events:
::

'pull_request.*', 'pull_request_review.*', 'status.*', 'check_suite.*'
'pull_request.*', 'pull_request_review.*', 'status.*', 'check_suite.*', 'issue_comment.*'
2 changes: 1 addition & 1 deletion docs/actions/request_review.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Request Review
^^^^^^^^^^^^^^^

You can request specific reviews from specific reviewers, teams, or both
You can request specific reviews from specific reviewers, teams, or both for a pull request.

::

Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CHANGELOG
=====================================
| June 12, 2024: feat: Support `issue_comment` event as trigger for actions `#754 <https://github.com/mergeability/mergeable/pull/754>`_
| June 10, 2024: fix: Docker image not working `#753 <https://github.com/mergeability/mergeable/pull/753>`_
| June 10, 2024: feat: publish multi arch docker image to dockerhub `#751 <https://github.com/mergeability/mergeable/pull/751>`_
| April 29, 2024: fix: Always allow assigning author `#744 <https://github.com/mergeability/mergeable/pull/744>`_
Expand Down
Loading

0 comments on commit 196099e

Please sign in to comment.