Skip to content

Commit

Permalink
Merge pull request #14 from DynamicYield/github-sorting
Browse files Browse the repository at this point in the history
Support for list pulls sorting
  • Loading branch information
zhiyelee authored Dec 23, 2021
2 parents b8f320d + 17b6303 commit 798d0de
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 67 deletions.
13 changes: 10 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Update PR Branch'
description: 'Automatically update the branch of newest ready to merge PR. Designed to work with the auto-merge option.'
description: 'Automatically update the branch of newest (by default) ready to merge PR. Designed to work with the auto-merge option.'
branding:
icon: git-pull-request
color: orange
Expand All @@ -17,8 +17,15 @@ inputs:
default: '2'
require_passed_checks:
required: false
description: "If the action should skip PRs that have failed checks, defaults to `true`"
default: "true"
description: 'If the action should skip PRs that have failed checks, defaults to `true`'
default: 'true'
github_sort:
required: false
description: 'What to sort results by. Can be either `created`, `updated`, `popularity` (comment count) or `long-running` (age, filtering by pulls updated in the last month).'
github_sort_direction:
required: false
description: 'The direction of the github_sort. Can be either `asc` or `desc`. Default: `desc` when github_sort is created or github_sort is not specified, otherwise `asc`.'

runs:
using: 'node12'
main: 'dest/index.js'
171 changes: 113 additions & 58 deletions dest/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1461,7 +1461,7 @@ exports.Octokit = Octokit;

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

var isPlainObject = __nccwpck_require__(287);
var isPlainObject = __nccwpck_require__(558);
var universalUserAgent = __nccwpck_require__(429);

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


/***/ }),

/***/ 558:
/***/ ((__unused_webpack_module, exports) => {

"use strict";


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

/*!
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/

function isObject(o) {
return Object.prototype.toString.call(o) === '[object Object]';
}

function isPlainObject(o) {
var ctor,prot;

if (isObject(o) === false) return false;

// If has modified constructor
ctor = o.constructor;
if (ctor === undefined) return true;

// If has modified prototype
prot = ctor.prototype;
if (isObject(prot) === false) return false;

// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}

// Most likely a plain Object
return true;
}

exports.isPlainObject = isPlainObject;


/***/ }),

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

var endpoint = __nccwpck_require__(440);
var universalUserAgent = __nccwpck_require__(429);
var isPlainObject = __nccwpck_require__(287);
var isPlainObject = __nccwpck_require__(62);
var nodeFetch = _interopDefault(__nccwpck_require__(467));
var requestError = __nccwpck_require__(537);

Expand Down Expand Up @@ -3478,6 +3524,52 @@ exports.request = request;
//# sourceMappingURL=index.js.map


/***/ }),

/***/ 62:
/***/ ((__unused_webpack_module, exports) => {

"use strict";


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

/*!
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/

function isObject(o) {
return Object.prototype.toString.call(o) === '[object Object]';
}

function isPlainObject(o) {
var ctor,prot;

if (isObject(o) === false) return false;

// If has modified constructor
ctor = o.constructor;
if (ctor === undefined) return true;

// If has modified prototype
prot = ctor.prototype;
if (isObject(prot) === false) return false;

// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}

// Most likely a plain Object
return true;
}

exports.isPlainObject = isPlainObject;


/***/ }),

/***/ 682:
Expand Down Expand Up @@ -3683,52 +3775,6 @@ class Deprecation extends Error {
exports.Deprecation = Deprecation;


/***/ }),

/***/ 287:
/***/ ((__unused_webpack_module, exports) => {

"use strict";


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

/*!
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/

function isObject(o) {
return Object.prototype.toString.call(o) === '[object Object]';
}

function isPlainObject(o) {
var ctor,prot;

if (isObject(o) === false) return false;

// If has modified constructor
ctor = o.constructor;
if (ctor === undefined) return true;

// If has modified prototype
prot = ctor.prototype;
if (isObject(prot) === false) return false;

// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}

// Most likely a plain Object
return true;
}

exports.isPlainObject = isPlainObject;


/***/ }),

