Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing review state to APPROVED whe 'LGTM' in COMMENTED review #72

Merged
merged 11 commits into from
Nov 8, 2017
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ get-metadata <identifier>
Retrieves metadata for a PR and validates them against nodejs/node PR rules

Options:
--version Show version number [boolean]
--owner, -o GitHub owner of the PR repository [string]
--repo, -r GitHub repository of the PR [string]
--file, -f File to write the metadata in [string]
--help, -h Show help [boolean]
--version Show version number [boolean]
--owner, -o GitHub owner of the PR repository [string]
--repo, -r GitHub repository of the PR [string]
--file, -f File to write the metadata in [string]
--check-comments Check for 'LGTM' in comments [boolean]
--help, -h Show help [boolean]
```

Examples:
Expand Down
11 changes: 9 additions & 2 deletions lib/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ function buildYargs(args = null) {
describe: 'File to write the metadata in',
type: 'string'
})
.option('check-comments', {
demandOption: false,
describe: 'Check for \'LGTM\' in comments',
type: 'boolean'
})
.help()
.alias('help', 'h')
.argv;
Expand All @@ -47,8 +52,10 @@ const PR_RE = new RegExp(
'([0-9]+)(?:/(?:files)?)?$');

function checkAndParseArgs(args) {
const { owner = 'nodejs', repo = 'node', identifier, file } = args;
const result = { owner, repo, file };
const {
owner = 'nodejs', repo = 'node', identifier, file, checkComments
} = args;
const result = { owner, repo, file, checkComments };
if (!isNaN(identifier)) {
result.prid = +identifier;
} else {
Expand Down
21 changes: 12 additions & 9 deletions lib/pr_checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const WEEKDAY_WAIT = 48;
const WEEKEND_WAIT = 72;

const {
REVIEW_SOURCES: { FROM_COMMENT }
REVIEW_SOURCES: { FROM_COMMENT, FROM_REVIEW_COMMENT }
} = require('./reviews');
const {
FIRST_TIME_CONTRIBUTOR, FIRST_TIMER
Expand Down Expand Up @@ -45,9 +45,9 @@ class PRChecker {
);
}

checkAll() {
checkAll(comments = false) {
const status = [
this.checkReviews(),
this.checkReviews(comments),
this.checkCommitsAfterReview(),
this.checkPRWait(new Date()),
this.checkCI()
Expand Down Expand Up @@ -75,7 +75,7 @@ class PRChecker {
return hint;
}

checkReviews() {
checkReviews(comments = false) {
const {
pr, logger, reviewers: { rejected, approved }
} = this;
Expand All @@ -88,7 +88,7 @@ class PRChecker {
let hint = this.getTSCHint(rejected);
logger.warn(`Rejections: ${rejected.length}${hint}`);
for (const { reviewer, review } of rejected) {
logger.warn(`${reviewer.getName()}) rejected in ${review.ref}`);
logger.warn(`${reviewer.getName()} rejected in ${review.ref}`);
}
}
if (approved.length === 0) {
Expand All @@ -98,10 +98,13 @@ class PRChecker {
let hint = this.getTSCHint(approved);
logger.info(`Approvals: ${approved.length}${hint}`);

for (const { reviewer, review } of approved) {
if (review.source === FROM_COMMENT) {
logger.info(
`${reviewer.getName()}) approved in via LGTM in comments`);
if (comments) {
for (const {reviewer, review} of approved) {
if (review.source === FROM_COMMENT ||
review.source === FROM_REVIEW_COMMENT) {
logger.warn(
`${reviewer.getName()} approved in via LGTM in comments`);
}
}
}

Expand Down
41 changes: 36 additions & 5 deletions lib/reviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ const {
} = require('./review_state');
const { isCollaborator } = require('./collaborators');
const { ascending } = require('./comp');
const LGTM_RE = /(\W|^)lgtm(\W|$)/i;
const LGTM_RE = /^lgtm\W?$/i;
const FROM_REVIEW = 'review';
const FROM_COMMENT = 'comment';
const FROM_REVIEW_COMMENT = 'review_comment';

class Review {
/**
Expand Down Expand Up @@ -55,7 +56,14 @@ class ReviewAnalyzer {
const map = new Map();
const collaborators = this.collaborators;
const list = this.reviews
.filter((r) => r.state !== PENDING && r.state !== COMMENTED)
.filter((r) => r.state !== PENDING)
.filter((r) => {
if (r.state === COMMENTED) {
return this.isApprovedInComment(r);
} else {
return true;
}
})
.filter((r) => {
return (isCollaborator(collaborators, r.author));
}).sort((a, b) => {
Expand All @@ -80,6 +88,12 @@ class ReviewAnalyzer {
new Review(r.state, r.publishedAt, r.url, FROM_REVIEW)
);
break;
case COMMENTED:
map.set(
login,
new Review(APPROVED, r.publishedAt, r.bodyText, FROM_REVIEW_COMMENT)
);
break;
case DISMISSED:
// TODO: check the state of the dismissed review?
map.delete(login);
Expand All @@ -97,7 +111,7 @@ class ReviewAnalyzer {
updateMapByRawReviews(oldMap) {
const comments = this.comments;
const collaborators = this.collaborators;
const withLgtm = comments.filter((c) => LGTM_RE.test(c.bodyText))
const withLgtm = comments.filter((c) => this.hasLGTM(c))
.filter((c) => {
return (isCollaborator(collaborators, c.author));
}).sort((a, b) => {
Expand Down Expand Up @@ -133,17 +147,34 @@ class ReviewAnalyzer {
for (const [ login, review ] of reviewers) {
const reviewer = collaborators.get(login.toLowerCase());
if (review.state === APPROVED) {
result.approved.push({ reviewer, review });
result.approved.push({reviewer, review});
} else if (review.state === CHANGES_REQUESTED) {
result.rejected.push({ reviewer, review });
}
}
return result;
}

/**
* @param review
* @returns {boolean}
*/
isApprovedInComment(review) {
return review.state === COMMENTED && this.hasLGTM(review);
}

/**
* @param object
* @param prop: string
* @returns {boolean}
*/
hasLGTM(object) {
return LGTM_RE.test(object.bodyText.trim());
}
}

const REVIEW_SOURCES = {
FROM_COMMENT, FROM_REVIEW
FROM_COMMENT, FROM_REVIEW, FROM_REVIEW_COMMENT
};

module.exports = {
Expand Down
2 changes: 1 addition & 1 deletion steps/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module.exports = async function getMetadata(argv, logger) {
}, 'Generated metadata:');

const checker = new PRChecker(logger, data);
const status = checker.checkAll();
const status = checker.checkAll(argv.checkComments);
return {
status,
request,
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ For more information about the governance of the Node.js project, see
**Foo User** &lt;[email protected]&gt; (she/her)
* [Quo](https://github.com/quo) -
**Quo User** &lt;[email protected]&gt; (she/her)
* [Quux](https://github.com/quux) -
**Quux User** &lt;[email protected]&gt; (he/him)

### Collaborator Emeriti

Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/collaborators.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,11 @@
"name": "Quo User",
"email": "[email protected]",
"type": "COLLABORATOR"
},
{
"login": "Quux",
"name": "Quux User",
"email": "[email protected]",
"type": "COLLABORATOR"
}
]
14 changes: 14 additions & 0 deletions test/fixtures/reviewers_approved.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@
"source": "review"
}
},
{
"reviewer": {
"login": "Quux",
"name": "Quux User",
"email": "[email protected]",
"type": "COLLABORATOR"
},
"review": {
"state": "APPROVED",
"date": "2017-10-24T14:49:52Z",
"ref": "LGTM",
"source": "review_comment"
}
},
{
"reviewer": {
"login": "Baz",
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/reviews_approved.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@
"url": "https://github.com/nodejs/node/pull/16438#pullrequestreview-71488236",
"publishedAt": "2017-10-24T14:49:52Z"
},
{
"bodyText": "LGTM",
"state": "COMMENTED",
"author": {
"login": "Quux"
},
"url": "https://github.com/nodejs/node/pull/16438#pullrequestreview-71817236",
"publishedAt": "2017-10-24T14:49:52Z"
},
{
"bodyText": "A few nits",
"state": "COMMENTED",
Expand Down
1 change: 1 addition & 0 deletions test/unit/args.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const parseArgs = require('../../lib/args');
const assert = require('assert');

const expected = {
checkComments: false,
owner: `nodejs`,
repo: `node`,
prid: 16637,
Expand Down
1 change: 1 addition & 0 deletions test/unit/metadata_gen.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const expected = `PR-URL: https://github.com/nodejs/node/pull/16438
Fixes: https://github.com/nodejs/node/issues/16437
Refs: https://github.com/nodejs/node/pull/15148
Reviewed-By: Foo User <[email protected]>
Reviewed-By: Quux User <[email protected]>
Reviewed-By: Baz User <[email protected]>
Reviewed-By: Bar User <[email protected]>
`;
Expand Down
11 changes: 6 additions & 5 deletions test/unit/pr_checker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@ describe('PRChecker', () => {

const expectedLogs = {
warn: [
['Quux User(Quux) approved in via LGTM in comments'],
['Bar User(bar) approved in via LGTM in comments'],
['semver-major requires at least two TSC approvals']
],
info: [
['Rejections: 0'],
['Approvals: 3, 1 from TSC (bar)'],
['Bar User(bar)) approved in via LGTM in comments']
['Approvals: 4, 1 from TSC (bar)']
],
error: [],
trace: []
Expand All @@ -100,7 +101,7 @@ describe('PRChecker', () => {
collaborators
});

const status = checker.checkReviews();
const status = checker.checkReviews(true);
assert(!status);
assert.deepStrictEqual(logger.logs, expectedLogs);
});
Expand All @@ -111,8 +112,8 @@ describe('PRChecker', () => {
const expectedLogs = {
warn: [
['Rejections: 2, 1 from TSC (bar)'],
['Foo User(foo)) rejected in https://github.com/nodejs/node/pull/16438#pullrequestreview-71480624'],
['Bar User(bar)) rejected in https://github.com/nodejs/node/pull/16438#pullrequestreview-71482624'],
['Foo User(foo) rejected in https://github.com/nodejs/node/pull/16438#pullrequestreview-71480624'],
['Bar User(bar) rejected in https://github.com/nodejs/node/pull/16438#pullrequestreview-71482624'],
['Approvals: 0']
],
info: [],
Expand Down