feat(github): allow positive PR reviews to override changes requested (#3037)

Closes #3012
This commit is contained in:
rtaum 2019-01-06 17:56:30 +01:00 committed by Rhys Arkins
parent 60f73779d8
commit 9af3ef2ee1
4 changed files with 157 additions and 4 deletions

View file

@ -1061,7 +1061,7 @@ async function getOpenPrs() {
}
}
body
reviews(first: 1, states:[CHANGES_REQUESTED]){
reviews(first: 100){
nodes{
state
}
@ -1091,10 +1091,9 @@ async function getOpenPrs() {
delete pr.headRefName;
// https://developer.github.com/v4/enum/mergeablestate
const canMergeStates = ['BEHIND', 'CLEAN'];
const hasNegativeReview =
pr.reviews && pr.reviews.nodes && pr.reviews.nodes.length > 0;
pr.canMerge =
canMergeStates.includes(pr.mergeStateStatus) && !hasNegativeReview;
canMergeStates.includes(pr.mergeStateStatus) &&
!hasNegativeReview(pr.reviews.nodes);
// https://developer.github.com/v4/enum/mergestatestatus
if (pr.mergeStateStatus === 'DIRTY') {
pr.isConflicted = true;
@ -1537,3 +1536,17 @@ async function getVulnerabilityAlerts() {
}
return alerts;
}
function hasNegativeReview(reviews) {
const negativeReviews = {};
for (const review of reviews) {
if (review.state === 'CHANGES_REQUESTED') {
negativeReviews[review.author.login] = review.state;
} else if (review.state === 'APPROVED') {
if (negativeReviews[review.author.login]) {
delete negativeReviews[review.author.login];
}
}
}
return Object.keys(negativeReviews).length > 0;
}

View file

@ -40,6 +40,24 @@
}
}
]
},
"reviews": {
"nodes": [
{
"state": "CHANGES_REQUESTED",
"author": {
"login": "login"
},
"createdAt": "2018-12-30T15:53:22Z"
},
{
"state": "APPROVED",
"author": {
"login": "login"
},
"createdAt": "2018-12-30T15:53:29Z"
}
]
}
},
{
@ -72,6 +90,17 @@
}
}
]
},
"reviews": {
"nodes": [
{
"state": "CHANGES_REQUESTED",
"author": {
"login": "login"
},
"createdAt": "2018-12-30T15:53:22Z"
}
]
}
},
{

View file

@ -308,6 +308,17 @@ Object {
"isConflicted": true,
"isStale": true,
"number": 2500,
"reviews": Object {
"nodes": Array [
Object {
"author": Object {
"login": "login",
},
"createdAt": "2018-12-30T15:53:22Z",
"state": "CHANGES_REQUESTED",
},
],
},
"state": "open",
"title": "chore(deps): update dependency jest to v23.6.0",
}
@ -360,6 +371,66 @@ Object {
}
`;
exports[`platform/github getPr(prNo) should return a mergeable PR if last review from the user is APPROVED 1`] = `
Object {
"branchName": "renovate/major-got-packages",
"canMerge": true,
"canRebase": true,
"displayNumber": "Pull Request #2433",
"isConflicted": false,
"isStale": true,
"labels": Array [
"blocked",
],
"number": 2433,
"reviews": Object {
"nodes": Array [
Object {
"author": Object {
"login": "login",
},
"createdAt": "2018-12-30T15:53:22Z",
"state": "CHANGES_REQUESTED",
},
Object {
"author": Object {
"login": "login",
},
"createdAt": "2018-12-30T15:53:29Z",
"state": "APPROVED",
},
],
},
"state": "open",
"title": "build(deps): update got packages (major)",
}
`;
exports[`platform/github getPr(prNo) should return a not mergeable PR if last review from the user is CHANGES_REQUESTED 1`] = `
Object {
"branchName": "renovate/jest-monorepo",
"canMerge": false,
"canRebase": true,
"displayNumber": "Pull Request #2500",
"isConflicted": true,
"isStale": true,
"number": 2500,
"reviews": Object {
"nodes": Array [
Object {
"author": Object {
"login": "login",
},
"createdAt": "2018-12-30T15:53:22Z",
"state": "CHANGES_REQUESTED",
},
],
},
"state": "open",
"title": "chore(deps): update dependency jest to v23.6.0",
}
`;
exports[`platform/github getPr(prNo) should return a not rebaseable PR if gitAuthor does not match 1 commit 1`] = `
Object {
"base": Object {

View file

@ -1651,6 +1651,46 @@ describe('platform/github', () => {
expect(pr.canRebase).toBe(false);
expect(pr).toMatchSnapshot();
});
it('should return a mergeable PR if last review from the user is APPROVED', async () => {
await initRepo({
repository: 'some/repo',
token: 'token',
});
get.post.mockImplementationOnce(() => ({
body: graphqlOpenPullRequests,
}));
// getBranchCommit
get.mockImplementationOnce(() => ({
body: {
object: {
sha: '1234',
},
},
}));
const pr = await github.getPr(2433);
expect(pr.canMerge).toBe(true);
expect(pr).toMatchSnapshot();
});
it('should return a not mergeable PR if last review from the user is CHANGES_REQUESTED', async () => {
await initRepo({
repository: 'some/repo',
token: 'token',
});
get.post.mockImplementationOnce(() => ({
body: graphqlOpenPullRequests,
}));
// getBranchCommit
get.mockImplementationOnce(() => ({
body: {
object: {
sha: '1234',
},
},
}));
const pr = await github.getPr(2500);
expect(pr.canMerge).toBe(false);
expect(pr).toMatchSnapshot();
});
});
describe('getPrFiles()', () => {
it('should return empty if no prNo is passed', async () => {