Skip to content

Commit

Permalink
[New] add --commit to check status of commits instead of just PRs
Browse files Browse the repository at this point in the history
  • Loading branch information
Meghal Bisht authored and Green-Ranger11 committed Jan 29, 2022
1 parent 3a6fa74 commit 848a8db
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 36 deletions.
72 changes: 50 additions & 22 deletions bin/can-merge
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const parsePullRequest = require('../utils/parsePullRequest');
const parseRemoteUrl = require('../utils/parseRemoteUrl');
const pullRequestStatus = require('../utils/models/pullRequestStatus');
const getMessage = require('../utils/getMessage');
const evaluateCommitStatus = require('../utils/evaluateCommitStatus');
const commitStatus = require('../utils/models/commitStatus');
const { STATUS_SUCCESS } = require('../utils/models/commitStatus');

const {
GITHUB_TOKEN,
Expand All @@ -35,6 +38,13 @@ const args = Yargs
.help()
.strict()
.options({
commit: {
alias: 'c',
default: false,
demandOption: false,
describe: 'check commit status',
type: 'boolean',
},
pr: {
alias: 'p',
demandOption: false,
Expand Down Expand Up @@ -72,7 +82,6 @@ const args = Yargs
},
watch: {
alias: 'w',
default: false,
describe: 'watch pending checks',
type: 'boolean',
},
Expand Down Expand Up @@ -114,33 +123,51 @@ function outputStatus(response) {
if (NODE_ENV === 'DEBUG') {
console.log(JSON.stringify(response, null, 2));
}
const prs = parsePullRequest(response);
if (prs.length === 0) {
if (args.pr) {
console.info(chalk.redBright(`⚠ This remote repository does not contain any pull requests matching number: ${args.pr}`));
} else {
console.info(chalk.redBright(`⚠ This remote repository does not contain any pull requests matching sha: ${args.sha}`));
if (args.commit && args.sha && !args.pr) {
const status = evaluateCommitStatus(response.repository.commit);
console.info(getMessage(status));
if (status !== STATUS_SUCCESS) {
process.exitCode = (process.exitCode ?? 0) + 1;
}
process.exitCode = 1;
} else {
prs.forEach((pr) => {
const status = evaluatePullRequest(pr);
console.info('PR:', pr.number, getMessage(status));
if (status !== pullRequestStatus.MERGEABLE) {
process.exitCode = (process.exitCode ?? 0) + 1;
const prs = parsePullRequest(response);
if (prs.length === 0 && !args.commit) {
if (args.pr) {
console.info(chalk.redBright(`⚠ This remote repository does not contain any pull requests matching number: ${args.pr}`));
} else {
console.info(chalk.redBright(`⚠ This remote repository does not contain any pull requests matching sha: ${args.sha}`));
}
if (status === pullRequestStatus.STATUS_FAILURE || status === pullRequestStatus.STATUS_PENDING) {
const { failure, pending } = evaluateChecks(pr);

if (pending.length > 0) {
console.info(chalk.yellowBright(`Pending Checks (${pending.length}): ${pending.join(', ')}`));
} else {
prs.forEach((pr) => {
if (args.commit && !(args.sha && !args.pr)) {
if (pr.commits.nodes.length > 1) {
throw chalk.red(`Failed to evaluate commit status of PR ${pr.number}`);
}
const status = evaluateCommitStatus(pr.commits.nodes[0].commit);
console.info(`PR ${pr.number} commit status: `, getMessage(status));
if (status !== commitStatus.STATUS_SUCCESS) {
process.exitCode = (process.exitCode ?? 0) + 1;
}
}
if (failure.length > 0) {
console.info(chalk.redBright(`Failed Checks (${failure.length}): ${failure.join(', ')}`));
const status = evaluatePullRequest(pr);
console.info('PR status:', pr.number, getMessage(status));
if (status !== pullRequestStatus.MERGEABLE) {
process.exitCode = (process.exitCode ?? 0) + 1;
}
}
});
if (status === pullRequestStatus.STATUS_FAILURE || status === pullRequestStatus.STATUS_PENDING) {
const { failure, pending } = evaluateChecks(pr);

if (pending.length > 0) {
console.info(chalk.yellowBright(`Pending Checks (${pending.length}): ${pending.join(', ')}`));
}
if (failure.length > 0) {
console.info(chalk.redBright(`Failed Checks (${failure.length}): ${failure.join(', ')}`));
}
}
});
}
}

}
const { repo, pr, sha } = args;

Expand All @@ -152,6 +179,7 @@ const options = {

https.request(options, (response) => {
const params = {
commit: args.commit,
repo: parseRemoteUrl(response.headers?.location) ?? String(repo),
pr,
sha: pr ? null : sha,
Expand Down
56 changes: 45 additions & 11 deletions utils/buildQuery.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable max-lines-per-function */

'use strict';

const pullRequestQuery = () => `
Expand Down Expand Up @@ -47,19 +49,51 @@ module.exports = function buildQuery({
owner,
pr,
sha,
commit,
}) {
return `
{
search(query: "is:pr repo:${owner}/${name} ${sha ? `sha:${sha}` : ''} ${pr}", type:ISSUE, first: 100) {
issueCount
edges {
node {
... on PullRequest {
${pullRequestQuery()}
return `${commit
? `{
repository(name: "${name}", owner: "${owner}") {
commit: object(expression: "${sha}") {
... on Commit {
statusCheckRollup {
state
contexts(last: 100) {
totalCount
pageInfo {
endCursor
hasNextPage
}
nodes {
__typename
... on CheckRun {
status
name
conclusion
}
... on StatusContext {
state
context
description
}
}
}
}
}
}
}
}
}
`;
}`
: `{
search(query: "is:pr repo:${owner}/${name} ${sha ? `sha:${sha}` : ''} ${pr}", type:ISSUE, first: 100) {
issueCount
edges {
node {
... on PullRequest {
${pullRequestQuery()}
}
}
}
}
}`
}`;
};
20 changes: 20 additions & 0 deletions utils/evaluateCommitStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const commitStatus = require('./models/commitStatus');

const success = (commit) => commit?.statusCheckRollup?.state === 'SUCCESS';
const failure = (commit) => commit?.statusCheckRollup?.state === 'ERROR' || commit?.statusCheckRollup?.state === 'FAILURE';
const pending = (commit) => commit?.statusCheckRollup?.state === 'PENDING';

module.exports = function evaluateCommitStatus(commit) {
if (success(commit)) {
return commitStatus.STATUS_SUCCESS;
}
if (failure(commit)) {
return commitStatus.STATUS_FAILURE;
}
if (pending(commit)) {
return commitStatus.STATUS_PENDING;
}
return commitStatus.STATUS_NOT_FOUND;
};
7 changes: 6 additions & 1 deletion utils/getMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const chalk = require('chalk');
const pullRequestStatus = require('./models/pullRequestStatus');
const commitStatus = require('./models/commitStatus');

const messages = {
[pullRequestStatus.CLOSED]: chalk.redBright(pullRequestStatus.CLOSED),
Expand All @@ -12,7 +13,11 @@ const messages = {
[pullRequestStatus.REVIEW_DISAPPROVED]: chalk.yellowBright(pullRequestStatus.REVIEW_DISAPPROVED),
[pullRequestStatus.REVIEW_REQUIRED]: chalk.redBright(pullRequestStatus.REVIEW_REQUIRED),
[pullRequestStatus.STATUS_FAILURE]: chalk.blueBright(pullRequestStatus.STATUS_FAILURE),
[pullRequestStatus.STATUS_PENDING]: chalk.yellowBright(pullRequestStatus.STATUS_PENDING),
[pullRequestStatus.STATUSCHECK_PENDING]: chalk.yellowBright(pullRequestStatus.STATUSCHECK_PENDING),
[commitStatus.STATUS_FAILURE]: chalk.redBright(commitStatus.STATUS_FAILURE),
[commitStatus.STATUS_PENDING]: chalk.yellowBright(commitStatus.STATUS_PENDING),
[commitStatus.STATUS_SUCCESS]: chalk.greenBright(commitStatus.STATUS_SUCCESS),
[commitStatus.STATUS_NOT_FOUND]: chalk.yellowBright(commitStatus.STATUS_NOT_FOUND),
};

module.exports = function getMessage(response) {
Expand Down
8 changes: 8 additions & 0 deletions utils/models/commitStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

module.exports = {
STATUS_FAILURE: '⚠ Some commit checks were not successful',
STATUS_NOT_FOUND: 'ℹ No commit checks were found',
STATUS_PENDING: '⌛ Some commit checks are pending',
STATUS_SUCCESS: '✔ All commit checks are successful',
};
4 changes: 2 additions & 2 deletions utils/runQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
const { graphql } = require('@octokit/graphql');
const buildQuery = require('./buildQuery');

module.exports = async function runQuery({ repo, pr, sha, token }) {
module.exports = async function runQuery({ commit, repo, pr, sha, token }) {
const [owner, name] = repo.split('/');
let response = null;
try {
response = await graphql(buildQuery({ name, owner, pr, sha }), {
response = await graphql(buildQuery({ commit, name, owner, pr, sha }), {
headers: {
authorization: `token ${token}`,
},
Expand Down

0 comments on commit 848a8db

Please sign in to comment.