From 4665f1d60284fef73dbdb60fb33fcb5e9646745d Mon Sep 17 00:00:00 2001 From: RahulGautamSingh Date: Sun, 18 Jun 2023 00:10:30 +0545 Subject: [PATCH] feat(github): update pr baseBranch (#22663) Co-authored-by: Rhys Arkins --- lib/modules/platform/github/index.spec.ts | 16 +++++++++++ lib/modules/platform/github/index.ts | 4 +++ lib/modules/platform/types.ts | 1 + .../repository/update/pr/index.spec.ts | 28 +++++++++++++++++++ lib/workers/repository/update/pr/index.ts | 16 ++++++++++- .../repository/update/pr/pr-fingerprint.ts | 2 ++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 3714876461c986..fd917c0a98daa3 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -2829,6 +2829,22 @@ describe('modules/platform/github/index', () => { await expect(github.updatePr(pr)).toResolve(); }); + + it('should update target branch', async () => { + const pr: UpdatePrConfig = { + number: 1234, + prTitle: 'The New Title', + prBody: 'Hello world again', + state: 'closed', + targetBranch: 'new_base', + }; + const scope = httpMock.scope(githubApiHost); + initRepoMock(scope, 'some/repo'); + await github.initRepo({ repository: 'some/repo' }); + scope.patch('/repos/some/repo/pulls/1234').reply(200, pr); + + await expect(github.updatePr(pr)).toResolve(); + }); }); describe('mergePr(prNo)', () => { diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 307e7a0a3731f8..d00cc2df6365c3 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -1602,6 +1602,7 @@ export async function updatePr({ prTitle: title, prBody: rawBody, state, + targetBranch, }: UpdatePrConfig): Promise { logger.debug(`updatePr(${prNo}, ${title}, body)`); const body = sanitize(rawBody); @@ -1609,6 +1610,9 @@ export async function updatePr({ if (body) { patchBody.body = body; } + if (targetBranch) { + patchBody.base = targetBranch; + } if (state) { patchBody.state = state; } diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index bfc54c32251a4c..4a0d5a825b9cb2 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -112,6 +112,7 @@ export interface UpdatePrConfig { prTitle: string; prBody?: string; state?: 'open' | 'closed'; + targetBranch?: string; } export interface EnsureIssueConfig { title: string; diff --git a/lib/workers/repository/update/pr/index.spec.ts b/lib/workers/repository/update/pr/index.spec.ts index 2daad4639762e0..06caf733c26267 100644 --- a/lib/workers/repository/update/pr/index.spec.ts +++ b/lib/workers/repository/update/pr/index.spec.ts @@ -65,6 +65,7 @@ describe('workers/repository/update/pr/index', () => { title: prTitle, bodyStruct, state: 'open', + targetBranch: 'base', }; const config: BranchConfig = { @@ -304,6 +305,32 @@ describe('workers/repository/update/pr/index', () => { ); }); + it('updates PR target branch if base branch changed in config', async () => { + platform.getBranchPr.mockResolvedValueOnce(pr); + + const res = await ensurePr({ ...config, baseBranch: 'new_base' }); // user changed base branch in config + + expect(platform.updatePr).toHaveBeenCalled(); + expect(platform.createPr).not.toHaveBeenCalled(); + expect(prCache.setPrCache).toHaveBeenCalled(); + expect(logger.logger.info).toHaveBeenCalledWith( + { pr: pr.number, prTitle }, + `PR updated` + ); + expect(logger.logger.debug).toHaveBeenCalledWith( + { + branchName: 'renovate-branch', + oldBaseBranch: 'base', + newBaseBranch: 'new_base', + }, + 'PR base branch has changed' + ); + expect(res).toEqual({ + type: 'with-pr', + pr: { ...pr, targetBranch: 'new_base' }, // updated target branch of pr + }); + }); + it('ignores reviewable content ', async () => { // See: https://reviewable.io/ @@ -892,6 +919,7 @@ describe('workers/repository/update/pr/index', () => { title: prTitle, bodyStruct, state: 'open', + targetBranch: 'base', }, }); expect(logger.logger.debug).toHaveBeenCalledWith( diff --git a/lib/workers/repository/update/pr/index.ts b/lib/workers/repository/update/pr/index.ts index cadbb3bea8df14..2a2dea9432c145 100644 --- a/lib/workers/repository/update/pr/index.ts +++ b/lib/workers/repository/update/pr/index.ts @@ -342,6 +342,7 @@ export async function ensurePr( const newPrTitle = stripEmojis(prTitle); const newPrBodyHash = hashBody(prBody); if ( + existingPr?.targetBranch === config.baseBranch && existingPrTitle === newPrTitle && existingPrBodyHash === newPrBodyHash ) { @@ -353,6 +354,16 @@ export async function ensurePr( return { type: 'with-pr', pr: existingPr }; } // PR must need updating + if (existingPr?.targetBranch !== config.baseBranch) { + logger.debug( + { + branchName, + oldBaseBranch: existingPr?.targetBranch, + newBaseBranch: config.baseBranch, + }, + 'PR base branch has changed' + ); + } if (existingPrTitle !== newPrTitle) { logger.debug( { @@ -370,6 +381,7 @@ export async function ensurePr( 'PR body changed' ); } + if (GlobalConfig.get('dryRun')) { logger.info(`DRY-RUN: Would update PR #${existingPr.number}`); return { type: 'with-pr', pr: existingPr }; @@ -379,6 +391,7 @@ export async function ensurePr( prTitle, prBody, platformOptions: getPlatformPrOptions(config), + targetBranch: config.baseBranch, }); logger.info({ pr: existingPr.number, prTitle }, `PR updated`); setPrCache(branchName, prBodyFingerprint, true); @@ -389,6 +402,7 @@ export async function ensurePr( ...existingPr, bodyStruct: getPrBodyStruct(prBody), title: prTitle, + targetBranch: config.baseBranch, }, }; } @@ -412,7 +426,7 @@ export async function ensurePr( } pr = await platform.createPr({ sourceBranch: branchName, - targetBranch: config.baseBranch ?? '', + targetBranch: config.baseBranch, prTitle, prBody, labels: prepareLabels(config), diff --git a/lib/workers/repository/update/pr/pr-fingerprint.ts b/lib/workers/repository/update/pr/pr-fingerprint.ts index cd91d440690b5b..14889efcde7f06 100644 --- a/lib/workers/repository/update/pr/pr-fingerprint.ts +++ b/lib/workers/repository/update/pr/pr-fingerprint.ts @@ -24,6 +24,7 @@ export interface FilteredBranchUpgradeConfig { export interface PrBodyFingerprintConfig { // BranchConfig - filtered automerge?: boolean; + baseBranch?: string; automergeSchedule?: string[]; hasReleaseNotes?: boolean; isPin?: boolean; @@ -63,6 +64,7 @@ export function generatePrBodyFingerprintConfig( return { automerge: config.automerge, automergeSchedule: config.automergeSchedule, + baseBranch: config.baseBranch, filteredUpgrades, hasReleaseNotes: config.hasReleaseNotes, isPin: config.isPin,