Skip to content

Commit a430400

Browse files
authored
feat: Add more supported events to baseRef validator (#598)
- The auto-merge workflow (using the `merge` action) listens to `check_suite.*` events in addition to the more standard `pull-request.*` and `pull_request_review.*`. This workflow relies on branch protections to stop the merge while the check_suite is running. Since branch protections are usually setup **only** only on the default branch it means PRs that are targetting non-default branches are auto-merged by the workflow sometime before the check suite has even completed (if `check_suite.*` is used). - Add `check_suite.*` event support to the baseRef validator so that auto-merge can be limited to the default branch. - If more than one pull request is associated with a check_suite the validator will validate ALL of them and only pass if ALL of them pass - If NO pull requests are associated with a check_suite the validator considers this to be a failure since there is no baseRef to validate - Add unit tests for check_suite events.
1 parent 577cc12 commit a430400

File tree

4 files changed

+130
-6
lines changed

4 files changed

+130
-6
lines changed

__tests__/unit/validators/baseRef.test.js

+98
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ test('checks that it fail when exclude regex is in baseRef', async () => {
3535
expect(baseRefValidation.status).toBe('fail')
3636
})
3737

38+
test('checks that it passes when exclude regex is not in baseRef', async () => {
39+
const baseRef = new BaseRef()
40+
41+
const settings = {
42+
do: 'baseRef',
43+
must_exclude: {
44+
regex: 'wip'
45+
}
46+
}
47+
48+
const baseRefValidation = await baseRef.processValidate(mockContext('foo'), settings)
49+
expect(baseRefValidation.status).toBe('pass')
50+
})
51+
52+
test('checks that it passes when include regex is in baseRef', async () => {
53+
const baseRef = new BaseRef()
54+
55+
const settings = {
56+
do: 'baseRef',
57+
must_include: {
58+
regex: '^\\(feat\\)|^\\(doc\\)|^\\(fix\\)'
59+
}
60+
}
61+
62+
const baseRefValidation = await baseRef.processValidate(mockContext('(feat) foo'), settings)
63+
expect(baseRefValidation.status).toBe('pass')
64+
})
65+
3866
test('checks that advance setting of must_include works', async () => {
3967
const baseRef = new BaseRef()
4068

@@ -61,7 +89,77 @@ test('checks that advance setting of must_include works', async () => {
6189
expect(baseRefValidation.status).toBe('fail')
6290
})
6391

92+
test('fail when exclude regex is in baseRef of single check_suite pull request', async () => {
93+
const baseRef = new BaseRef()
94+
95+
const settings = {
96+
do: 'baseRef',
97+
must_exclude: {
98+
regex: 'wip'
99+
}
100+
}
101+
102+
const context = mockCheckSuiteContext(['WIP foo'])
103+
104+
const baseRefValidation = await baseRef.processValidate(context, settings)
105+
expect(baseRefValidation.status).toBe('fail')
106+
})
107+
108+
test('fail when exclude regex is in one baseRef of multiple check_suite pull requests', async () => {
109+
const baseRef = new BaseRef()
110+
111+
const settings = {
112+
do: 'baseRef',
113+
must_exclude: {
114+
regex: 'wip'
115+
}
116+
}
117+
118+
const context = mockCheckSuiteContext(['foo', 'WIP bar', 'baz'])
119+
120+
const baseRefValidation = await baseRef.processValidate(context, settings)
121+
expect(baseRefValidation.status).toBe('fail')
122+
})
123+
124+
test('pass when exclude regex is not in any baseRef of multiple check_suite pull requests', async () => {
125+
const baseRef = new BaseRef()
126+
127+
const settings = {
128+
do: 'baseRef',
129+
must_exclude: {
130+
regex: 'wip'
131+
}
132+
}
133+
134+
const context = mockCheckSuiteContext(['foo', 'bar', 'baz'])
135+
136+
const baseRefValidation = await baseRef.processValidate(context, settings)
137+
expect(baseRefValidation.status).toBe('pass')
138+
})
139+
140+
test('fail when include regex exists and there are no pull requests in check_suite', async () => {
141+
const baseRef = new BaseRef()
142+
143+
const settings = {
144+
do: 'baseRef',
145+
must_include: {
146+
regex: 'foo'
147+
}
148+
}
149+
150+
const context = mockCheckSuiteContext([])
151+
152+
const baseRefValidation = await baseRef.processValidate(context, settings)
153+
expect(baseRefValidation.status).toBe('fail')
154+
})
155+
64156
const mockContext = baseRef => {
65157
const context = Helper.mockContext({ baseRef: baseRef })
66158
return context
67159
}
160+
161+
const mockCheckSuiteContext = baseRefs => {
162+
const context = Helper.mockContext({ eventName: 'check_suite' })
163+
context.payload.check_suite.pull_requests = baseRefs.map(baseRef => ({ base: { ref: baseRef } }))
164+
return context
165+
}

docs/changelog.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
CHANGELOG
22
=====================================
3+
| November 25, 2021: feat: Add more supported events to baseRef validator `#395 <https://github.com/mergeability/mergeable/issues/395#issuecomment-975763927>` _
34
| November 12, 2021 : feat: Add baseRef filter `#596 <https://github.com/mergeability/mergeable/pull/596>`_
45
| October 19, 2021 : feat: Add validator approval option to exclude users `#594 <https://github.com/mergeability/mergeable/pull/594>`_
56
| October 12, 2021 : feat: Add boolean option for payload filter `#583 <https://github.com/mergeability/mergeable/pull/583>`_

docs/validators/baseRef.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ Simple example:
2626
Supported Events:
2727
::
2828

29-
'pull_request.*', 'pull_request_review.*'
29+
'pull_request.*', 'pull_request_review.*', 'check_suite.*'

lib/validators/baseRef.js

+30-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
const { Validator } = require('./validator')
2+
const consolidateResults = require('./options_processor/options/lib/consolidateResults')
3+
const constructOutput = require('./options_processor/options/lib/constructOutput')
24

35
class BaseRef extends Validator {
46
constructor () {
57
super('baseRef')
68
this.supportedEvents = [
79
'pull_request.*',
8-
'pull_request_review.*'
10+
'pull_request_review.*',
11+
'check_suite.*'
912
]
1013
this.supportedSettings = {
1114
must_include: {
@@ -22,10 +25,32 @@ class BaseRef extends Validator {
2225
}
2326

2427
async validate (context, validationSettings) {
25-
return this.processOptions(
26-
validationSettings,
27-
this.getPayload(context).base.ref
28-
)
28+
const payload = this.getPayload(context)
29+
30+
if (context.eventName === 'check_suite') {
31+
return this.validateCheckSuite(payload, validationSettings)
32+
}
33+
34+
return this.processOptions(validationSettings, payload.base.ref)
35+
}
36+
37+
async validateCheckSuite (payload, validationSettings) {
38+
// A check_suite's payload contains multiple pull_requests
39+
// Need to make sure that each pull_request's base ref is valid
40+
const validatorContext = { name: 'baseRef' }
41+
const baseRefs = payload.pull_requests.map(pullRequest => pullRequest.base.ref)
42+
43+
// If a check_suite has NO associated pull requests it is considered
44+
// a failed validation since there is no baseRef to validate
45+
if (baseRefs.length === 0) {
46+
return constructOutput({ name: 'baseRef' }, undefined, validationSettings, { status: 'fail', description: 'No pull requests associated with check_suite' })
47+
}
48+
49+
const results = await Promise.all(baseRefs.map(
50+
baseRef => this.processOptions(validationSettings, baseRef)
51+
))
52+
53+
return consolidateResults(results, validatorContext)
2954
}
3055
}
3156

0 commit comments

Comments
 (0)