diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap index b6cc064b626438..dba7b4034e7d56 100644 --- a/lib/platform/github/__snapshots__/index.spec.ts.snap +++ b/lib/platform/github/__snapshots__/index.spec.ts.snap @@ -4119,6 +4119,23 @@ Array [ "method": "POST", "url": "https://api.github.com/repos/some/repo/forks", }, + Object { + "body": Object { + "force": true, + "sha": "1234", + }, + "headers": Object { + "accept": "application/vnd.github.v3+json", + "accept-encoding": "gzip, deflate, br", + "authorization": "token 123test", + "content-length": "27", + "content-type": "application/json", + "host": "api.github.com", + "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", + }, + "method": "PATCH", + "url": "https://api.github.com/repos/forked/repo/git/refs/heads/master", + }, Object { "headers": Object { "accept": "application/vnd.github.v3+json", @@ -7384,6 +7401,23 @@ Array [ "method": "PATCH", "url": "https://api.github.com/repos/forked/repo", }, + Object { + "body": Object { + "force": true, + "sha": "1234", + }, + "headers": Object { + "accept": "application/vnd.github.v3+json", + "accept-encoding": "gzip, deflate, br", + "authorization": "token 123test", + "content-length": "27", + "content-type": "application/json", + "host": "api.github.com", + "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", + }, + "method": "PATCH", + "url": "https://api.github.com/repos/forked/repo/git/refs/heads/master", + }, ] `; @@ -7870,6 +7904,23 @@ Array [ "method": "POST", "url": "https://api.github.com/repos/some/repo/forks", }, + Object { + "body": Object { + "force": true, + "sha": "1234", + }, + "headers": Object { + "accept": "application/vnd.github.v3+json", + "accept-encoding": "gzip, deflate, br", + "authorization": "token 123test", + "content-length": "27", + "content-type": "application/json", + "host": "api.github.com", + "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", + }, + "method": "PATCH", + "url": "https://api.github.com/repos/forked/repo/git/refs/heads/master", + }, ] `; diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts index a8b46b5199c3bd..7e5f0b3b104387 100644 --- a/lib/platform/github/index.spec.ts +++ b/lib/platform/github/index.spec.ts @@ -300,6 +300,7 @@ describe('platform/github/index', () => { it('should update fork when forkMode', async () => { const scope = httpMock.scope(githubApiHost); forkInitRepoMock(scope, 'some/repo', true); + scope.patch('/repos/forked/repo/git/refs/heads/master').reply(200); const config = await github.initRepo({ repository: 'some/repo', forkMode: true, @@ -312,6 +313,7 @@ describe('platform/github/index', () => { forkInitRepoMock(scope, 'some/repo', true, 'not_master'); scope.post('/repos/forked/repo/git/refs').reply(200); scope.patch('/repos/forked/repo').reply(200); + scope.patch('/repos/forked/repo/git/refs/heads/master').reply(200); const config = await github.initRepo({ repository: 'some/repo', forkMode: true, @@ -730,7 +732,9 @@ describe('platform/github/index', () => { }, head: { ref: 'somebranch', repo: { full_name: 'other/repo' } }, state: PrState.Open, - }); + }) + .patch('/repos/forked/repo/git/refs/heads/master') + .reply(200); await github.initRepo({ repository: 'some/repo', forkMode: true, diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index 761bb3e8d18e8a..496e3fcf447f91 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -422,11 +422,33 @@ export async function initRepo({ { repository_fork: config.repository }, 'Found existing fork' ); + // This is a lovely "hack" by GitHub that lets us force update our fork's default branch + // with the base commit from the parent repository + const url = `repos/${config.repository}/git/refs/heads/${config.defaultBranch}`; + const sha = repo.defaultBranchRef.target.oid; + try { + logger.debug( + `Updating forked repository default sha ${sha} to match upstream` + ); + await githubApi.patchJson(url, { + body: { + sha, + force: true, + }, + token: forkToken || opts.token, + }); + } catch (err) /* istanbul ignore next */ { + logger.warn( + { url, sha, err: err.err || err }, + 'Error updating fork from upstream - cannot continue' + ); + if (err instanceof ExternalHostError) { + throw err; + } + throw new ExternalHostError(err); + } } else { - logger.debug( - { repository_fork: config.repository }, - 'Created fork, waiting 30s' - ); + logger.debug({ repository_fork: config.repository }, 'Created fork'); existingRepos.push(config.repository); // Wait an arbitrary 30s to hopefully give GitHub enough time for forking to complete await delay(30000); @@ -451,15 +473,9 @@ export async function initRepo({ ); parsedEndpoint.pathname = config.repository + '.git'; const url = URL.format(parsedEndpoint); - let upstreamUrl: string; - if (forkMode) { - parsedEndpoint.pathname = config.parentRepo + '.git'; - upstreamUrl = URL.format(parsedEndpoint); - } await git.initRepo({ ...config, url, - upstreamUrl, }); const repoConfig: RepoResult = { defaultBranch: config.defaultBranch, diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 8ead25335092fd..54d8cbc62dc01f 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -121,10 +121,9 @@ export async function validateGitVersion(): Promise { return true; } -async function fetchBranchCommits(preferUpstream = true): Promise { +async function fetchBranchCommits(): Promise { config.branchCommits = {}; - const url = (preferUpstream && config.upstreamUrl) || config.url; - const opts = ['ls-remote', '--heads', url]; + const opts = ['ls-remote', '--heads', config.url]; if (config.extraCloneOpts) { Object.entries(config.extraCloneOpts).forEach((e) => opts.unshift(e[0], `${e[1]}`) @@ -314,6 +313,7 @@ export async function syncGit(): Promise { const durationMs = Math.round(Date.now() - cloneStart); logger.debug({ durationMs }, 'git clone completed'); } + config.currentBranchSha = (await git.raw(['rev-parse', 'HEAD'])).trim(); if (config.cloneSubmodules) { const submodules = await getSubmodules(); for (const submodule of submodules) { @@ -339,23 +339,6 @@ export async function syncGit(): Promise { logger.warn({ err }, 'Cannot retrieve latest commit'); } config.currentBranch = config.currentBranch || (await getDefaultBranch(git)); - // istanbul ignore if - if (config.upstreamUrl) { - logger.debug(`Resetting ${config.currentBranch} to upstream`); - await git.addRemote('upstream', config.upstreamUrl); - await git.fetch(['upstream']); - await resetToBranch(config.currentBranch); - const resetLog = await git.reset([ - '--hard', - `upstream/${config.currentBranch}`, - ]); - logger.debug({ resetLog }, 'git reset log'); - const pushLog = await git.push(['origin', config.currentBranch, '--force']); - logger.debug({ pushLog }, 'git push log'); - await fetchBranchCommits(false); - } - config.currentBranchSha = (await git.raw(['rev-parse', 'HEAD'])).trim(); - logger.debug(`Current branch SHA: ${config.currentBranchSha}`); } // istanbul ignore next @@ -408,10 +391,7 @@ export async function checkoutBranch(branchName: string): Promise { await git.checkout(['-f', branchName, '--']); const latestCommitDate = (await git.log({ n: 1 }))?.latest?.date; if (latestCommitDate) { - logger.debug( - { branchName, latestCommitDate, sha: config.currentBranchSha }, - 'latest commit' - ); + logger.debug({ branchName, latestCommitDate }, 'latest commit'); } await git.reset(ResetMode.HARD); return config.currentBranchSha; diff --git a/lib/util/git/types.ts b/lib/util/git/types.ts index 1b309f2d3697fb..d0f82cfcfda5ed 100644 --- a/lib/util/git/types.ts +++ b/lib/util/git/types.ts @@ -14,8 +14,6 @@ export type CommitSha = string; export interface StorageConfig { currentBranch?: string; url: string; - - upstreamUrl?: string; extraCloneOpts?: GitOptions; cloneSubmodules?: boolean; fullClone?: boolean;