diff --git a/lib/pr_checker.js b/lib/pr_checker.js index 68b3db3a..0a516054 100644 --- a/lib/pr_checker.js +++ b/lib/pr_checker.js @@ -53,8 +53,8 @@ class PRChecker { const status = [ this.checkReviews(comments), this.checkCommitsAfterReview(), - this.checkPRWait(new Date()), this.checkCI(), + this.checkPRWait(new Date()), this.checkMergeableState() ]; @@ -150,12 +150,31 @@ class PRChecker { * @param {Date} now */ checkPRWait(now) { - const { pr } = this; - const { cli } = this; + const { + pr, cli, reviewers, CIStatus + } = this; const labels = pr.labels.nodes; - const fast = labels.some((l) => l.name === 'code-and-learn') || - (labels.length === 1 && labels[0].name === 'doc'); - if (fast) { return true; } + + const fast = + labels.some((l) => ['fast-track'].includes(l.name)); + if (fast) { + const { approved } = reviewers; + if (approved.length > 1 && CIStatus) { + cli.info('This PR is being fast-tracked'); + return true; + } else { + const msg = ['This PR is being fast-tracked, but awating ']; + if (approved.length < 2) msg.push('approvals of 2 contributors'); + if (!CIStatus) msg.push('a CI run'); + + let warnMsg = msg.length === 2 + ? msg.join('') : `${msg[0] + msg[1]} and ${msg[2]}`; + cli.warn(warnMsg); + } + + return false; + } + const wait = this.getWait(now); if (wait.timeLeft > 0) { const dateStr = new Date(pr.createdAt).toDateString(); @@ -182,6 +201,7 @@ class PRChecker { let status = true; if (!ciMap.size) { cli.error('No CI runs detected'); + this.CIStatus = false; return false; } else if (!ciMap.get(FULL)) { status = false; @@ -231,6 +251,7 @@ class PRChecker { } } + this.CIStatus = status; return status; } diff --git a/test/unit/pr_checker.test.js b/test/unit/pr_checker.test.js index 8109d67e..85156bf2 100644 --- a/test/unit/pr_checker.test.js +++ b/test/unit/pr_checker.test.js @@ -201,37 +201,151 @@ describe('PRChecker', () => { cli.assertCalledWith(expectedLogs); }); - it('should skip wait check for Code & Learn PR', () => { + it('should log as expected if PR can be fast-tracked', () => { const cli = new TestCLI(); - const expectedLogs = {}; + const expectedLogs = { + info: [ + [ 'This PR is being fast-tracked' ] + ] + }; - const now = new Date(); - const youngPR = Object.assign({}, firstTimerPR, { - createdAt: '2017-10-27T14:25:41.682Z', + const now = new Date('2017-11-01T14:25:41.682Z'); + const PR = Object.assign({}, firstTimerPR, { + createdAt: '2017-10-31T13:00:41.682Z', labels: { nodes: [ - { - name: 'code-and-learn' - } + { name: 'fast-track' } ] } }); const options = { - pr: youngPR, + pr: PR, reviewers: allGreenReviewers, - comments: commentsWithLGTM, + comments: commentsWithCI, reviews: approvingReviews, - commits: simpleCommits, + commits: [], collaborators }; const checker = new PRChecker(cli, options, argv); + checker.checkCI(); + cli.clearCalls(); const status = checker.checkPRWait(now); assert(status); cli.assertCalledWith(expectedLogs); }); + + it('should warn about approvals and CI for fast-tracked PR', () => { + const cli = new TestCLI(); + + const expectedLogs = { + warn: [ + [ 'This PR is being fast-tracked, but awating ' + + 'approvals of 2 contributors and a CI run' ] + ] + }; + + const now = new Date('2017-11-01T14:25:41.682Z'); + const PR = Object.assign({}, firstTimerPR, { + createdAt: '2017-10-31T13:00:41.682Z', + labels: { + nodes: [ + { name: 'fast-track' } + ] + } + }); + + const options = { + pr: PR, + reviewers: requestedChangesReviewers, + comments: [], + reviews: requestingChangesReviews, + commits: simpleCommits, + collaborators + }; + const checker = new PRChecker(cli, options, argv); + + checker.checkCI(); + cli.clearCalls(); + const status = checker.checkPRWait(now); + assert(!status); + cli.assertCalledWith(expectedLogs); + }); + + it('should warn cannot be fast-tracked because of approvals', () => { + const cli = new TestCLI(); + + const expectedLogs = { + warn: [ + [ 'This PR is being fast-tracked, but awating ' + + 'approvals of 2 contributors' ] + ] + }; + + const now = new Date('2017-11-01T14:25:41.682Z'); + const PR = Object.assign({}, firstTimerPR, { + createdAt: '2017-10-31T13:00:41.682Z', + labels: { + nodes: [ + { name: 'fast-track' } + ] + } + }); + + const options = { + pr: PR, + reviewers: requestedChangesReviewers, + comments: commentsWithCI, + reviews: approvingReviews, + commits: [], + collaborators + }; + const checker = new PRChecker(cli, options, argv); + + checker.checkCI(); + cli.clearCalls(); + const status = checker.checkPRWait(now); + assert(!status); + cli.assertCalledWith(expectedLogs); + }); + + it('should warn if the PR has no CI and cannot be fast-tracked', () => { + const cli = new TestCLI(); + + const expectedLogs = { + warn: [ + [ 'This PR is being fast-tracked, but awating a CI run' ] + ] + }; + + const now = new Date('2017-11-01T14:25:41.682Z'); + const PR = Object.assign({}, firstTimerPR, { + createdAt: '2017-10-31T13:00:41.682Z', + labels: { + nodes: [ + { name: 'fast-track' } + ] + } + }); + + const options = { + pr: PR, + reviewers: allGreenReviewers, + comments: [], + reviews: approvingReviews, + commits: simpleCommits, + collaborators + }; + const checker = new PRChecker(cli, options, argv); + + checker.checkCI(); + cli.clearCalls(); + const status = checker.checkPRWait(now); + assert(!status); + cli.assertCalledWith(expectedLogs); + }); }); describe('checkCI', () => {