/***/ 467:
Expand Down Expand Up @@ -5806,11 +5852,16 @@ const getOpenPRs = async () => {
const octokit = getOctokit();
const repo = github.context.repo;
const baseBranch = github_core.getInput('base');
const githubSort = github_core.getInput('github_sort').toLowerCase() || null;
const githubSortDirection =
github_core.getInput('github_sort_direction').toLowerCase() || null;

const { data } = await octokit.pulls.list({
...repo,
base: baseBranch,
state: 'open',
sort: githubSort,
direction: githubSortDirection,
});

return data;
Expand Down Expand Up @@ -5864,7 +5915,6 @@ const getMergeableStatus = async (pullNumber) => {
if (mergeableStatus.mergeable_state === 'unknown') {
// https://docs.github.com/en/rest/guides/getting-started-with-the-git-database-api#checking-mergeability-of-pull-requests
// Github recommends to use poll to get a non null/unknown value, we use a compromised version here because of the api rate limit
console.info(mergeableStatus, wait);
await wait(3000);
data = await getPR(pullNumber);
mergeableStatus = {
Expand Down Expand Up @@ -5897,8 +5947,7 @@ const areAllChecksPassed = async (sha) => {
};

/**
* check whether PR is mergeable from the Approval perspective
* the pr needs to have minimum required approvals && no request-for-changes reviews
* get the count of the latest concluding review (approved or CHANGES_REQUESTED) of each reviewer
*/
const getApprovalStatus = async (pullNumber) => {
const octokit = getOctokit();
Expand All @@ -5910,12 +5959,20 @@ const getApprovalStatus = async (pullNumber) => {
pull_number: pullNumber,
});

let reviewers = new Set();
let changesRequestedCount = 0;
let approvalCount = 0;

reviewsData.forEach(({ state }) => {
reviewsData.reverse().forEach(({ state, user }) => {
const reviewer = user.login;

// only count the latest concluding review per perviewer
if (reviewers.has(reviewer)) return;
if (!['CHANGES_REQUESTED', 'APPROVED'].includes(state)) return;

if (state === 'CHANGES_REQUESTED') changesRequestedCount += 1;
if (state === 'APPROVED') approvalCount += 1;
reviewers.add(reviewer);
});

return {
Expand All @@ -5932,7 +5989,8 @@ const getAutoUpdateCandidate = async (openPRs) => {
if (!openPRs) return null;

const requiredApprovalCount = github_core.getInput('required_approval_count');
const requirePassedChecks = /true/i.test(github_core.getInput('require_passed_checks'));
const requirePassedChecks =
github_core.getInput('require_passed_checks').toUpperCase() === 'TRUE';

// only update `auto merge` enabled PRs
const autoMergeEnabledPRs = openPRs.filter((item) => item.auto_merge);
Expand All @@ -5947,11 +6005,8 @@ const getAutoUpdateCandidate = async (openPRs) => {
log(`Checking applicable status of #${pullNumber}`);

// #1 check whether the pr has enough approvals
const {
changesRequestedCount,
approvalCount,
requiredApprovalCount,
} = await getApprovalStatus(pullNumber);
const { changesRequestedCount, approvalCount, requiredApprovalCount } =
await getApprovalStatus(pullNumber);
if (changesRequestedCount || approvalCount < requiredApprovalCount) {
const reason = `approvalsCount: ${approvalCount}, requiredApprovalCount: ${requiredApprovalCount}, changesRequestedReviews: ${changesRequestedCount}`;
printFailReason(pullNumber, reason);
Expand Down
15 changes: 9 additions & 6 deletions src/lib/github.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ export const getOpenPRs = async () => {
const octokit = getOctokit();
const repo = github.context.repo;
const baseBranch = core.getInput('base');
const githubSort = core.getInput('github_sort').toLowerCase() || null;
const githubSortDirection =
core.getInput('github_sort_direction').toLowerCase() || null;

const { data } = await octokit.pulls.list({
...repo,
base: baseBranch,
state: 'open',
sort: githubSort,
direction: githubSortDirection,
});

return data;
Expand Down Expand Up @@ -143,7 +148,8 @@ export const getAutoUpdateCandidate = async (openPRs) => {
if (!openPRs) return null;

const requiredApprovalCount = core.getInput('required_approval_count');
const requirePassedChecks = core.getInput('require_passed_checks').toUpperCase() === 'TRUE';
const requirePassedChecks =
core.getInput('require_passed_checks').toUpperCase() === 'TRUE';

// only update `auto merge` enabled PRs
const autoMergeEnabledPRs = openPRs.filter((item) => item.auto_merge);
Expand All @@ -158,11 +164,8 @@ export const getAutoUpdateCandidate = async (openPRs) => {
log(`Checking applicable status of #${pullNumber}`);

// #1 check whether the pr has enough approvals
const {
changesRequestedCount,
approvalCount,
requiredApprovalCount,
} = await getApprovalStatus(pullNumber);
const { changesRequestedCount, approvalCount, requiredApprovalCount } =
await getApprovalStatus(pullNumber);
if (changesRequestedCount || approvalCount < requiredApprovalCount) {
const reason = `approvalsCount: ${approvalCount}, requiredApprovalCount: ${requiredApprovalCount}, changesRequestedReviews: ${changesRequestedCount}`;
printFailReason(pullNumber, reason);
Expand Down

0 comments on commit 798d0de

Please sign in to comment.