From e78048dfc1d0d5321fd338748ded9a5db7e02d30 Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Mon, 23 Jan 2023 22:20:54 +0100
Subject: [PATCH] fix: no cycles (#19982)

---
 .eslintrc.js                                  |   2 +
 lib/modules/manager/bazel/parser.spec.ts      |   3 +-
 lib/modules/manager/bazel/parser.ts           |  26 +---
 lib/modules/manager/bazel/rules/index.ts      |  18 ++-
 lib/modules/manager/gradle/artifacts.spec.ts  |   2 +-
 lib/modules/manager/gradle/artifacts.ts       |  11 +-
 lib/modules/manager/gradle/extract.spec.ts    |  16 +--
 lib/modules/manager/gradle/extract.ts         |   4 +-
 lib/modules/manager/gradle/parser.ts          |   3 +
 lib/modules/manager/gradle/parser/handlers.ts |   8 +-
 lib/modules/manager/nuget/artifacts.spec.ts   | 134 ++++++++----------
 lib/modules/manager/nuget/artifacts.ts        |   7 +-
 lib/util/fs/index.spec.ts                     |  20 +--
 lib/util/fs/index.ts                          |  10 +-
 lib/util/git/index.spec.ts                    |  10 ++
 lib/util/git/index.ts                         |  12 ++
 lib/util/string.ts                            |   3 -
 17 files changed, 142 insertions(+), 147 deletions(-)

diff --git a/.eslintrc.js b/.eslintrc.js
index 95517d09e2..259a035c36 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -41,6 +41,8 @@ module.exports = {
     ],
     'import/prefer-default-export': 0, // no benefit
 
+    'import/no-cycle': 2, // cycles don't work when moving to esm
+
     /*
      * This rule is not needed since the project uses typescript and the rule
      * `@typescript-eslint/explicit-function-return-type`.
diff --git a/lib/modules/manager/bazel/parser.spec.ts b/lib/modules/manager/bazel/parser.spec.ts
index d99cef0b22..42dc65c863 100644
--- a/lib/modules/manager/bazel/parser.spec.ts
+++ b/lib/modules/manager/bazel/parser.spec.ts
@@ -1,4 +1,5 @@
-import { extract, parse } from './parser';
+import { parse } from './parser';
+import { extract } from './rules';
 
 describe('modules/manager/bazel/parser', () => {
   it('parses rules input', () => {
diff --git a/lib/modules/manager/bazel/parser.ts b/lib/modules/manager/bazel/parser.ts
index 9b2a18d87b..776f38673d 100644
--- a/lib/modules/manager/bazel/parser.ts
+++ b/lib/modules/manager/bazel/parser.ts
@@ -2,13 +2,8 @@ import { lang, lexer, parser, query as q } from 'good-enough-parser';
 import hasha from 'hasha';
 import { logger } from '../../../logger';
 import * as memCache from '../../../util/cache/memory';
-import { supportedRulesRegex } from './rules/index';
-import type {
-  Fragment,
-  FragmentData,
-  NestedFragment,
-  RecordFragment,
-} from './types';
+import { supportedRulesRegex } from './rules';
+import type { NestedFragment, RecordFragment } from './types';
 
 interface Ctx {
   readonly source: string;
@@ -231,20 +226,3 @@ export function parse(
   memCache.set(cacheKey, result);
   return result;
 }
-
-export function extract(fragment: Fragment): FragmentData {
-  if (fragment.type === 'string') {
-    return fragment.value;
-  }
-
-  if (fragment.type === 'record') {
-    const { children } = fragment;
-    const result: Record<string, FragmentData> = {};
-    for (const [key, value] of Object.entries(children)) {
-      result[key] = extract(value);
-    }
-    return result;
-  }
-
-  return fragment.children.map(extract);
-}
diff --git a/lib/modules/manager/bazel/rules/index.ts b/lib/modules/manager/bazel/rules/index.ts
index 8296c4514d..deafa4d077 100644
--- a/lib/modules/manager/bazel/rules/index.ts
+++ b/lib/modules/manager/bazel/rules/index.ts
@@ -1,7 +1,6 @@
 import { z } from 'zod';
 import { regEx } from '../../../../util/regex';
 import type { PackageDependency } from '../../types';
-import { extract } from '../parser';
 import type { Fragment, FragmentData, Target } from '../types';
 import { DockerTarget, dockerRules } from './docker';
 import { GitTarget, gitRules } from './git';
@@ -33,3 +32,20 @@ export function extractDepFromFragment(
   const fragmentData = extract(fragment);
   return extractDepFromFragmentData(fragmentData);
 }
+
+export function extract(fragment: Fragment): FragmentData {
+  if (fragment.type === 'string') {
+    return fragment.value;
+  }
+
+  if (fragment.type === 'record') {
+    const { children } = fragment;
+    const result: Record<string, FragmentData> = {};
+    for (const [key, value] of Object.entries(children)) {
+      result[key] = extract(value);
+    }
+    return result;
+  }
+
+  return fragment.children.map(extract);
+}
diff --git a/lib/modules/manager/gradle/artifacts.spec.ts b/lib/modules/manager/gradle/artifacts.spec.ts
index f2856dc899..fffb4314e4 100644
--- a/lib/modules/manager/gradle/artifacts.spec.ts
+++ b/lib/modules/manager/gradle/artifacts.spec.ts
@@ -68,7 +68,7 @@ describe('modules/manager/gradle/artifacts', () => {
       'gradle.lockfile',
       'gradle/wrapper/gradle-wrapper.properties',
     ]);
-    fs.getFileContentMap.mockResolvedValue({
+    git.getFiles.mockResolvedValue({
       'gradle.lockfile': 'Current gradle.lockfile',
     });
     git.getRepoStatus.mockResolvedValue(
diff --git a/lib/modules/manager/gradle/artifacts.ts b/lib/modules/manager/gradle/artifacts.ts
index 8f7a384b7b..3247d4230d 100644
--- a/lib/modules/manager/gradle/artifacts.ts
+++ b/lib/modules/manager/gradle/artifacts.ts
@@ -5,13 +5,8 @@ import { TEMPORARY_ERROR } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
 import { exec } from '../../../util/exec';
 import type { ExecOptions } from '../../../util/exec/types';
-import {
-  findUpLocal,
-  getFileContentMap,
-  readLocalFile,
-  writeLocalFile,
-} from '../../../util/fs';
-import { getFileList, getRepoStatus } from '../../../util/git';
+import { findUpLocal, readLocalFile, writeLocalFile } from '../../../util/fs';
+import { getFileList, getFiles, getRepoStatus } from '../../../util/git';
 import { regEx } from '../../../util/regex';
 import {
   extraEnv,
@@ -128,7 +123,7 @@ export async function updateArtifacts({
   logger.debug('Updating found Gradle dependency lockfiles');
 
   try {
-    const oldLockFileContentMap = await getFileContentMap(lockFiles);
+    const oldLockFileContentMap = await getFiles(lockFiles);
 
     await writeLocalFile(packageFileName, newPackageFileContent);
     await prepareGradleCommand(gradlewFile);
diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts
index c63b0e3a66..2e8450d65d 100644
--- a/lib/modules/manager/gradle/extract.spec.ts
+++ b/lib/modules/manager/gradle/extract.spec.ts
@@ -9,16 +9,14 @@ jest.mock('../../../util/fs');
 
 function mockFs(files: Record<string, string>): void {
   // TODO: fix types, jest is using wrong overload (#7154)
-  fs.getFileContentMap.mockImplementation(
-    (fileNames: string[]): Promise<any> => {
-      const fileContentMap: Record<string, string | null> = {};
-      for (const fileName of fileNames) {
-        fileContentMap[fileName] = files?.[fileName];
-      }
-
-      return Promise.resolve(fileContentMap);
+  fs.getLocalFiles.mockImplementation((fileNames: string[]): Promise<any> => {
+    const fileContentMap: Record<string, string | null> = {};
+    for (const fileName of fileNames) {
+      fileContentMap[fileName] = files?.[fileName];
     }
-  );
+
+    return Promise.resolve(fileContentMap);
+  });
 
   fs.getSiblingFileName.mockImplementation(
     (existingFileNameWithPath: string, otherFileName: string) => {
diff --git a/lib/modules/manager/gradle/extract.ts b/lib/modules/manager/gradle/extract.ts
index 7053716f06..8d2f78ff14 100644
--- a/lib/modules/manager/gradle/extract.ts
+++ b/lib/modules/manager/gradle/extract.ts
@@ -1,6 +1,6 @@
 import upath from 'upath';
 import { logger } from '../../../logger';
-import { getFileContentMap } from '../../../util/fs';
+import { getLocalFiles } from '../../../util/fs';
 import { MavenDatasource } from '../../datasource/maven';
 import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
 import { parseCatalog } from './extract/catalog';
@@ -54,7 +54,7 @@ export async function extractAllPackageFiles(
   const packageFilesByName: Record<string, PackageFile> = {};
   const packageRegistries: PackageRegistry[] = [];
   const reorderedFiles = reorderFiles(packageFiles);
-  const fileContents = await getFileContentMap(packageFiles, true);
+  const fileContents = await getLocalFiles(packageFiles);
 
   for (const packageFile of reorderedFiles) {
     packageFilesByName[packageFile] = {
diff --git a/lib/modules/manager/gradle/parser.ts b/lib/modules/manager/gradle/parser.ts
index 44fd6066b4..02a788145d 100644
--- a/lib/modules/manager/gradle/parser.ts
+++ b/lib/modules/manager/gradle/parser.ts
@@ -4,6 +4,7 @@ import type { PackageDependency } from '../types';
 import { qApplyFrom } from './parser/apply-from';
 import { qAssignments } from './parser/assignments';
 import { qDependencies, qLongFormDep } from './parser/dependencies';
+import { setParseGradleFunc } from './parser/handlers';
 import { qPlugins } from './parser/plugins';
 import { qRegistryUrls } from './parser/registry-urls';
 import { qVersionCatalogs } from './parser/version-catalogs';
@@ -18,6 +19,8 @@ import { isDependencyString, parseDependencyString } from './utils';
 
 const groovy = lang.createLang('groovy');
 
+setParseGradleFunc(parseGradle);
+
 export function parseGradle(
   input: string,
   initVars: PackageVariables = {},
diff --git a/lib/modules/manager/gradle/parser/handlers.ts b/lib/modules/manager/gradle/parser/handlers.ts
index 8e2044bb4a..9ab3f4dd9a 100644
--- a/lib/modules/manager/gradle/parser/handlers.ts
+++ b/lib/modules/manager/gradle/parser/handlers.ts
@@ -4,7 +4,7 @@ import { logger } from '../../../../logger';
 import { getSiblingFileName } from '../../../../util/fs';
 import { regEx } from '../../../../util/regex';
 import type { PackageDependency } from '../../types';
-import { parseGradle } from '../parser';
+import type { parseGradle as parseGradleCallback } from '../parser';
 import type { Ctx, GradleManagerData } from '../types';
 import { parseDependencyString } from '../utils';
 import {
@@ -15,6 +15,12 @@ import {
   loadFromTokenMap,
 } from './common';
 
+// needed to break circular dependency
+let parseGradle: typeof parseGradleCallback;
+export function setParseGradleFunc(func: typeof parseGradleCallback): void {
+  parseGradle = func;
+}
+
 export function handleAssignment(ctx: Ctx): Ctx {
   const key = loadFromTokenMap(ctx, 'keyToken')[0].value;
   const valTokens = loadFromTokenMap(ctx, 'valToken');
diff --git a/lib/modules/manager/nuget/artifacts.spec.ts b/lib/modules/manager/nuget/artifacts.spec.ts
index 7ed9178d22..aa22079b09 100644
--- a/lib/modules/manager/nuget/artifacts.spec.ts
+++ b/lib/modules/manager/nuget/artifacts.spec.ts
@@ -51,7 +51,7 @@ describe('modules/manager/nuget/artifacts', () => {
   it('aborts if no lock file found', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap.mockResolvedValueOnce({ 'packages.lock.json': null });
+    git.getFiles.mockResolvedValueOnce({ 'packages.lock.json': null });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -68,13 +68,12 @@ describe('modules/manager/nuget/artifacts', () => {
     fs.getSiblingFileName.mockReturnValueOnce(
       'path/with space/packages.lock.json'
     );
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'path/with space/packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'path/with space/packages.lock.json': 'Current packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'path/with space/packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'path/with space/packages.lock.json': 'Current packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'path/with space/project.csproj',
@@ -101,13 +100,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('updates lock file', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -142,13 +140,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('does not update lock file when non-proj file is changed', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'otherfile.props',
@@ -163,13 +160,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('does not update lock file when no deps changed', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -184,13 +180,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('performs lock file maintenance', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -229,13 +224,12 @@ describe('modules/manager/nuget/artifacts', () => {
     GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -292,13 +286,12 @@ describe('modules/manager/nuget/artifacts', () => {
     GlobalConfig.set({ ...adminConfig, binarySource: 'install' });
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -349,13 +342,12 @@ describe('modules/manager/nuget/artifacts', () => {
     GlobalConfig.set({ ...adminConfig, binarySource: 'global' });
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     expect(
       await nuget.updateArtifacts({
         packageFileName: 'project.csproj',
@@ -390,7 +382,7 @@ describe('modules/manager/nuget/artifacts', () => {
   it('catches errors', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap.mockResolvedValueOnce({
+    git.getFiles.mockResolvedValueOnce({
       'packages.lock.json': 'Current packages.lock.json',
     });
     fs.writeLocalFile.mockImplementationOnce(() => {
@@ -417,13 +409,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('authenticates at registries', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     getConfiguredRegistries.mockResolvedValueOnce([
       {
         name: 'myRegistry',
@@ -473,13 +464,12 @@ describe('modules/manager/nuget/artifacts', () => {
   it('strips protocol version from feed url', async () => {
     const execSnapshots = mockExecAll();
     fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
-    fs.getFileContentMap
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'Current packages.lock.json',
-      })
-      .mockResolvedValueOnce({
-        'packages.lock.json': 'New packages.lock.json',
-      });
+    git.getFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'Current packages.lock.json',
+    });
+    fs.getLocalFiles.mockResolvedValueOnce({
+      'packages.lock.json': 'New packages.lock.json',
+    });
     getConfiguredRegistries.mockResolvedValueOnce([
       {
         name: 'myRegistry',
diff --git a/lib/modules/manager/nuget/artifacts.ts b/lib/modules/manager/nuget/artifacts.ts
index aec59e1d7b..2d2f4e1a6a 100644
--- a/lib/modules/manager/nuget/artifacts.ts
+++ b/lib/modules/manager/nuget/artifacts.ts
@@ -6,12 +6,13 @@ import { exec } from '../../../util/exec';
 import type { ExecOptions } from '../../../util/exec/types';
 import {
   ensureDir,
-  getFileContentMap,
+  getLocalFiles,
   getSiblingFileName,
   outputCacheFile,
   privateCacheDir,
   writeLocalFile,
 } from '../../../util/fs';
+import { getFiles } from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { regEx } from '../../../util/regex';
 import { NugetDatasource } from '../../datasource/nuget';
@@ -145,7 +146,7 @@ export async function updateArtifacts({
     getSiblingFileName(f.name, 'packages.lock.json')
   );
 
-  const existingLockFileContentMap = await getFileContentMap(lockFileNames);
+  const existingLockFileContentMap = await getFiles(lockFileNames);
 
   const hasLockFileContent = Object.values(existingLockFileContentMap).some(
     (val) => !!val
@@ -170,7 +171,7 @@ export async function updateArtifacts({
 
     await runDotnetRestore(packageFileName, packageFiles, config);
 
-    const newLockFileContentMap = await getFileContentMap(lockFileNames, true);
+    const newLockFileContentMap = await getLocalFiles(lockFileNames);
 
     const retArray: UpdateArtifactsResult[] = [];
     for (const lockFileName of lockFileNames) {
diff --git a/lib/util/fs/index.spec.ts b/lib/util/fs/index.spec.ts
index 2594f7e024..2e0af88fe0 100644
--- a/lib/util/fs/index.spec.ts
+++ b/lib/util/fs/index.spec.ts
@@ -2,7 +2,7 @@ import _findUp from 'find-up';
 import fs from 'fs-extra';
 import tmp, { DirectoryResult } from 'tmp-promise';
 import { join, resolve } from 'upath';
-import { git, mockedFunction } from '../../../test/util';
+import { mockedFunction } from '../../../test/util';
 import { GlobalConfig } from '../../config/global';
 import {
   cachePathExists,
@@ -14,7 +14,7 @@ import {
   ensureLocalDir,
   findLocalSiblingOrParent,
   findUpLocal,
-  getFileContentMap,
+  getLocalFiles,
   getParentDir,
   getSiblingFileName,
   listCacheDir,
@@ -464,7 +464,7 @@ describe('util/fs/index', () => {
     });
   });
 
-  describe('getFileContentMap', () => {
+  describe('getLocalFiles', () => {
     it('reads list of files from local fs', async () => {
       const fileContentMap = {
         file1: 'foobar',
@@ -473,22 +473,12 @@ describe('util/fs/index', () => {
 
       await fs.outputFile(`${localDir}/file1`, fileContentMap.file1);
       await fs.outputFile(`${localDir}/file2`, fileContentMap.file2);
-      const res = await getFileContentMap(Object.keys(fileContentMap), true);
-      expect(res).toStrictEqual(fileContentMap);
-    });
-
-    it('reads list of files from git', async () => {
-      const fileContentMap = {
-        file1: 'foobar',
-      };
-
-      git.getFile.mockResolvedValueOnce('foobar');
-      const res = await getFileContentMap(Object.keys(fileContentMap));
+      const res = await getLocalFiles(Object.keys(fileContentMap));
       expect(res).toStrictEqual(fileContentMap);
     });
 
     it('returns null as content if file is not found', async () => {
-      const res = await getFileContentMap(['invalidfile'], true);
+      const res = await getLocalFiles(['invalidfile']);
       expect(res).toStrictEqual({
         invalidfile: null,
       });
diff --git a/lib/util/fs/index.ts b/lib/util/fs/index.ts
index ae659c8324..68c16d04e1 100644
--- a/lib/util/fs/index.ts
+++ b/lib/util/fs/index.ts
@@ -6,7 +6,6 @@ import fs from 'fs-extra';
 import upath from 'upath';
 import { GlobalConfig } from '../../config/global';
 import { logger } from '../../logger';
-import { getFile } from '../git';
 import { ensureCachePath, ensureLocalPath } from './util';
 
 export const pipeline = util.promisify(stream.pipeline);
@@ -287,16 +286,13 @@ export function readSystemFile(
   return encoding ? fs.readFile(fileName, encoding) : fs.readFile(fileName);
 }
 
-export async function getFileContentMap(
-  fileNames: string[],
-  local = false
+export async function getLocalFiles(
+  fileNames: string[]
 ): Promise<Record<string, string | null>> {
   const fileContentMap: Record<string, string | null> = {};
 
   for (const fileName of fileNames) {
-    fileContentMap[fileName] = local
-      ? await readLocalFile(fileName, 'utf8')
-      : await getFile(fileName);
+    fileContentMap[fileName] = await readLocalFile(fileName, 'utf8');
   }
 
   return fileContentMap;
diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts
index 459e4b9944..239bb5b39f 100644
--- a/lib/util/git/index.spec.ts
+++ b/lib/util/git/index.spec.ts
@@ -385,6 +385,16 @@ describe('util/git/index', () => {
     });
   });
 
+  describe('getFiles(filePath)', () => {
+    it('gets the file', async () => {
+      const res = await git.getFiles(['master_file', 'some_missing_path']);
+      expect(res).toEqual({
+        master_file: defaultBranch,
+        some_missing_path: null,
+      });
+    });
+  });
+
   describe('hasDiff(sourceRef, targetRef)', () => {
     it('compare without changes', () => {
       return expect(git.hasDiff('HEAD', 'HEAD')).resolves.toBeFalse();
diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 365b2beaed..d74941ecea 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -857,6 +857,18 @@ export async function getFile(
   }
 }
 
+export async function getFiles(
+  fileNames: string[]
+): Promise<Record<string, string | null>> {
+  const fileContentMap: Record<string, string | null> = {};
+
+  for (const fileName of fileNames) {
+    fileContentMap[fileName] = await getFile(fileName);
+  }
+
+  return fileContentMap;
+}
+
 export async function hasDiff(
   sourceRef: string,
   targetRef: string
diff --git a/lib/util/string.ts b/lib/util/string.ts
index 2ef7ae661d..4030956cdd 100644
--- a/lib/util/string.ts
+++ b/lib/util/string.ts
@@ -1,5 +1,3 @@
-import { logger } from '../logger';
-
 // Return true if the match string is found at index in content
 export function matchAt(
   content: string,
@@ -16,7 +14,6 @@ export function replaceAt(
   oldString: string,
   newString: string
 ): string {
-  logger.trace(`Replacing ${oldString} with ${newString} at index ${index}`);
   return (
     content.substring(0, index) +
     newString +
-- 
GitLab