From 854d0a86e8fbd83b047f77a0b6e8a79b213e63d4 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Fri, 28 May 2021 12:36:53 +0200 Subject: [PATCH] feat(internal): use cache to delay git cloning (#10209) Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- lib/util/cache/repository/types.ts | 2 ++ .../init/__snapshots__/merge.spec.ts.snap | 7 +++++++ lib/workers/repository/init/merge.spec.ts | 8 +++++++ lib/workers/repository/init/merge.ts | 15 ++++++++++++- lib/workers/repository/init/semantic.spec.ts | 12 ++++++++++- lib/workers/repository/init/semantic.ts | 13 +++++++++--- .../repository/onboarding/branch/check.ts | 18 ++++++++++++++++ .../onboarding/branch/index.spec.ts | 21 +++++++++++++++++++ 8 files changed, 91 insertions(+), 5 deletions(-) diff --git a/lib/util/cache/repository/types.ts b/lib/util/cache/repository/types.ts index 3a7995b559..bca06bd77c 100644 --- a/lib/util/cache/repository/types.ts +++ b/lib/util/cache/repository/types.ts @@ -32,6 +32,8 @@ export interface BranchCache { } export interface Cache { + configFileName?: string; + semanticCommits?: 'enabled' | 'disabled'; branches?: BranchCache[]; repository?: string; revision?: number; diff --git a/lib/workers/repository/init/__snapshots__/merge.spec.ts.snap b/lib/workers/repository/init/__snapshots__/merge.spec.ts.snap index 9f136f5d06..42481bc0f3 100644 --- a/lib/workers/repository/init/__snapshots__/merge.spec.ts.snap +++ b/lib/workers/repository/init/__snapshots__/merge.spec.ts.snap @@ -21,6 +21,13 @@ Object { } `; +exports[`workers/repository/init/merge detectRepoFileConfig() finds .renovaterc.json 2`] = ` +Object { + "configFileName": ".renovaterc.json", + "configFileParsed": "{\\"something\\":\\"new\\"}", +} +`; + exports[`workers/repository/init/merge detectRepoFileConfig() finds and parse renovate.json5 1`] = ` Object { "configFileName": "renovate.json5", diff --git a/lib/workers/repository/init/merge.spec.ts b/lib/workers/repository/init/merge.spec.ts index e45fd77aca..b5e620a136 100644 --- a/lib/workers/repository/init/merge.spec.ts +++ b/lib/workers/repository/init/merge.spec.ts @@ -5,9 +5,11 @@ import { getName, git, mocked, + platform, } from '../../../../test/util'; import * as _migrateAndValidate from '../../../config/migrate-validate'; import * as _migrate from '../../../config/migration'; +import { initialize } from '../../../util/cache/repository'; import { checkForRepoConfigError, detectRepoFileConfig, @@ -33,6 +35,10 @@ jest.mock('../../../config/migrate-validate'); describe(getName(), () => { describe('detectRepoFileConfig()', () => { + beforeEach(async () => { + await initialize({}); + }); + it('returns config if not found', async () => { git.getFileList.mockResolvedValue(['package.json']); fs.readLocalFile.mockResolvedValue('{}'); @@ -87,6 +93,8 @@ describe(getName(), () => { it('finds .renovaterc.json', async () => { git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']); fs.readLocalFile.mockResolvedValue('{}'); + platform.getJsonFile.mockResolvedValueOnce('{"something":"new"}'); + expect(await detectRepoFileConfig()).toMatchSnapshot(); expect(await detectRepoFileConfig()).toMatchSnapshot(); }); }); diff --git a/lib/workers/repository/init/merge.ts b/lib/workers/repository/init/merge.ts index 08117020fe..79d029c8b1 100644 --- a/lib/workers/repository/init/merge.ts +++ b/lib/workers/repository/init/merge.ts @@ -15,12 +15,24 @@ import { } from '../../../constants/error-messages'; import * as npmApi from '../../../datasource/npm'; import { logger } from '../../../logger'; +import { platform } from '../../../platform'; +import { getCache } from '../../../util/cache/repository'; import { readLocalFile } from '../../../util/fs'; import { getFileList } from '../../../util/git'; import * as hostRules from '../../../util/host-rules'; import type { RepoFileConfig } from './types'; export async function detectRepoFileConfig(): Promise<RepoFileConfig> { + const cache = getCache(); + let { configFileName } = cache; + if (configFileName) { + const configFileParsed = await platform.getJsonFile(configFileName); + if (configFileParsed) { + logger.debug('Existing config file confirmed'); + return { configFileName, configFileParsed }; + } + logger.debug('Existing config file no longer exists'); + } const fileList = await getFileList(); async function detectConfigFile(): Promise<string | null> { for (const fileName of configFileNames) { @@ -40,11 +52,12 @@ export async function detectRepoFileConfig(): Promise<RepoFileConfig> { } return null; } - const configFileName = await detectConfigFile(); + configFileName = await detectConfigFile(); if (!configFileName) { logger.debug('No renovate config file found'); return {}; } + cache.configFileName = configFileName; logger.debug(`Found ${configFileName} config file`); let configFileParsed; if (configFileName === 'package.json') { diff --git a/lib/workers/repository/init/semantic.spec.ts b/lib/workers/repository/init/semantic.spec.ts index 1ac0f5a339..e3be88d5c7 100644 --- a/lib/workers/repository/init/semantic.spec.ts +++ b/lib/workers/repository/init/semantic.spec.ts @@ -1,4 +1,5 @@ import { RenovateConfig, getConfig, getName, git } from '../../../../test/util'; +import { initialize } from '../../../util/cache/repository'; import { detectSemanticCommits } from './semantic'; jest.mock('../../../util/git'); @@ -13,11 +14,20 @@ beforeEach(() => { describe(getName(), () => { describe('detectSemanticCommits()', () => { + beforeEach(async () => { + await initialize({}); + }); it('detects false if unknown', async () => { config.semanticCommits = null; - git.getCommitMessages.mockResolvedValue(['foo', 'bar']); + git.getCommitMessages.mockResolvedValueOnce(['foo', 'bar']); + git.getCommitMessages.mockResolvedValueOnce([ + 'fix: foo', + 'refactor: bar', + ]); const res = await detectSemanticCommits(); expect(res).toBe('disabled'); + const res2 = await detectSemanticCommits(); + expect(res2).toBe('disabled'); }); it('detects true if known', async () => { config.semanticCommits = null; diff --git a/lib/workers/repository/init/semantic.ts b/lib/workers/repository/init/semantic.ts index 62816e63e5..297fa13a65 100644 --- a/lib/workers/repository/init/semantic.ts +++ b/lib/workers/repository/init/semantic.ts @@ -1,19 +1,26 @@ import conventionalCommitsDetector from 'conventional-commits-detector'; import { logger } from '../../../logger'; +import { getCache } from '../../../util/cache/repository'; import { getCommitMessages } from '../../../util/git'; type DetectedSemanticCommit = 'enabled' | 'disabled'; export async function detectSemanticCommits(): Promise<DetectedSemanticCommit> { logger.debug('detectSemanticCommits()'); + const cache = getCache(); + if (cache.semanticCommits) { + return cache.semanticCommits; + } const commitMessages = await getCommitMessages(); logger.trace(`commitMessages=${JSON.stringify(commitMessages)}`); const type = conventionalCommitsDetector(commitMessages); logger.debug('Semantic commits detection: ' + type); if (type === 'angular') { logger.debug('angular semantic commits detected'); - return 'enabled'; + cache.semanticCommits = 'enabled'; + } else { + logger.debug('No semantic commits detected'); + cache.semanticCommits = 'disabled'; } - logger.debug('No semantic commits detected'); - return 'disabled'; + return cache.semanticCommits; } diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts index 9a2a436921..475f1e9bc9 100644 --- a/lib/workers/repository/onboarding/branch/check.ts +++ b/lib/workers/repository/onboarding/branch/check.ts @@ -7,6 +7,7 @@ import { import { logger } from '../../../../logger'; import { platform } from '../../../../platform'; import { PrState } from '../../../../types'; +import { getCache } from '../../../../util/cache/repository'; import { readLocalFile } from '../../../../util/fs'; import { getFileList } from '../../../../util/git'; @@ -57,6 +58,23 @@ export const isOnboarded = async (config: RenovateConfig): Promise<boolean> => { // Return early and avoid checking for config files return true; } + const cache = getCache(); + if (cache.configFileName) { + logger.debug('Checking cached config file name'); + try { + const configFileContent = await platform.getJsonFile( + cache.configFileName + ); + if (configFileContent) { + logger.debug('Existing config file confirmed'); + return true; + } + } catch (err) { + // probably file doesn't exist + } + logger.debug('Existing config file no longer exists'); + delete cache.configFileName; + } if (await configFileExists()) { await platform.ensureIssueClosing(title); return true; diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts index 10074a91a1..b7faee9dd8 100644 --- a/lib/workers/repository/onboarding/branch/index.spec.ts +++ b/lib/workers/repository/onboarding/branch/index.spec.ts @@ -5,6 +5,7 @@ import { getConfig, getName, git, + mocked, platform, } from '../../../../../test/util'; import { @@ -13,6 +14,7 @@ import { } from '../../../../constants/error-messages'; import { Pr } from '../../../../platform'; import { PrState } from '../../../../types'; +import * as _cache from '../../../../util/cache/repository'; import * as _config from './config'; import * as _rebase from './rebase'; import { checkOnboardingBranch } from '.'; @@ -21,10 +23,13 @@ const rebase: any = _rebase; const configModule: any = _config; jest.mock('../../../../workers/repository/onboarding/branch/rebase'); +jest.mock('../../../../util/cache/repository'); jest.mock('../../../../util/fs'); jest.mock('../../../../util/git'); jest.mock('./config'); +const cache = mocked(_cache); + describe(getName(), () => { describe('checkOnboardingBranch', () => { let config: RenovateConfig; @@ -33,6 +38,7 @@ describe(getName(), () => { config = getConfig(); config.repository = 'some/repo'; git.getFileList.mockResolvedValue([]); + cache.getCache.mockReturnValue({}); }); it('throws if no package files', async () => { await expect(checkOnboardingBranch(config)).rejects.toThrow( @@ -110,6 +116,21 @@ describe(getName(), () => { const res = await checkOnboardingBranch(config); expect(res.repoIsOnboarded).toBe(true); }); + + it('handles removed cached file name', async () => { + cache.getCache.mockReturnValue({ configFileName: '.renovaterc' }); + git.getFileList.mockResolvedValueOnce(['renovate.json']); + const res = await checkOnboardingBranch(config); + expect(res.repoIsOnboarded).toBe(true); + }); + + it('handles cached file name', async () => { + cache.getCache.mockReturnValue({ configFileName: '.renovaterc' }); + platform.getJsonFile.mockResolvedValueOnce({}); + const res = await checkOnboardingBranch(config); + expect(res.repoIsOnboarded).toBe(true); + }); + it('detects repo is onboarded via package.json config', async () => { git.getFileList.mockResolvedValueOnce(['package.json']); fs.readLocalFile.mockResolvedValueOnce('{"renovate":{}}'); -- GitLab