From 062045168a1c3d7ff18f2c61e4ae95b13afa8e56 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Mon, 17 Aug 2020 13:31:53 +0200 Subject: [PATCH] refactor(git): lazy sync git (#6984) Co-authored-by: Jamie Magee <JamieMagee@users.noreply.github.com> --- lib/platform/azure/index.ts | 2 +- lib/platform/bitbucket-server/index.ts | 2 +- lib/platform/bitbucket/index.ts | 2 +- lib/platform/gitea/index.ts | 2 +- lib/platform/github/index.ts | 2 +- lib/platform/gitlab/index.ts | 2 +- lib/util/git/index.spec.ts | 15 ++++--- lib/util/git/index.ts | 55 ++++++++++++++++++-------- 8 files changed, 53 insertions(+), 29 deletions(-) diff --git a/lib/platform/azure/index.ts b/lib/platform/azure/index.ts index 51040110fb..7f9b5c42d4 100644 --- a/lib/platform/azure/index.ts +++ b/lib/platform/azure/index.ts @@ -150,7 +150,7 @@ export async function initRepo({ const url = defaults.endpoint + `${encodeURIComponent(projectName)}/_git/${encodeURIComponent(repoName)}`; - await git.initRepo({ + git.initRepo({ ...config, localDir, url, diff --git a/lib/platform/bitbucket-server/index.ts b/lib/platform/bitbucket-server/index.ts index f2a7ab70d6..f3ff7b8669 100644 --- a/lib/platform/bitbucket-server/index.ts +++ b/lib/platform/bitbucket-server/index.ts @@ -179,7 +179,7 @@ export async function initRepo({ repository, }); - await git.initRepo({ + git.initRepo({ ...config, localDir, url: gitUrl, diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts index 53b0cd12a2..30ad14f102 100644 --- a/lib/platform/bitbucket/index.ts +++ b/lib/platform/bitbucket/index.ts @@ -153,7 +153,7 @@ export async function initRepo({ repository, }); - await git.initRepo({ + git.initRepo({ ...config, localDir, url, diff --git a/lib/platform/gitea/index.ts b/lib/platform/gitea/index.ts index 081d1f2005..fa4ab36f41 100644 --- a/lib/platform/gitea/index.ts +++ b/lib/platform/gitea/index.ts @@ -306,7 +306,7 @@ const platform: Platform = { gitEndpoint.auth = opts.token; // Initialize Git storage - await git.initRepo({ + git.initRepo({ ...config, url: URL.format(gitEndpoint), gitAuthorName: global.gitAuthor?.name, diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index 09bb5a4af5..7d1ce6d5fe 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -413,7 +413,7 @@ export async function initRepo({ ); parsedEndpoint.pathname = config.repository + '.git'; const url = URL.format(parsedEndpoint); - await git.initRepo({ + git.initRepo({ ...config, url, gitAuthorName: global.gitAuthor?.name, diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts index 518cf5b3c0..19e511d6de 100644 --- a/lib/platform/gitlab/index.ts +++ b/lib/platform/gitlab/index.ts @@ -224,7 +224,7 @@ export async function initRepo({ repoUrl.auth = 'oauth2:' + opts.token; url = URL.format(repoUrl); } - await git.initRepo({ + git.initRepo({ ...config, url, gitAuthorName: global.gitAuthor?.name, diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts index 0a344739a7..4e31c3a315 100644 --- a/lib/util/git/index.spec.ts +++ b/lib/util/git/index.spec.ts @@ -60,7 +60,7 @@ describe('platform/git', () => { const repo = Git(origin.path); await repo.clone(base.path, '.', ['--bare']); tmpDir = await tmp.dir({ unsafeCleanup: true }); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: origin.path, extraCloneOpts: { @@ -100,10 +100,11 @@ describe('platform/git', () => { const repo = Git(base.path).silent(true); await repo.submoduleAdd(base.path, 'submodule'); await repo.commit('Add submodule'); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: base.path, }); + await git.syncGit(); expect(await fs.exists(tmpDir.path + '/.gitmodules')).toBeTruthy(); expect(await git.getFileList()).toMatchSnapshot(); await repo.reset(['--hard', 'HEAD^']); @@ -129,6 +130,7 @@ describe('platform/git', () => { }); describe('isBranchStale()', () => { beforeEach(async () => { + await git.syncGit(); await git.setBranch('master'); }); it('should return false if same SHA as master', async () => { @@ -369,7 +371,7 @@ describe('platform/git', () => { await git.setBranch('develop'); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: base.path, }); @@ -391,7 +393,7 @@ describe('platform/git', () => { await repo.commit('past message2'); await repo.checkout('master'); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: base.path, }); @@ -400,7 +402,7 @@ describe('platform/git', () => { expect(await git.branchExists('renovate/test')).toBe(true); const cid = await git.getBranchCommit('renovate/test'); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: base.path, }); @@ -429,10 +431,11 @@ describe('platform/git', () => { 'test', ]); await repo.commit('Add submodule'); - await git.initRepo({ + git.initRepo({ localDir: tmpDir.path, url: base.path, }); + await git.syncGit(); expect(await fs.exists(tmpDir.path + '/.gitmodules')).toBeTruthy(); await repo.reset(['--hard', 'HEAD^']); }); diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index 3dafd524c7..a2eb0bc6b1 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -114,6 +114,13 @@ let git: SimpleGit | undefined; let privateKeySet = false; +export function initRepo(args: StorageConfig): void { + config = { ...args } as any; + config.branchExists = {}; + config.branchIsModified = {}; + git = undefined; +} + async function resetToBranch(branchName: string): Promise<void> { logger.debug(`resetToBranch(${branchName})`); await git.raw(['reset', '--hard']); @@ -143,14 +150,17 @@ async function cleanLocalBranches(): Promise<void> { * By calling this function once the repo's branchPrefix is known, we can fetch all of Renovate's branches in one command. */ export async function setBranchPrefix(branchPrefix: string): Promise<void> { - logger.debug('Setting branchPrefix: ' + branchPrefix); config.branchPrefix = branchPrefix; - const ref = `refs/heads/${branchPrefix}*:refs/remotes/origin/${branchPrefix}*`; - try { - await git.fetch(['origin', ref, '--depth=2', '--force']); - } catch (err) /* istanbul ignore next */ { - checkForPlatformFailure(err); - throw err; + // If the repo is already cloned then set branchPrefix now, otherwise it will be called again during syncGit() + if (git) { + logger.debug('Setting branchPrefix: ' + branchPrefix); + const ref = `refs/heads/${branchPrefix}*:refs/remotes/origin/${branchPrefix}*`; + try { + await git.fetch(['origin', ref, '--depth=2', '--force']); + } catch (err) /* istanbul ignore next */ { + checkForPlatformFailure(err); + throw err; + } } } @@ -258,20 +268,15 @@ export async function syncGit(): Promise<void> { logger.debug({ err }, 'Error setting git author config'); throw new Error(REPOSITORY_TEMPORARY_ERROR); } - config.currentBranch = config.currentBranch || (await getDefaultBranch(git)); -} - -export async function initRepo(args: StorageConfig): Promise<void> { - config = { ...args } as any; - config.branchExists = {}; - config.branchIsModified = {}; - git = undefined; - await syncGit(); + if (config.branchPrefix) { + await setBranchPrefix(config.branchPrefix); + } } // istanbul ignore next -export function getRepoStatus(): Promise<StatusResult> { +export async function getRepoStatus(): Promise<StatusResult> { + await syncGit(); return git.status(); } @@ -279,6 +284,7 @@ export async function createBranch( branchName: string, sha: string ): Promise<void> { + await syncGit(); logger.debug(`createBranch(${branchName})`); await git.reset(ResetMode.HARD); await git.raw(['clean', '-fd']); @@ -289,6 +295,7 @@ export async function createBranch( } export async function branchExists(branchName: string): Promise<boolean> { + await syncGit(); // First check cache if (config.branchExists[branchName] !== undefined) { return config.branchExists[branchName]; @@ -315,6 +322,7 @@ export async function branchExists(branchName: string): Promise<boolean> { // Return the commit SHA for a branch export async function getBranchCommit(branchName: string): Promise<string> { + await syncGit(); if (!(await branchExists(branchName))) { throw Error( 'Cannot fetch commit for branch that does not exist: ' + branchName @@ -325,6 +333,7 @@ export async function getBranchCommit(branchName: string): Promise<string> { } export async function getCommitMessages(): Promise<string[]> { + await syncGit(); logger.debug('getCommitMessages'); const res = await git.log({ n: 10, @@ -334,6 +343,7 @@ export async function getCommitMessages(): Promise<string[]> { } export async function setBranch(branchName: string): Promise<string> { + await syncGit(); if (!(await branchExists(branchName))) { throwBranchValidationError(branchName); } @@ -365,6 +375,7 @@ export async function setBranch(branchName: string): Promise<string> { } export async function getFileList(): Promise<string[]> { + await syncGit(); const branch = config.currentBranch; const submodules = await getSubmodules(); const files: string = await git.raw(['ls-tree', '-r', branch]); @@ -385,6 +396,7 @@ export async function getFileList(): Promise<string[]> { export async function getAllRenovateBranches( branchPrefix: string ): Promise<string[]> { + await syncGit(); const branches = await git.branch(['--remotes', '--verbose']); return branches.all .map(localName) @@ -392,6 +404,7 @@ export async function getAllRenovateBranches( } export async function isBranchStale(branchName: string): Promise<boolean> { + await syncGit(); if (!(await branchExists(branchName))) { throw Error( 'Cannot check staleness for branch that does not exist: ' + branchName @@ -407,6 +420,7 @@ export async function isBranchStale(branchName: string): Promise<boolean> { } export async function isBranchModified(branchName: string): Promise<boolean> { + await syncGit(); // First check cache if (config.branchIsModified[branchName] !== undefined) { return config.branchIsModified[branchName]; @@ -438,6 +452,7 @@ export async function isBranchModified(branchName: string): Promise<boolean> { } export async function deleteBranch(branchName: string): Promise<void> { + await syncGit(); try { await git.raw(['push', '--delete', 'origin', branchName]); logger.debug({ branchName }, 'Deleted remote branch'); @@ -457,6 +472,7 @@ export async function deleteBranch(branchName: string): Promise<void> { } export async function mergeBranch(branchName: string): Promise<void> { + await syncGit(); await git.reset(ResetMode.HARD); await git.checkout(['-B', branchName, 'origin/' + branchName]); await git.checkout(config.currentBranch); @@ -468,6 +484,7 @@ export async function mergeBranch(branchName: string): Promise<void> { export async function getBranchLastCommitTime( branchName: string ): Promise<Date> { + await syncGit(); try { const time = await git.show(['-s', '--format=%ai', 'origin/' + branchName]); return new Date(Date.parse(time)); @@ -478,6 +495,7 @@ export async function getBranchLastCommitTime( } export async function getBranchFiles(branchName: string): Promise<string[]> { + await syncGit(); try { const diff = await git.diffSummary([branchName, config.currentBranch]); return diff.files.map((file) => file.file); @@ -491,6 +509,7 @@ export async function getFile( filePath: string, branchName?: string ): Promise<string | null> { + await syncGit(); if (branchName) { const exists = await branchExists(branchName); if (!exists) { @@ -510,6 +529,7 @@ export async function getFile( } export async function hasDiff(branchName: string): Promise<boolean> { + await syncGit(); try { return (await git.diff(['HEAD', branchName])) !== ''; } catch (err) { @@ -545,6 +565,7 @@ export async function commitFiles({ message, force = false, }: CommitFilesConfig): Promise<string | null> { + await syncGit(); logger.debug(`Committing files to branch ${branchName}`); if (!privateKeySet) { await writePrivateKey(config.localDir); -- GitLab