From 1adc0777daf6a60918f089d55914ec449e022d9a Mon Sep 17 00:00:00 2001 From: Sergei Zharinov <zharinov@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:51:00 +0300 Subject: [PATCH] fix(platform/github): Fix branch recreation for existing branches (#21629) --- lib/modules/platform/github/index.spec.ts | 13 ++++--- lib/modules/platform/github/index.ts | 43 +++++++++++++---------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 9fac0812dd..91d35bc717 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -35,7 +35,6 @@ describe('modules/platform/github/index', () => { setBaseUrl(githubApiHost); - git.branchExists.mockReturnValue(true); git.isBranchBehindBase.mockResolvedValue(true); git.getBranchCommit.mockReturnValue( '0d9c7726c3d628b7e28af234595cfd20febdbf8e' @@ -861,6 +860,8 @@ describe('modules/platform/github/index', () => { updated_at: '01-09-2022', }, ]) + .head('/repos/some/repo/git/refs/heads/somebranch') + .reply(404) .post('/repos/some/repo/git/refs') .reply(201) .patch('/repos/some/repo/pulls/91') @@ -950,6 +951,8 @@ describe('modules/platform/github/index', () => { closed_at: DateTime.now().minus({ minutes: 10 }).toISO(), }, ]) + .head('/repos/some/repo/git/refs/heads/somebranch') + .reply(404) .post('/repos/some/repo/git/refs') .reply(201) .patch('/repos/some/repo/pulls/91') @@ -976,7 +979,7 @@ describe('modules/platform/github/index', () => { closed_at: DateTime.now().minus({ minutes: 10 }).toISO(), }, ]) - .post('/repos/some/repo/git/refs') + .head('/repos/some/repo/git/refs/heads/somebranch') .reply(422); await github.initRepo({ repository: 'some/repo' }); @@ -3243,7 +3246,6 @@ describe('modules/platform/github/index', () => { it('commits and returns SHA string', async () => { git.pushCommitToRenovateRef.mockResolvedValueOnce(); git.listCommitTree.mockResolvedValueOnce([]); - git.branchExists.mockReturnValueOnce(false); const scope = httpMock.scope(githubApiHost); @@ -3255,6 +3257,8 @@ describe('modules/platform/github/index', () => { .reply(200, { sha: '111' }) .post('/repos/some/repo/git/commits') .reply(200, { sha: '222' }) + .head('/repos/some/repo/git/refs/heads/foo/bar') + .reply(404) .post('/repos/some/repo/git/refs') .reply(200); @@ -3270,7 +3274,6 @@ describe('modules/platform/github/index', () => { it('performs rebase', async () => { git.pushCommitToRenovateRef.mockResolvedValueOnce(); git.listCommitTree.mockResolvedValueOnce([]); - git.branchExists.mockReturnValueOnce(true); const scope = httpMock.scope(githubApiHost); @@ -3282,6 +3285,8 @@ describe('modules/platform/github/index', () => { .reply(200, { sha: '111' }) .post('/repos/some/repo/git/commits') .reply(200, { sha: '222' }) + .head('/repos/some/repo/git/refs/heads/foo/bar') + .reply(200) .patch('/repos/some/repo/git/refs/heads/foo/bar') .reply(200); diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index 7c9ac146a3..ffc5f1ab89 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -742,6 +742,29 @@ export async function findPr({ const REOPEN_THRESHOLD_MILLIS = 1000 * 60 * 60 * 24 * 7; +async function ensureBranchSha(branchName: string, sha: string): Promise<void> { + const refUrl = `/repos/${config.repository}/git/refs/heads/${branchName}`; + + let branchExists = false; + try { + await githubApi.head(refUrl, { useCache: false }); + branchExists = true; + } catch (err) { + if (err.statusCode !== 404) { + throw err; + } + } + + if (branchExists) { + await githubApi.patchJson(refUrl, { body: { sha, force: true } }); + return; + } + + await githubApi.postJson(`/repos/${config.repository}/git/refs`, { + body: { sha, ref: `refs/heads/${branchName}` }, + }); +} + // Returns the Pull Request for a branch. Null if not exists. export async function getBranchPr(branchName: string): Promise<GhPr | null> { logger.debug(`getBranchPr(${branchName})`); @@ -776,9 +799,7 @@ export async function getBranchPr(branchName: string): Promise<GhPr | null> { } const { sha, number } = autoclosedPr; try { - await githubApi.postJson(`repos/${config.repository}/git/refs`, { - body: { ref: `refs/heads/${branchName}`, sha }, - }); + await ensureBranchSha(branchName, sha!); logger.debug(`Recreated autoclosed branch ${branchName} with sha ${sha}`); } catch (err) { logger.debug('Could not recreate autoclosed branch - skipping reopen'); @@ -1794,21 +1815,7 @@ async function pushFiles( { body: { message, tree: treeSha, parents: [parentCommitSha] } } ); const remoteCommitSha = commitRes.body.sha; - - // Create branch if it didn't already exist, update it otherwise - if (git.branchExists(branchName)) { - // This is the equivalent of a git force push - // We are using this REST API because the GraphQL API doesn't support force push - await githubApi.patchJson( - `/repos/${config.repository}/git/refs/heads/${branchName}`, - { body: { sha: remoteCommitSha, force: true } } - ); - } else { - await githubApi.postJson(`/repos/${config.repository}/git/refs`, { - body: { ref: `refs/heads/${branchName}`, sha: remoteCommitSha }, - }); - } - + await ensureBranchSha(branchName, remoteCommitSha); return remoteCommitSha; } catch (err) { logger.debug({ branchName, err }, 'Platform-native commit: unknown error'); -- GitLab