diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 9fac0812ddfa151a89e582bc01b9c9eb185d10ff..91d35bc7177cf7368cd668bf1381aa4c7024faa0 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 7c9ac146a375bce2c1654bca45e52b1cc063a8cf..ffc5f1ab893144afd68eff0042fe78a670689002 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');