diff --git a/lib/api/github.js b/lib/api/github.js index 7dffbb9c69d93478f2f7d4192c9f2c693fdbf83e..63cb6de61a69d336f9f125d7a74c4778a19b1487 100644 --- a/lib/api/github.js +++ b/lib/api/github.js @@ -184,14 +184,32 @@ async function getPr(prNo) { if (pr.state === 'closed') { pr.isClosed = true; } - if (pr.mergeable_state === 'dirty') { - pr.isUnmergeable = true; - } - if (pr.additions * pr.deletions === 1 || pr.commits === 1) { - pr.canRebase = true; - } - if (pr.base.sha !== config.baseCommitSHA) { - pr.isStale = true; + if (!pr.isClosed) { + if (pr.mergeable_state === 'dirty') { + pr.isUnmergeable = true; + } + if (pr.commits === 1) { + // Only one commit was made - must have been renovate + pr.canRebase = true; + } else { + // Check if only one author of all commits + logger.debug('Checking all commits'); + const prCommits = (await ghGot(`repos/${config.repoName}/pulls/${prNo}/commits`)).body; + const authors = prCommits.reduce((arr, commit) => { + const author = commit.author.login; + if (arr.indexOf(author) === -1) { + arr.push(author); + } + return arr; + }, []); + logger.debug(`Author list: ${authors}`); + if (authors.length === 1) { + pr.canRebase = true; + } + } + if (pr.base.sha !== config.baseCommitSHA) { + pr.isStale = true; + } } return pr; } diff --git a/test/api/__snapshots__/github.spec.js.snap b/test/api/__snapshots__/github.spec.js.snap index 33ba760614b7f643538cd7fa71576b35a0efb97a..89d1260379ecdf6454327288233780266cab03ef 100644 --- a/test/api/__snapshots__/github.spec.js.snap +++ b/test/api/__snapshots__/github.spec.js.snap @@ -529,6 +529,8 @@ Object { "base": Object { "sha": "1234", }, + "canRebase": true, + "commits": 1, "displayNumber": "Pull Request #1", "isUnmergeable": true, "mergeable_state": "dirty", @@ -542,6 +544,8 @@ Object { "base": Object { "sha": "5678", }, + "canRebase": true, + "commits": 1, "displayNumber": "Pull Request #1", "isStale": true, "number": 1, @@ -549,6 +553,35 @@ Object { } `; +exports[`api/github getPr(prNo) should return a rebaseable PR despite multiple commits 1`] = ` +Object { + "base": Object { + "sha": "1234", + }, + "canRebase": true, + "commits": 2, + "displayNumber": "Pull Request #1", + "isUnmergeable": true, + "mergeable_state": "dirty", + "number": 1, + "state": "open", +} +`; + +exports[`api/github getPr(prNo) should return an unrebaseable PR if multiple authors 1`] = ` +Object { + "base": Object { + "sha": "1234", + }, + "commits": 2, + "displayNumber": "Pull Request #1", + "isUnmergeable": true, + "mergeable_state": "dirty", + "number": 1, + "state": "open", +} +`; + exports[`api/github initRepo should initialise the config for the repo - 0 1`] = ` Array [ Array [ diff --git a/test/api/github.spec.js b/test/api/github.spec.js index 8008f8b9e18b0f57480d76d62c2a6e57bfb4d80a..1cf8de88a4b98609e6371a63ff35e13d7e568f25 100644 --- a/test/api/github.spec.js +++ b/test/api/github.spec.js @@ -263,8 +263,8 @@ describe('api/github', () => { }); [ { number: 1, state: 'closed', base: { sha: '1234' } }, - { number: 1, state: 'open', mergeable_state: 'dirty', base: { sha: '1234' } }, - { number: 1, state: 'open', base: { sha: '5678' } }, + { number: 1, state: 'open', mergeable_state: 'dirty', base: { sha: '1234' }, commits: 1 }, + { number: 1, state: 'open', base: { sha: '5678' }, commits: 1 }, ].forEach((body, i) => { it(`should return a PR object - ${i}`, async () => { await initRepo('some/repo', 'token'); @@ -275,6 +275,52 @@ describe('api/github', () => { expect(pr).toMatchSnapshot(); }); }); + it('should return a rebaseable PR despite multiple commits', async () => { + await initRepo('some/repo', 'token'); + ghGot.mockImplementationOnce(() => ({ + body: { + number: 1, + state: 'open', + mergeable_state: 'dirty', + base: { sha: '1234' }, + commits: 2, + }, + })); + ghGot.mockImplementationOnce(() => ({ + body: [{ + author: { + login: 'foo', + }, + }], + })); + const pr = await github.getPr(1234); + expect(pr).toMatchSnapshot(); + }); + it('should return an unrebaseable PR if multiple authors', async () => { + await initRepo('some/repo', 'token'); + ghGot.mockImplementationOnce(() => ({ + body: { + number: 1, + state: 'open', + mergeable_state: 'dirty', + base: { sha: '1234' }, + commits: 2, + }, + })); + ghGot.mockImplementationOnce(() => ({ + body: [{ + author: { + login: 'foo', + }, + }, { + author: { + login: 'bar', + }, + }], + })); + const pr = await github.getPr(1234); + expect(pr).toMatchSnapshot(); + }); }); describe('updatePr(prNo, title, body)', () => { it('should update the PR', async () => {