diff --git a/lib/platform/azure/__snapshots__/util.spec.ts.snap b/lib/platform/azure/__snapshots__/util.spec.ts.snap index 53d676b17e3b420a5199d7fc95e76ddf48cecc44..55e871558368717b769ad16455e7320da3fd03f3 100644 --- a/lib/platform/azure/__snapshots__/util.spec.ts.snap +++ b/lib/platform/azure/__snapshots__/util.spec.ts.snap @@ -42,21 +42,6 @@ Object { } `; -exports[`platform/azure/util getRenovatePRFormat should be formated (isConflicted) 1`] = ` -Object { - "body": undefined, - "createdAt": undefined, - "displayNumber": "Pull Request #undefined", - "isConflicted": true, - "mergeStatus": 2, - "number": undefined, - "sourceBranch": undefined, - "sourceRefName": undefined, - "state": "open", - "targetBranch": undefined, -} -`; - exports[`platform/azure/util getRenovatePRFormat should be formated (not closed) 1`] = ` Object { "body": undefined, diff --git a/lib/platform/azure/util.spec.ts b/lib/platform/azure/util.spec.ts index 8dad90be812e264a5bdd3418108713502363d7a1..dbcf61b2f3a25927a23e2fde434b04c0fa8bb1d9 100644 --- a/lib/platform/azure/util.spec.ts +++ b/lib/platform/azure/util.spec.ts @@ -107,11 +107,6 @@ describe('platform/azure/util', () => { const res = getRenovatePRFormat({ status: 1 } as any); expect(res).toMatchSnapshot(); }); - - it('should be formated (isConflicted)', () => { - const res = getRenovatePRFormat({ mergeStatus: 2 } as any); - expect(res).toMatchSnapshot(); - }); }); describe('streamToString', () => { diff --git a/lib/platform/azure/util.ts b/lib/platform/azure/util.ts index 15372cb3abe5738e1a5e0f3a0476c42de6e18f85..32f8d6ec7aef3362788e4a84edb2ed3b3dec04cf 100644 --- a/lib/platform/azure/util.ts +++ b/lib/platform/azure/util.ts @@ -2,7 +2,6 @@ import { GitPullRequest, GitRepository, GitStatusContext, - PullRequestAsyncStatus, PullRequestStatus, } from 'azure-devops-node-api/interfaces/GitInterfaces.js'; import { logger } from '../../logger'; @@ -103,8 +102,6 @@ export function getRenovatePRFormat(azurePr: GitPullRequest): AzurePr { const sourceRefName = azurePr.sourceRefName; - const isConflicted = azurePr.mergeStatus === PullRequestAsyncStatus.Conflicts; - return { ...azurePr, sourceBranch, @@ -115,7 +112,6 @@ export function getRenovatePRFormat(azurePr: GitPullRequest): AzurePr { sourceRefName, targetBranch, createdAt, - ...(isConflicted && { isConflicted }), } as AzurePr; } diff --git a/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap b/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap index a9dc459199cf13bb4aeb19f6f98b90f709368b50..9c9c81793dca028661faa58166ac7913a60a9dca 100644 --- a/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap +++ b/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap @@ -1597,7 +1597,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -2322,7 +2321,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -2343,7 +2341,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -2364,7 +2361,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -2486,7 +2482,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -6095,7 +6090,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -6820,7 +6814,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -6841,7 +6834,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -6862,7 +6854,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", @@ -6984,7 +6975,6 @@ Object { "createdAt": 1547853840016, "displayNumber": "Pull Request #5", "hasReviewers": true, - "isConflicted": false, "number": 5, "reviewers": Array [ "userName2", diff --git a/lib/platform/bitbucket-server/index.ts b/lib/platform/bitbucket-server/index.ts index 2a01c173fc03a29766489a4105b7e314fbbb43f4..087b0413c39cb267befd0e68e19d7c7e4ce03a00 100644 --- a/lib/platform/bitbucket-server/index.ts +++ b/lib/platform/bitbucket-server/index.ts @@ -297,7 +297,6 @@ export async function getPr( `./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/pull-requests/${prNo}/merge`, { useCache: !refreshCache } ); - pr.isConflicted = !!mergeRes.body.conflicted; pr.canMerge = !!mergeRes.body.canMerge; } diff --git a/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap b/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap index 3793afe6a79511d5dd2d6f6fc6b96f0e5d58ce43..8589269d259d1e4fe5159ccf512cfb2abbf69cd1 100644 --- a/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap +++ b/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap @@ -26,16 +26,6 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/diff", - }, Object { "body": Object { "reviewers": Array [ @@ -469,11 +459,9 @@ Array [ exports[`platform/bitbucket/index getBranchPr() bitbucket finds PR for branch 1`] = ` Object { "body": "summary", - "canMerge": true, "createdAt": "2018-07-02T07:02:25.275030+00:00", "displayNumber": "Pull Request #5", "hasReviewers": false, - "isConflicted": false, "number": 5, "sourceBranch": "branch", "state": "open", @@ -517,16 +505,6 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/diff", - }, ] `; @@ -1108,11 +1086,9 @@ Array [ exports[`platform/bitbucket/index getPr() canRebase 1`] = ` Object { "body": "summary", - "canMerge": true, "createdAt": "2018-07-02T07:02:25.275030+00:00", "displayNumber": "Pull Request #3", "hasReviewers": false, - "isConflicted": false, "number": 3, "sourceBranch": "branch", "state": "open", @@ -1124,11 +1100,9 @@ Object { exports[`platform/bitbucket/index getPr() canRebase 2`] = ` Object { "body": "summary", - "canMerge": true, "createdAt": "2018-07-02T07:02:25.275030+00:00", "displayNumber": "Pull Request #5", "hasReviewers": false, - "isConflicted": false, "number": 5, "sourceBranch": "branch", "state": "open", @@ -1140,11 +1114,9 @@ Object { exports[`platform/bitbucket/index getPr() canRebase 3`] = ` Object { "body": "summary", - "canMerge": true, "createdAt": "2018-07-02T07:02:25.275030+00:00", "displayNumber": "Pull Request #5", "hasReviewers": false, - "isConflicted": false, "number": 5, "sourceBranch": "branch", "state": "open", @@ -1177,16 +1149,6 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/3", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/3/diff", - }, Object { "headers": Object { "accept": "application/json", @@ -1198,16 +1160,6 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/diff", - }, Object { "headers": Object { "accept": "application/json", @@ -1219,27 +1171,15 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/diff", - }, ] `; exports[`platform/bitbucket/index getPr() exists 1`] = ` Object { "body": "summary", - "canMerge": true, "createdAt": "2018-07-02T07:02:25.275030+00:00", "displayNumber": "Pull Request #5", "hasReviewers": false, - "isConflicted": false, "number": 5, "sourceBranch": "branch", "state": "open", @@ -1272,16 +1212,6 @@ Array [ "method": "GET", "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5", }, - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "authorization": "Basic YWJjOjEyMw==", - "host": "api.bitbucket.org", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/diff", - }, ] `; diff --git a/lib/platform/bitbucket/index.spec.ts b/lib/platform/bitbucket/index.spec.ts index b09910050d2c008a926c28bce39d01b560c33079..45f20af1b9fb80ecd638dcf8117e13424a1a8ffa 100644 --- a/lib/platform/bitbucket/index.spec.ts +++ b/lib/platform/bitbucket/index.spec.ts @@ -17,22 +17,6 @@ const pr = { created_on: '2018-07-02T07:02:25.275030+00:00', }; -const diff = ` -diff --git a/requirements.txt b/requirements.txt -index 7e08d70..f5283ca 100644 ---- a/requirements.txt -+++ b/requirements.txt -@@ -7,7 +7,7 @@ docutils==0.12 -enum34==1.1.6 -futures==3.2.0 -isort==4.3.4 --jedi==0.11.1 -+jedi==0.12.1 -lazy-object-proxy==1.3.1 -lxml==3.6.0 -mccabe==0.6.1 -`; - describe('platform/bitbucket/index', () => { let bitbucket: Platform; let hostRules: jest.Mocked<typeof import('../../util/host-rules')>; @@ -164,9 +148,7 @@ describe('platform/bitbucket/index', () => { ) .reply(200, { values: [pr] }) .get('/2.0/repositories/some/repo/pullrequests/5') - .reply(200, pr) - .get('/2.0/repositories/some/repo/pullrequests/5/diff') - .reply(200, diff); + .reply(200, pr); expect(await bitbucket.getBranchPr('branch')).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); @@ -584,8 +566,6 @@ describe('platform/bitbucket/index', () => { scope .get('/2.0/repositories/some/repo/pullrequests/5') .reply(200, pr) - .get('/2.0/repositories/some/repo/pullrequests/5/diff') - .reply(200, diff) .put('/2.0/repositories/some/repo/pullrequests/5') .reply(200); await bitbucket.addReviewers(5, ['someuser', 'someotheruser']); @@ -699,11 +679,7 @@ describe('platform/bitbucket/index', () => { describe('getPr()', () => { it('exists', async () => { const scope = await initRepoMock(); - scope - .get('/2.0/repositories/some/repo/pullrequests/5') - .reply(200, pr) - .get('/2.0/repositories/some/repo/pullrequests/5/diff') - .reply(200, diff); + scope.get('/2.0/repositories/some/repo/pullrequests/5').reply(200, pr); expect(await bitbucket.getPr(5)).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); }); @@ -722,14 +698,9 @@ describe('platform/bitbucket/index', () => { state: 'OPEN', created_on: '2018-07-02T07:02:25.275030+00:00', }) - .get('/2.0/repositories/some/repo/pullrequests/3/diff') - .reply(200, ' ') .get('/2.0/repositories/some/repo/pullrequests/5') .twice() - .reply(200, pr) - .get('/2.0/repositories/some/repo/pullrequests/5/diff') - .twice() - .reply(200, diff); + .reply(200, pr); expect(await bitbucket.getPr(3)).toMatchSnapshot(); expect(await bitbucket.getPr(5)).toMatchSnapshot(); diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts index 7a1fc392a1a927825119b8e5daca4f6a4fd5c81a..a3bd1a580f05c98080622c8a225fc5d0427fdf18 100644 --- a/lib/platform/bitbucket/index.ts +++ b/lib/platform/bitbucket/index.ts @@ -1,7 +1,6 @@ import URL from 'url'; import is from '@sindresorhus/is'; import JSON5 from 'json5'; -import parseDiff from 'parse-diff'; import { PlatformId } from '../../constants'; import { REPOSITORY_NOT_FOUND } from '../../constants/error-messages'; import { logger } from '../../logger'; @@ -270,16 +269,6 @@ export async function findPr({ return pr; } -async function isPrConflicted(prNo: number): Promise<boolean> { - const diff = ( - await bitbucketHttp.get( - `/2.0/repositories/${config.repository}/pullrequests/${prNo}/diff` - ) - ).body; - - return utils.isConflicted(parseDiff(diff)); -} - // Gets details for a PR export async function getPr(prNo: number): Promise<Pr | null> { const pr = ( @@ -298,12 +287,6 @@ export async function getPr(prNo: number): Promise<Pr | null> { ...utils.prInfo(pr), }; - if (utils.prStates.open.includes(pr.state)) { - res.isConflicted = await isPrConflicted(prNo); - - // TODO: Is that correct? Should we check getBranchStatus like gitlab? (#9618) - res.canMerge = !res.isConflicted; - } res.hasReviewers = is.nonEmptyArray(pr.reviewers); return res; diff --git a/lib/platform/bitbucket/utils.spec.ts b/lib/platform/bitbucket/utils.spec.ts index e33ead8098c9970a283faf87828baf199446738c..61ba6ddb271bce48ff6d12ab63503535d474f567 100644 --- a/lib/platform/bitbucket/utils.spec.ts +++ b/lib/platform/bitbucket/utils.spec.ts @@ -34,10 +34,4 @@ describe('platform/bitbucket/utils', () => { expect(httpMock.getTrace()).toHaveLength(3); expect(httpMock.getTrace()).toMatchSnapshot(); }); - - it('isConflicted', () => { - expect( - utils.isConflicted([{ chunks: [{ changes: [{ content: '+=======' }] }] }]) - ).toBeTrue(); - }); }); diff --git a/lib/platform/bitbucket/utils.ts b/lib/platform/bitbucket/utils.ts index a77075053bb690563b9c505c04a90c53b5b2453e..90cc7748cfb522cc6ba60a969491ec824c01dbde 100644 --- a/lib/platform/bitbucket/utils.ts +++ b/lib/platform/bitbucket/utils.ts @@ -148,27 +148,6 @@ export async function accumulateValues<T = any>( return accumulator; } -interface Files { - chunks: { - changes: { - content: string; - }[]; - }[]; -} - -export function isConflicted(files: Files[]): boolean { - for (const file of files) { - for (const chunk of file.chunks) { - for (const change of chunk.changes) { - if (change.content === '+=======') { - return true; - } - } - } - } - return false; -} - export interface PrResponse { id: number; title: string; diff --git a/lib/platform/gitea/__snapshots__/index.spec.ts.snap b/lib/platform/gitea/__snapshots__/index.spec.ts.snap index 45d8f593ea571e19ebdb8628256e7d20f43774c6..f24e5756ac0c332c44675f1b4455197cf28e5192 100644 --- a/lib/platform/gitea/__snapshots__/index.spec.ts.snap +++ b/lib/platform/gitea/__snapshots__/index.spec.ts.snap @@ -7,7 +7,6 @@ Object { "createdAt": "2014-04-01T05:14:20Z", "displayNumber": "Pull Request #42", "hasAssignees": false, - "isConflicted": false, "number": 42, "sha": "0d9c7726c3d628b7e28af234595cfd20febdbf8e", "sourceBranch": "pr-branch", @@ -25,7 +24,6 @@ Object { "createdAt": "2014-04-01T05:14:20Z", "displayNumber": "Pull Request #42", "hasAssignees": false, - "isConflicted": false, "number": 42, "sha": "0d9c7726c3d628b7e28af234595cfd20febdbf8e", "sourceBranch": "pr-branch", @@ -43,7 +41,6 @@ Object { "createdAt": "2015-03-22T20:36:16Z", "displayNumber": "Pull Request #1", "hasAssignees": false, - "isConflicted": false, "number": 1, "sha": "some-head-sha", "sourceBranch": "some-head-branch", @@ -61,7 +58,6 @@ Object { "createdAt": "2015-03-22T20:36:16Z", "displayNumber": "Pull Request #1", "hasAssignees": false, - "isConflicted": false, "number": 1, "sha": "some-head-sha", "sourceBranch": "some-head-branch", @@ -87,7 +83,6 @@ Array [ "createdAt": "2015-03-22T20:36:16Z", "displayNumber": "Pull Request #1", "hasAssignees": false, - "isConflicted": false, "number": 1, "sha": "some-head-sha", "sourceBranch": "some-head-branch", @@ -102,7 +97,6 @@ Array [ "createdAt": "2011-08-18T22:30:38Z", "displayNumber": "Pull Request #2", "hasAssignees": false, - "isConflicted": false, "number": 2, "sha": "other-head-sha", "sourceBranch": "other-head-branch", @@ -122,7 +116,6 @@ Array [ "createdAt": "2015-03-22T20:36:16Z", "displayNumber": "Pull Request #1", "hasAssignees": false, - "isConflicted": false, "number": 1, "sha": "some-head-sha", "sourceBranch": "some-head-branch", @@ -137,7 +130,6 @@ Array [ "createdAt": "2011-08-18T22:30:38Z", "displayNumber": "Pull Request #2", "hasAssignees": false, - "isConflicted": false, "number": 2, "sha": "other-head-sha", "sourceBranch": "other-head-branch", diff --git a/lib/platform/gitea/index.ts b/lib/platform/gitea/index.ts index ce2b535aac759565e8021a93a53257b236bbb2e0..e55150cff021032862df0a0af1009ca35b05c007 100644 --- a/lib/platform/gitea/index.ts +++ b/lib/platform/gitea/index.ts @@ -103,7 +103,6 @@ function toRenovatePR(data: helper.PR): Pr | null { sourceRepo: data.head.repo.full_name, createdAt: data.created_at, canMerge: data.mergeable, - isConflicted: !data.mergeable, hasAssignees: !!(data.assignee?.login || is.nonEmptyArray(data.assignees)), }; } diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap index d6715d11e3db39e6d5e52fad9a5ed79ea7cb7dde..dba7b4034e7d56520e65b006bef6911e0c2cb6fc 100644 --- a/lib/platform/github/__snapshots__/index.spec.ts.snap +++ b/lib/platform/github/__snapshots__/index.spec.ts.snap @@ -5571,7 +5571,6 @@ Object { "displayNumber": "Pull Request #2500", "hasAssignees": false, "hasReviewers": false, - "isConflicted": true, "number": 2500, "sourceBranch": "renovate/jest-monorepo", "state": "open", @@ -6005,7 +6004,6 @@ Object { "canMergeReason": "mergeable = undefined", "commits": 1, "displayNumber": "Pull Request #1", - "isConflicted": true, "mergeable_state": "dirty", "number": 1, "sha": undefined, diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index 2bb8d39b86961a07fdc28da984e4890aa1113bf6..f8a6f575f967f6d07bd947fdf9f938992d964330 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -624,12 +624,6 @@ async function getOpenPrs(): Promise<PrList> { pr.canMerge = false; pr.canMergeReason = `mergeStateStatus = ${pr.mergeStateStatus}`; } - // https://developer.github.com/v4/enum/mergestatestatus - if (pr.mergeStateStatus === 'DIRTY') { - pr.isConflicted = true; - } else { - pr.isConflicted = false; - } if (pr.labels) { pr.labels = pr.labels.nodes.map((label) => label.name); } @@ -692,10 +686,6 @@ export async function getPr(prNo: number): Promise<Pr | null> { pr.canMerge = false; pr.canMergeReason = `mergeable = ${pr.mergeable}`; } - if (pr.mergeable_state === 'dirty') { - logger.debug({ prNo }, 'PR state is dirty so unmergeable'); - pr.isConflicted = true; - } } return pr; } diff --git a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap index dc2c6e615441ee4d2c70b87b6efa6715d1290c57..4180bbfec0535aaf5b3a7c23421c26f1f2b67b14 100644 --- a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap +++ b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap @@ -2441,7 +2441,6 @@ Object { "displayNumber": "Merge Request #12345", "hasAssignees": false, "hasReviewers": false, - "isConflicted": true, "isDraft": true, "labels": undefined, "number": 12345, @@ -2476,7 +2475,6 @@ Object { "displayNumber": "Merge Request #12345", "hasAssignees": false, "hasReviewers": false, - "isConflicted": true, "isDraft": true, "labels": undefined, "number": 12345, @@ -2511,7 +2509,6 @@ Object { "displayNumber": "Merge Request #12345", "hasAssignees": false, "hasReviewers": false, - "isConflicted": true, "labels": undefined, "number": 12345, "sha": undefined, @@ -2545,7 +2542,6 @@ Object { "displayNumber": "Merge Request #12345", "hasAssignees": true, "hasReviewers": false, - "isConflicted": true, "labels": undefined, "number": 12345, "sha": undefined, diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts index 4c1f309f72087dd232027177782bfc0162e52089..57ec3d30ca1b841892a893e43a8bcd02bb0daff7 100644 --- a/lib/platform/gitlab/index.ts +++ b/lib/platform/gitlab/index.ts @@ -614,7 +614,6 @@ export async function getPr(iid: number): Promise<Pr> { if (mr.merge_status === 'cannot_be_merged') { logger.debug('pr cannot be merged'); pr.canMerge = false; - pr.isConflicted = true; } else if (pr.state === PrState.Open) { const branchStatus = await getBranchStatus(pr.sourceBranch); if (branchStatus === BranchStatus.green) { diff --git a/lib/platform/types.ts b/lib/platform/types.ts index 0c0936e446beffad4912944cc70051dba9c31843..b1b3490dac8b4f0466c2ee850c7d6f241c77b148 100644 --- a/lib/platform/types.ts +++ b/lib/platform/types.ts @@ -55,7 +55,6 @@ export interface Pr { displayNumber?: string; hasAssignees?: boolean; hasReviewers?: boolean; - isConflicted?: boolean; labels?: string[]; number?: number; reviewers?: string[]; diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts index f609565c4a522c5f423dae95acfba71d8cd8b64b..de9da6eaa15603db410f3911bdfd68b18bee77f4 100644 --- a/lib/util/git/index.spec.ts +++ b/lib/util/git/index.spec.ts @@ -600,4 +600,83 @@ describe('util/git/index', () => { expect(() => git.setGitAuthor('invalid')).toThrow(CONFIG_VALIDATION); }); }); + + describe('isBranchConflicted', () => { + beforeAll(async () => { + const repo = Git(base.path); + await repo.init(); + + await repo.checkout(['-b', 'renovate/conflicted_branch', defaultBranch]); + await repo.checkout([ + '-b', + 'renovate/non_conflicted_branch', + defaultBranch, + ]); + + await repo.checkout(defaultBranch); + await fs.writeFile(base.path + '/one_file', 'past (updated)'); + await repo.add(['one_file']); + await repo.commit('past (updated) message'); + + await repo.checkout('renovate/conflicted_branch'); + await fs.writeFile(base.path + '/one_file', 'past (updated branch)'); + await repo.add(['one_file']); + await repo.commit('past (updated branch) message'); + + await repo.checkout('renovate/non_conflicted_branch'); + await fs.writeFile(base.path + '/another_file', 'other'); + await repo.add(['another_file']); + await repo.commit('other (updated branch) message'); + + await repo.checkout(defaultBranch); + }); + + it('returns true for non-existing source branch', async () => { + const res = await git.isBranchConflicted( + defaultBranch, + 'renovate/non_existing_branch' + ); + expect(res).toBeTrue(); + }); + + it('returns true for non-existing target branch', async () => { + const res = await git.isBranchConflicted( + 'renovate/non_existing_branch', + 'renovate/non_conflicted_branch' + ); + expect(res).toBeTrue(); + }); + + it('detects conflicted branch', async () => { + const branchBefore = 'renovate/non_conflicted_branch'; + await git.checkoutBranch(branchBefore); + + const res = await git.isBranchConflicted( + defaultBranch, + 'renovate/conflicted_branch' + ); + + expect(res).toBeTrue(); + + const status = await git.getRepoStatus(); + expect(status.current).toEqual(branchBefore); + expect(status.isClean()).toBeTrue(); + }); + + it('detects non-conflicted branch', async () => { + const branchBefore = 'renovate/conflicted_branch'; + await git.checkoutBranch(branchBefore); + + const res = await git.isBranchConflicted( + defaultBranch, + 'renovate/non_conflicted_branch' + ); + + expect(res).toBeFalse(); + + const status = await git.getRepoStatus(); + expect(status.current).toEqual(branchBefore); + expect(status.isClean()).toBeTrue(); + }); + }); }); diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 9761bdb0cc2b7421f9c4c85d5fe0514dfb386c57..7c9f5512eba8e8ad6e9c0e687cc61002c9ac4950 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -573,6 +573,56 @@ export async function isBranchModified(branchName: string): Promise<boolean> { return true; } +export async function isBranchConflicted( + baseBranch: string, + branch: string +): Promise<boolean> { + logger.debug(`isBranchConflicted(${baseBranch}, ${branch})`); + await syncGit(); + + if (!branchExists(baseBranch) || !branchExists(branch)) { + logger.warn( + { baseBranch, branch }, + 'isBranchConflicted: branch does not exist' + ); + return true; + } + + let result = false; + + const origBranch = config.currentBranch; + try { + await git.reset(ResetMode.HARD); + if (origBranch !== baseBranch) { + await git.checkout(baseBranch); + } + await git.merge(['--no-commit', '--no-ff', `origin/${branch}`]); + } catch (err) { + result = true; + // istanbul ignore if: not easily testable + if (!err?.git?.conflicts?.length) { + logger.debug( + { baseBranch, branch, err }, + 'isBranchConflicted: unknown error' + ); + } + } finally { + try { + await git.merge(['--abort']); + if (origBranch !== baseBranch) { + await git.checkout(origBranch); + } + } catch (err) /* istanbul ignore next */ { + logger.debug( + { baseBranch, branch, err }, + 'isBranchConflicted: cleanup error' + ); + } + } + + return result; +} + export async function deleteBranch(branchName: string): Promise<void> { await syncGit(); try { diff --git a/lib/workers/branch/index.ts b/lib/workers/branch/index.ts index d0d301718824debba2e782d10a8a253b679bc929..84e92e02661c8f2ca2f0bb9e0100d0823bfb89c2 100644 --- a/lib/workers/branch/index.ts +++ b/lib/workers/branch/index.ts @@ -25,6 +25,7 @@ import { deleteBranch, getBranchCommit, branchExists as gitBranchExists, + isBranchConflicted, isBranchModified, } from '../../util/git'; import { @@ -439,7 +440,11 @@ export async function processBranch( } } const forcedManually = userRebaseRequested || !branchExists; - config.forceCommit = forcedManually || branchPr?.isConflicted; + + config.isConflicted ??= + branchExists && + (await isBranchConflicted(config.baseBranch, config.branchName)); + config.forceCommit = forcedManually || config.isConflicted; config.stopUpdating = branchPr?.labels?.includes(config.stopUpdatingLabel); diff --git a/lib/workers/branch/reuse.spec.ts b/lib/workers/branch/reuse.spec.ts index edcbd3ce94de8dbaeb68e083238866aa9b387252..0cdacc6aa881e2549f9a8688b8d10bff4d3153be 100644 --- a/lib/workers/branch/reuse.spec.ts +++ b/lib/workers/branch/reuse.spec.ts @@ -36,10 +36,8 @@ describe('workers/branch/reuse', () => { }); it('returns true if does not need rebasing', async () => { git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: false, - }); + git.isBranchConflicted.mockResolvedValueOnce(false); + platform.getBranchPr.mockResolvedValueOnce(pr); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBeTrue(); }); @@ -58,10 +56,8 @@ describe('workers/branch/reuse', () => { }, ]; git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: false, - }); + git.isBranchConflicted.mockResolvedValueOnce(false); + platform.getBranchPr.mockResolvedValueOnce(pr); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBe(false); }); @@ -80,20 +76,16 @@ describe('workers/branch/reuse', () => { }, ]; git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: false, - }); + git.isBranchConflicted.mockResolvedValueOnce(false); + platform.getBranchPr.mockResolvedValueOnce(pr); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBe(true); }); it('returns true if unmergeable and cannot rebase', async () => { git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: true, - }); + git.isBranchConflicted.mockResolvedValueOnce(true); + platform.getBranchPr.mockResolvedValueOnce(pr); git.isBranchModified.mockResolvedValueOnce(true); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBeTrue(); @@ -101,10 +93,8 @@ describe('workers/branch/reuse', () => { it('returns true if unmergeable and can rebase, but rebaseWhen is never', async () => { config.rebaseWhen = 'never'; git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: true, - }); + git.isBranchConflicted.mockResolvedValueOnce(true); + platform.getBranchPr.mockResolvedValueOnce(pr); git.isBranchModified.mockResolvedValueOnce(false); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBeTrue(); @@ -139,10 +129,8 @@ describe('workers/branch/reuse', () => { }); it('returns false if unmergeable and can rebase', async () => { git.branchExists.mockReturnValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: true, - }); + git.isBranchConflicted.mockResolvedValueOnce(true); + platform.getBranchPr.mockResolvedValueOnce(pr); git.isBranchModified.mockResolvedValueOnce(false); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBeFalse(); @@ -167,10 +155,8 @@ describe('workers/branch/reuse', () => { config.rebaseWhen = 'behind-base-branch'; git.branchExists.mockReturnValueOnce(true); git.isBranchStale.mockResolvedValueOnce(true); - platform.getBranchPr.mockResolvedValueOnce({ - ...pr, - isConflicted: true, - }); + git.isBranchConflicted.mockResolvedValueOnce(true); + platform.getBranchPr.mockResolvedValueOnce(pr); git.isBranchModified.mockResolvedValueOnce(true); const res = await shouldReuseExistingBranch(config); expect(res.reuseExistingBranch).toBeTrue(); diff --git a/lib/workers/branch/reuse.ts b/lib/workers/branch/reuse.ts index cd0e3938ea289a562036d1e4b56735685a7c76f8..1e55cb87c3557e28205f66575605c1fdf79006cb 100644 --- a/lib/workers/branch/reuse.ts +++ b/lib/workers/branch/reuse.ts @@ -2,7 +2,12 @@ import { GlobalConfig } from '../../config/global'; import { logger } from '../../logger'; import { platform } from '../../platform'; import type { RangeStrategy } from '../../types'; -import { branchExists, isBranchModified, isBranchStale } from '../../util/git'; +import { + branchExists, + isBranchConflicted, + isBranchModified, + isBranchStale, +} from '../../util/git'; import type { BranchConfig } from '../types'; type ParentBranch = { @@ -14,7 +19,7 @@ type ParentBranch = { export async function shouldReuseExistingBranch( config: BranchConfig ): Promise<ParentBranch> { - const { branchName } = config; + const { baseBranch, branchName } = config; const result: ParentBranch = { reuseExistingBranch: false }; // Check if branch exists if (!branchExists(branchName)) { @@ -74,9 +79,9 @@ export async function shouldReuseExistingBranch( } // Now check if PR is unmergeable. If so then we also rebase - result.isConflicted = !!pr?.isConflicted; + result.isConflicted = await isBranchConflicted(baseBranch, branchName); if (result.isConflicted) { - logger.debug('PR is conflicted'); + logger.debug('Branch is conflicted'); if ((await isBranchModified(branchName)) === false) { logger.debug(`Branch is not mergeable and needs rebasing`); diff --git a/lib/workers/pr/automerge.spec.ts b/lib/workers/pr/automerge.spec.ts index 967d127c7b56c3b2b70f06b92611420e55775e68..d4ae442c2db480cafec6c544b3a483b21332510b 100644 --- a/lib/workers/pr/automerge.spec.ts +++ b/lib/workers/pr/automerge.spec.ts @@ -99,7 +99,7 @@ describe('workers/pr/automerge', () => { }); it('should not automerge if enabled and pr is unmergeable', async () => { config.automerge = true; - pr.isConflicted = true; + git.isBranchConflicted.mockResolvedValueOnce(true); const res = await prAutomerge.checkAutoMerge(pr, config); expect(res).toEqual({ automerged: false, diff --git a/lib/workers/pr/automerge.ts b/lib/workers/pr/automerge.ts index 40025b50fcb64b29cc5352e231f60e29da4bbed3..87cb209211b854f8816c78be41f8ed7ca207f28c 100644 --- a/lib/workers/pr/automerge.ts +++ b/lib/workers/pr/automerge.ts @@ -2,7 +2,11 @@ import { GlobalConfig } from '../../config/global'; import { logger } from '../../logger'; import { Pr, platform } from '../../platform'; import { BranchStatus } from '../../types'; -import { deleteBranch, isBranchModified } from '../../util/git'; +import { + deleteBranch, + isBranchConflicted, + isBranchModified, +} from '../../util/git'; import { resolveBranchStatus } from '../branch/status-checks'; import { BranchConfig } from '../types'; @@ -36,7 +40,10 @@ export async function checkAutoMerge( rebaseRequested, } = config; // Return if PR not ready for automerge - if (pr.isConflicted) { + const isConflicted = + config.isConflicted ?? + (await isBranchConflicted(config.baseBranch, config.branchName)); + if (isConflicted) { logger.debug('PR is conflicted'); return { automerged: false, diff --git a/lib/workers/pr/index.spec.ts b/lib/workers/pr/index.spec.ts index 1c1a1eb445918cfe72531f9b6de74a1c7e55e624..5915de3808f4aebe229f9e101885c3d0a0abb6f7 100644 --- a/lib/workers/pr/index.spec.ts +++ b/lib/workers/pr/index.spec.ts @@ -160,7 +160,7 @@ describe('workers/pr/index', () => { }); it('should not automerge if enabled and pr is unmergeable', async () => { config.automerge = true; - pr.isConflicted = true; + git.isBranchConflicted.mockResolvedValueOnce(true); await prAutomerge.checkAutoMerge(pr, config); expect(platform.mergePr).toHaveBeenCalledTimes(0); }); diff --git a/lib/workers/repository/onboarding/pr/index.spec.ts b/lib/workers/repository/onboarding/pr/index.spec.ts index a2beb95758b0f7cc3eb264323defc210cf941c70..3d24d653132439697317edeb29400e0a5a2f364e 100644 --- a/lib/workers/repository/onboarding/pr/index.spec.ts +++ b/lib/workers/repository/onboarding/pr/index.spec.ts @@ -80,9 +80,9 @@ describe('workers/repository/onboarding/pr/index', () => { partial<Pr>({ title: 'Configure Renovate', body: createPrBody, - isConflicted: true, }) ); + git.isBranchConflicted.mockResolvedValueOnce(true); git.isBranchModified.mockResolvedValueOnce(true); await ensureOnboardingPr(config, {}, branches); expect(platform.createPr).toHaveBeenCalledTimes(0); @@ -113,9 +113,9 @@ describe('workers/repository/onboarding/pr/index', () => { partial<Pr>({ title: 'Configure Renovate', body: createPrBody, - isConflicted: true, }) ); + git.isBranchConflicted.mockResolvedValueOnce(true); git.isBranchModified.mockResolvedValueOnce(true); await ensureOnboardingPr(config, {}, branches); expect(logger.info).toHaveBeenCalledWith( diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index cd8ac079c23263ef8a8d9c08c9f53f780d0f46bd..00697727543791bb13c59b156f5099848e7269a3 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -4,7 +4,11 @@ import { logger } from '../../../../logger'; import type { PackageFile } from '../../../../manager/types'; import { platform } from '../../../../platform'; import { emojify } from '../../../../util/emoji'; -import { deleteBranch, isBranchModified } from '../../../../util/git'; +import { + deleteBranch, + isBranchConflicted, + isBranchModified, +} from '../../../../util/git'; import { addAssigneesReviewers, getPlatformPrOptions, @@ -76,7 +80,11 @@ If you need any further assistance then you can also [request help here](${confi configDesc = emojify( `### Configuration\n\n:abcd: Renovate has detected a custom config for this PR. Feel free to ask for [help](${config.productLinks.help}) if you have any doubts and would like it reviewed.\n\n` ); - if (existingPr?.isConflicted) { + const isConflicted = await isBranchConflicted( + config.baseBranch, + config.onboardingBranch + ); + if (isConflicted) { configDesc += emojify( `:warning: This PR has a merge conflict, however Renovate is unable to automatically fix that due to edits in this branch. Please resolve the merge conflict manually.\n\n` ); diff --git a/lib/workers/types.ts b/lib/workers/types.ts index 993535bb029e3ef60f5c0168d51dc791f13ee138..a145c52f94dc03da5939c780b8d2b6b5029b2072 100644 --- a/lib/workers/types.ts +++ b/lib/workers/types.ts @@ -120,4 +120,5 @@ export interface BranchConfig prBlockedBy?: PrBlockedBy; prNo?: number; stopUpdating?: boolean; + isConflicted?: boolean; } diff --git a/package.json b/package.json index 21322e33a7a827c58183c7cdd9c8c29f63150cfd..519c2b6fe6960452cadf2656f115599e8fec9985 100644 --- a/package.json +++ b/package.json @@ -187,7 +187,6 @@ "p-all": "3.0.0", "p-map": "4.0.0", "p-queue": "6.6.2", - "parse-diff": "0.9.0", "parse-link-header": "2.0.0", "redis": "4.0.2", "registry-auth-token": "4.2.1", diff --git a/yarn.lock b/yarn.lock index 41714d83993674c538af6301fe1cb65c2f3699ad..a3a3312d2e4c447c12dc39ccb02d8fc76e628a87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7618,11 +7618,6 @@ parse-conflict-json@*, parse-conflict-json@^2.0.1: just-diff "^5.0.1" just-diff-apply "^4.0.1" -parse-diff@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/parse-diff/-/parse-diff-0.9.0.tgz#2e71b5dc5d8f4b9c19c471fd6325646dc9f21724" - integrity sha512-Jn+VZORAezkfOXR6B40EZcXxdJBamtgBpfeoFH6hxD+p0e74nVaCL9SWlQj1ggc8b6AexgPKlDiiE0CMMZDSbQ== - parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"