Skip to content

Commit 83c61e2

Browse files
authored
Merge pull request #10 from alejandrohdezma/master
Add `require_passed_checks` input to control if should skip checks step by @alejandrohdezma
2 parents 7033c5a + eba2a02 commit 83c61e2

File tree

5 files changed

+126
-105
lines changed

5 files changed

+126
-105
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
The job of the action is to help click "Update branch" button for you. Designed to work with the `auto-merge` and ["Require branches to be up to date before merging"](https://docs.github.com/en/github/administering-a-repository/about-protected-branches#require-status-checks-before-merging) options. It will update the newest open PR that match the below conditions
99

1010
- The PR has the `auto-merge` option enabled
11-
- The PR has 2 approvals and no changes-requested review
12-
- The PR has all checks passed
11+
- The PR has 2 approvals and no changes-requested review (configurable)
12+
- The PR has all checks passed (configurable)
1313
- The PR branch has no conflicts with the base branch
1414
- The PR branch is behind the base branch
1515

@@ -54,7 +54,13 @@ The action will skip PRs that have less approvals than `required_approval_count`
5454

5555
We could retrieve this value from the repo settings through an API call but that will incur one more request. GitHub has [rate limit](https://docs.github.com/en/actions/reference/usage-limits-billing-and-administration#usage-limits) on API usage of GitHub actions.
5656

57-
> API requests - You can execute up to 1000 API requests in an hour across all actions within a repository. If exceeded, additional API calls will fail, which might cause jobs to fail.
57+
### `require_passed_checks`
58+
59+
**Optional**
60+
61+
Default: true
62+
63+
The action will skip PRs that have failed checks.
5864

5965
## Example usage
6066

@@ -75,6 +81,7 @@ jobs:
7581
token: ${{ secrets.ACTION_USER_TOKEN }}
7682
base: 'master'
7783
required_approval_count: 2
84+
require_passed_checks: false
7885
```
7986
8087
Replace the `VERSION_YOU_WANT_TO_USE` with the actual version you want to use, check the version format [here](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses)

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ inputs:
1515
required: true
1616
description: 'The action will skip PRs that have less approvals than this value'
1717
default: '2'
18+
require_passed_checks:
19+
required: false
20+
description: "If the action should skip PRs that have failed checks, defaults to `true`"
21+
default: "true"
1822
runs:
1923
using: 'node12'
2024
main: 'dest/index.js'

dest/index.js

Lines changed: 57 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,7 +1461,7 @@ exports.Octokit = Octokit;
14611461

14621462
Object.defineProperty(exports, "__esModule", ({ value: true }));
14631463

1464-
var isPlainObject = __nccwpck_require__(558);
1464+
var isPlainObject = __nccwpck_require__(287);
14651465
var universalUserAgent = __nccwpck_require__(429);
14661466

14671467
function lowercaseKeys(object) {
@@ -1849,52 +1849,6 @@ exports.endpoint = endpoint;
18491849
//# sourceMappingURL=index.js.map
18501850

18511851

1852-
/***/ }),
1853-
1854-
/***/ 558:
1855-
/***/ ((__unused_webpack_module, exports) => {
1856-
1857-
"use strict";
1858-
1859-
1860-
Object.defineProperty(exports, "__esModule", ({ value: true }));
1861-
1862-
/*!
1863-
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
1864-
*
1865-
* Copyright (c) 2014-2017, Jon Schlinkert.
1866-
* Released under the MIT License.
1867-
*/
1868-
1869-
function isObject(o) {
1870-
return Object.prototype.toString.call(o) === '[object Object]';
1871-
}
1872-
1873-
function isPlainObject(o) {
1874-
var ctor,prot;
1875-
1876-
if (isObject(o) === false) return false;
1877-
1878-
// If has modified constructor
1879-
ctor = o.constructor;
1880-
if (ctor === undefined) return true;
1881-
1882-
// If has modified prototype
1883-
prot = ctor.prototype;
1884-
if (isObject(prot) === false) return false;
1885-
1886-
// If constructor does not have an Object-specific method
1887-
if (prot.hasOwnProperty('isPrototypeOf') === false) {
1888-
return false;
1889-
}
1890-
1891-
// Most likely a plain Object
1892-
return true;
1893-
}
1894-
1895-
exports.isPlainObject = isPlainObject;
1896-
1897-
18981852
/***/ }),
18991853

19001854
/***/ 668:
@@ -3382,7 +3336,7 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau
33823336

33833337
var endpoint = __nccwpck_require__(440);
33843338
var universalUserAgent = __nccwpck_require__(429);
3385-
var isPlainObject = __nccwpck_require__(62);
3339+
var isPlainObject = __nccwpck_require__(287);
33863340
var nodeFetch = _interopDefault(__nccwpck_require__(467));
33873341
var requestError = __nccwpck_require__(537);
33883342

@@ -3524,52 +3478,6 @@ exports.request = request;
35243478
//# sourceMappingURL=index.js.map
35253479

35263480

3527-
/***/ }),
3528-
3529-
/***/ 62:
3530-
/***/ ((__unused_webpack_module, exports) => {
3531-
3532-
"use strict";
3533-
3534-
3535-
Object.defineProperty(exports, "__esModule", ({ value: true }));
3536-
3537-
/*!
3538-
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
3539-
*
3540-
* Copyright (c) 2014-2017, Jon Schlinkert.
3541-
* Released under the MIT License.
3542-
*/
3543-
3544-
function isObject(o) {
3545-
return Object.prototype.toString.call(o) === '[object Object]';
3546-
}
3547-
3548-
function isPlainObject(o) {
3549-
var ctor,prot;
3550-
3551-
if (isObject(o) === false) return false;
3552-
3553-
// If has modified constructor
3554-
ctor = o.constructor;
3555-
if (ctor === undefined) return true;
3556-
3557-
// If has modified prototype
3558-
prot = ctor.prototype;
3559-
if (isObject(prot) === false) return false;
3560-
3561-
// If constructor does not have an Object-specific method
3562-
if (prot.hasOwnProperty('isPrototypeOf') === false) {
3563-
return false;
3564-
}
3565-
3566-
// Most likely a plain Object
3567-
return true;
3568-
}
3569-
3570-
exports.isPlainObject = isPlainObject;
3571-
3572-
35733481
/***/ }),
35743482

35753483
/***/ 682:
@@ -3775,6 +3683,52 @@ class Deprecation extends Error {
37753683
exports.Deprecation = Deprecation;
37763684

37773685

3686+
/***/ }),
3687+
3688+
/***/ 287:
3689+
/***/ ((__unused_webpack_module, exports) => {
3690+
3691+
"use strict";
3692+
3693+
3694+
Object.defineProperty(exports, "__esModule", ({ value: true }));
3695+
3696+
/*!
3697+
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
3698+
*
3699+
* Copyright (c) 2014-2017, Jon Schlinkert.
3700+
* Released under the MIT License.
3701+
*/
3702+
3703+
function isObject(o) {
3704+
return Object.prototype.toString.call(o) === '[object Object]';
3705+
}
3706+
3707+
function isPlainObject(o) {
3708+
var ctor,prot;
3709+
3710+
if (isObject(o) === false) return false;
3711+
3712+
// If has modified constructor
3713+
ctor = o.constructor;
3714+
if (ctor === undefined) return true;
3715+
3716+
// If has modified prototype
3717+
prot = ctor.prototype;
3718+
if (isObject(prot) === false) return false;
3719+
3720+
// If constructor does not have an Object-specific method
3721+
if (prot.hasOwnProperty('isPrototypeOf') === false) {
3722+
return false;
3723+
}
3724+
3725+
// Most likely a plain Object
3726+
return true;
3727+
}
3728+
3729+
exports.isPlainObject = isPlainObject;
3730+
3731+
37783732
/***/ }),
37793733

37803734
/***/ 467:
@@ -5978,6 +5932,8 @@ const getAutoUpdateCandidate = async (openPRs) => {
59785932
if (!openPRs) return null;
59795933

59805934
const requiredApprovalCount = github_core.getInput('required_approval_count');
5935+
const requirePassedChecks = /true/i.test(github_core.getInput('require_passed_checks'));
5936+
59815937
// only update `auto merge` enabled PRs
59825938
const autoMergeEnabledPRs = openPRs.filter((item) => item.auto_merge);
59835939
log(`Count of auto-merge enabled PRs: ${autoMergeEnabledPRs.length}`);
@@ -6024,12 +5980,15 @@ const getAutoUpdateCandidate = async (openPRs) => {
60245980

60255981
/**
60265982
* #3 check whether the pr has failed checks
5983+
* only happens if require_passed_checks input is true
60275984
* need to note: the mergeable, and mergeable_state don't reflect the checks status
60285985
*/
6029-
const didChecksPass = await areAllChecksPassed(sha);
6030-
if (!didChecksPass) {
6031-
printFailReason(pullNumber, 'The PR has failed or ongoing check(s)');
6032-
continue;
5986+
if (requirePassedChecks) {
5987+
const didChecksPass = await areAllChecksPassed(sha);
5988+
if (!didChecksPass) {
5989+
printFailReason(pullNumber, 'The PR has failed or ongoing check(s)');
5990+
continue;
5991+
}
60335992
}
60345993

60355994
return pr;

src/lib/github.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export const getAutoUpdateCandidate = async (openPRs) => {
137137
if (!openPRs) return null;
138138

139139
const requiredApprovalCount = core.getInput('required_approval_count');
140+
const requirePassedChecks = /true/i.test(core.getInput('require_passed_checks'));
141+
140142
// only update `auto merge` enabled PRs
141143
const autoMergeEnabledPRs = openPRs.filter((item) => item.auto_merge);
142144
log(`Count of auto-merge enabled PRs: ${autoMergeEnabledPRs.length}`);
@@ -183,12 +185,15 @@ export const getAutoUpdateCandidate = async (openPRs) => {
183185

184186
/**
185187
* #3 check whether the pr has failed checks
188+
* only happens if require_passed_checks input is true
186189
* need to note: the mergeable, and mergeable_state don't reflect the checks status
187190
*/
188-
const didChecksPass = await areAllChecksPassed(sha);
189-
if (!didChecksPass) {
190-
printFailReason(pullNumber, 'The PR has failed or ongoing check(s)');
191-
continue;
191+
if (requirePassedChecks) {
192+
const didChecksPass = await areAllChecksPassed(sha);
193+
if (!didChecksPass) {
194+
printFailReason(pullNumber, 'The PR has failed or ongoing check(s)');
195+
continue;
196+
}
192197
}
193198

194199
return pr;

src/lib/github.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const fakeEnv = {
1616
token,
1717
base,
1818
required_approval_count: requiredApprovalCount,
19+
require_passed_checks: 'true'
1920
};
2021

2122
const oldEnv = process.env;
@@ -443,6 +444,51 @@ describe('getAutoUpdateCanidate()', () => {
443444
);
444445
expect(res).toBe(null);
445446
});
447+
test('PR with failed checks will be selected if require_passed_checks is false', async () => {
448+
process.env.require_passed_checks = 'false';
449+
450+
// has 2 approvals, no request for change review
451+
const reviews = {
452+
...reviewsList,
453+
data: [
454+
{ ...reviewsList.data[0], state: 'APPROVED' },
455+
{ ...reviewsList.data[0], state: 'APPROVED' },
456+
],
457+
};
458+
// pr mergeable: true, merge_state: clean
459+
const prData = {
460+
data: {
461+
...prMetaData.data,
462+
...{ mergeable: true, mergeable_state: 'behind' },
463+
},
464+
};
465+
466+
const check = checksList.data.check_runs[0];
467+
const checks = {
468+
...checksList,
469+
data: {
470+
total_count: 2,
471+
check_runs: [
472+
{ ...check, conclusion: 'success' },
473+
{ ...check, conclusion: 'failure' },
474+
],
475+
},
476+
};
477+
478+
// has auto-merge PR
479+
const prList = [{ ...pullsList.data[0], auto_merge: {} }];
480+
const mockedListReviews = jest.fn().mockResolvedValue(reviews);
481+
const mockedGet = jest.fn().mockResolvedValue(prData);
482+
const mockedListForRef = jest.fn().mockResolvedValue(checks);
483+
484+
github.getOctokit.mockReturnValue({
485+
pulls: { listReviews: mockedListReviews, get: mockedGet },
486+
checks: { listForRef: mockedListForRef },
487+
});
488+
489+
const res = await gitLib.getAutoUpdateCandidate(prList);
490+
expect(res).toBe(prList[0]);
491+
});
446492
test('Should return the first PR if it is all good', async () => {
447493
// has 2 approvals, no request for change review
448494
const reviews = {

0 commit comments

Comments
 (0)