diff --git a/lib/manager/bundler/artifacts.spec.ts b/lib/manager/bundler/artifacts.spec.ts
index e1dcc4b370b7e44be663f88c0a453d6c4c8a8937..d5691118b641e7f13f9d5e9f122d058bab01e7de 100644
--- a/lib/manager/bundler/artifacts.spec.ts
+++ b/lib/manager/bundler/artifacts.spec.ts
@@ -1,5 +1,4 @@
 import { exec as _exec } from 'child_process';
-import _fs from 'fs-extra';
 import Git from 'simple-git/promise';
 import { join } from 'upath';
 import { envMock, mockExecAll } from '../../../test/execUtil';
@@ -10,6 +9,7 @@ import { setUtilConfig } from '../../util';
 import { BinarySource } from '../../util/exec/common';
 import { resetPrefetchedImages } from '../../util/exec/docker';
 import * as _env from '../../util/exec/env';
+import * as _fs from '../../util/fs';
 import * as _bundlerHostRules from './host-rules';
 import { updateArtifacts } from '.';
 
@@ -25,6 +25,7 @@ jest.mock('child_process');
 jest.mock('../../../lib/util/exec/env');
 jest.mock('../../../lib/platform');
 jest.mock('../../../lib/datasource/docker');
+jest.mock('../../../lib/util/fs');
 jest.mock('../../../lib/util/host-rules');
 jest.mock('./host-rules');
 jest.mock('../../util/exec/docker/index', () =>
@@ -63,13 +64,13 @@ describe('bundler.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if Gemfile.lock was not changed', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-    fs.outputFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+    fs.writeLocalFile.mockResolvedValueOnce(null as never);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: [],
     } as Git.StatusResult);
-    fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+    fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
     expect(
       await updateArtifacts({
         packageFileName: 'Gemfile',
@@ -81,13 +82,14 @@ describe('bundler.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('works for default binarySource', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-    fs.outputFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+    fs.writeLocalFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce(null);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
     } as Git.StatusResult);
-    fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+    fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
     expect(
       await updateArtifacts({
         packageFileName: 'Gemfile',
@@ -99,13 +101,14 @@ describe('bundler.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('works explicit global binarySource', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-    fs.outputFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+    fs.writeLocalFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce(null);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
     } as Git.StatusResult);
-    fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+    fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
     expect(
       await updateArtifacts({
         packageFileName: 'Gemfile',
@@ -124,9 +127,9 @@ describe('bundler.updateArtifacts()', () => {
       await setUtilConfig({ ...config, binarySource: BinarySource.Docker });
     });
     it('.ruby-version', async () => {
-      platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-      fs.outputFile.mockResolvedValueOnce(null as never);
-      platform.getFile.mockResolvedValueOnce('1.2.0');
+      fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+      fs.writeLocalFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce('1.2.0');
       datasource.getReleases.mockResolvedValueOnce({
         releases: [
           { version: '1.0.0' },
@@ -138,7 +141,7 @@ describe('bundler.updateArtifacts()', () => {
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
       } as Git.StatusResult);
-      fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+      fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
       expect(
         await updateArtifacts({
           packageFileName: 'Gemfile',
@@ -153,8 +156,8 @@ describe('bundler.updateArtifacts()', () => {
       expect(execSnapshots).toMatchSnapshot();
     });
     it('compatibility options', async () => {
-      platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-      fs.outputFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+      fs.writeLocalFile.mockResolvedValueOnce(null as never);
       datasource.getReleases.mockResolvedValueOnce({
         releases: [
           { version: '1.0.0' },
@@ -166,7 +169,7 @@ describe('bundler.updateArtifacts()', () => {
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
       } as Git.StatusResult);
-      fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+      fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
       expect(
         await updateArtifacts({
           packageFileName: 'Gemfile',
@@ -186,8 +189,8 @@ describe('bundler.updateArtifacts()', () => {
       expect(execSnapshots).toMatchSnapshot();
     });
     it('invalid compatibility options', async () => {
-      platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-      fs.outputFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+      fs.writeLocalFile.mockResolvedValueOnce(null as never);
       datasource.getReleases.mockResolvedValueOnce({
         releases: [
           { version: '1.0.0' },
@@ -199,7 +202,7 @@ describe('bundler.updateArtifacts()', () => {
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
       } as Git.StatusResult);
-      fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+      fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
       expect(
         await updateArtifacts({
           packageFileName: 'Gemfile',
@@ -220,9 +223,9 @@ describe('bundler.updateArtifacts()', () => {
     });
 
     it('injects bundler host configuration environment variables', async () => {
-      platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-      fs.outputFile.mockResolvedValueOnce(null as never);
-      platform.getFile.mockResolvedValueOnce('1.2.0');
+      fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+      fs.writeLocalFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce('1.2.0');
       datasource.getReleases.mockResolvedValueOnce({
         releases: [
           { version: '1.0.0' },
@@ -246,7 +249,7 @@ describe('bundler.updateArtifacts()', () => {
       platform.getRepoStatus.mockResolvedValueOnce({
         modified: ['Gemfile.lock'],
       } as Git.StatusResult);
-      fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+      fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
       expect(
         await updateArtifacts({
           packageFileName: 'Gemfile',
@@ -265,8 +268,8 @@ describe('bundler.updateArtifacts()', () => {
     const execError = new Error();
     (execError as any).stdout = ' foo was resolved to';
     (execError as any).stderr = '';
-    platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-    fs.outputFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+    fs.writeLocalFile.mockResolvedValueOnce(null as never);
     const execSnapshots = mockExecAll(exec, execError);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
@@ -285,13 +288,13 @@ describe('bundler.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('performs lockFileMaintenance', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Gemfile.lock');
-    fs.outputFile.mockResolvedValueOnce(null as never);
+    fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock');
+    fs.writeLocalFile.mockResolvedValueOnce(null as never);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Gemfile.lock'],
     } as Git.StatusResult);
-    fs.readFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
+    fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock' as any);
     expect(
       await updateArtifacts({
         packageFileName: 'Gemfile',
diff --git a/lib/manager/bundler/artifacts.ts b/lib/manager/bundler/artifacts.ts
index 4fec0c0f759b3e2034ca302c3c3760cd0f7e176e..af3c439cf6611112f038248bc869b1f8ac12afeb 100644
--- a/lib/manager/bundler/artifacts.ts
+++ b/lib/manager/bundler/artifacts.ts
@@ -37,7 +37,7 @@ async function getRubyConstraint(
       packageFileName,
       '.ruby-version'
     );
-    const rubyVersionFileContent = await platform.getFile(rubyVersionFile);
+    const rubyVersionFileContent = await readLocalFile(rubyVersionFile, 'utf8');
     if (rubyVersionFileContent) {
       logger.debug('Using ruby version specified in .ruby-version');
       rubyConstraint = rubyVersionFileContent
@@ -80,7 +80,7 @@ export async function updateArtifacts(
     throw new Error(existingError);
   }
   const lockFileName = `${packageFileName}.lock`;
-  const existingLockFileContent = await platform.getFile(lockFileName);
+  const existingLockFileContent = await readLocalFile(lockFileName, 'utf8');
   if (!existingLockFileContent) {
     logger.debug('No Gemfile.lock found');
     return null;
diff --git a/lib/manager/cocoapods/artifacts.spec.ts b/lib/manager/cocoapods/artifacts.spec.ts
index 9b4eb3fd7cb64982d0f3c113eab1c295cd4eb773..24156f3aaf0e558e73eb7eb8d809f371ff91225e 100644
--- a/lib/manager/cocoapods/artifacts.spec.ts
+++ b/lib/manager/cocoapods/artifacts.spec.ts
@@ -97,7 +97,7 @@ describe('.updateArtifacts()', () => {
   });
   it('returns null if unchanged', async () => {
     const execSnapshots = mockExecAll(exec);
-    platform.getFile.mockResolvedValueOnce('Current Podfile');
+    fs.readFile.mockResolvedValueOnce('Current Podfile' as any);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: [],
     } as Git.StatusResult);
@@ -115,7 +115,7 @@ describe('.updateArtifacts()', () => {
   it('returns updated Podfile', async () => {
     const execSnapshots = mockExecAll(exec);
     await setExecConfig({ ...config, binarySource: BinarySource.Docker });
-    platform.getFile.mockResolvedValueOnce('Old Podfile');
+    fs.readFile.mockResolvedValueOnce('Old Podfile' as any);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['Podfile.lock'],
     } as Git.StatusResult);
@@ -133,14 +133,14 @@ describe('.updateArtifacts()', () => {
   it('returns updated Podfile and Pods files', async () => {
     const execSnapshots = mockExecAll(exec);
     await setExecConfig({ ...config, binarySource: BinarySource.Docker });
-    platform.getFile.mockResolvedValueOnce('Old Podfile');
-    platform.getFile.mockResolvedValueOnce('Old Manifest.lock');
+    fs.readFile.mockResolvedValueOnce('Old Manifest.lock' as any);
+    fs.readFile.mockResolvedValueOnce('New Podfile' as any);
+    fs.readFile.mockResolvedValueOnce('Pods manifest' as any);
     platform.getRepoStatus.mockResolvedValueOnce({
       not_added: ['Pods/New'],
       modified: ['Podfile.lock', 'Pods/Manifest.lock'],
       deleted: ['Pods/Deleted'],
     } as Git.StatusResult);
-    fs.readFile.mockResolvedValueOnce('New Podfile' as any);
     expect(
       await updateArtifacts({
         packageFileName: 'Podfile',
@@ -153,7 +153,7 @@ describe('.updateArtifacts()', () => {
   });
   it('catches write error', async () => {
     const execSnapshots = mockExecAll(exec);
-    platform.getFile.mockResolvedValueOnce('Current Podfile');
+    fs.readFile.mockResolvedValueOnce('Current Podfile' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
@@ -169,7 +169,7 @@ describe('.updateArtifacts()', () => {
   });
   it('returns pod exec error', async () => {
     const execSnapshots = mockExecAll(exec, new Error('exec exception'));
-    platform.getFile.mockResolvedValueOnce('Old Podfile.lock');
+    fs.readFile.mockResolvedValueOnce('Old Podfile.lock' as any);
     fs.outputFile.mockResolvedValueOnce(null as never);
     fs.readFile.mockResolvedValueOnce('Old Podfile.lock' as any);
     expect(
@@ -191,7 +191,7 @@ describe('.updateArtifacts()', () => {
       dockerUser: 'ubuntu',
     });
 
-    platform.getFile.mockResolvedValueOnce('COCOAPODS: 1.2.4');
+    fs.readFile.mockResolvedValueOnce('COCOAPODS: 1.2.4' as any);
 
     fs.readFile.mockResolvedValueOnce('New Podfile' as any);
 
@@ -216,7 +216,7 @@ describe('.updateArtifacts()', () => {
       dockerUser: 'ubuntu',
     });
 
-    platform.getFile.mockResolvedValueOnce('COCOAPODS: 1.2.4');
+    fs.readFile.mockResolvedValueOnce('COCOAPODS: 1.2.4' as any);
     datasource.getReleases.mockResolvedValueOnce({
       releases: [],
     });
diff --git a/lib/manager/cocoapods/artifacts.ts b/lib/manager/cocoapods/artifacts.ts
index 78879f7da9d3890c0b13f2365f49b9ab4e643a15..7e7d291b4de9fbbd6e9ef0cbab108dd037d30730 100644
--- a/lib/manager/cocoapods/artifacts.ts
+++ b/lib/manager/cocoapods/artifacts.ts
@@ -54,7 +54,7 @@ export async function updateArtifacts({
     ];
   }
 
-  const existingLockFileContent = await platform.getFile(lockFileName);
+  const existingLockFileContent = await readLocalFile(lockFileName, 'utf8');
   if (!existingLockFileContent) {
     logger.debug(`Lockfile not found: ${lockFileName}`);
     return null;
@@ -106,7 +106,7 @@ export async function updateArtifacts({
 
   const podsDir = join(dirname(packageFileName), 'Pods');
   const podsManifestFileName = join(podsDir, 'Manifest.lock');
-  if (await platform.getFile(podsManifestFileName)) {
+  if (await readLocalFile(podsManifestFileName, 'utf8')) {
     for (const f of status.modified.concat(status.not_added)) {
       if (f.startsWith(podsDir)) {
         res.push({
diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts
index cb6082f8ce5275fc5f7fdfff86bd7f6dde216e3d..09b55b48e3cd9dada7f2a5dc62d4cfca15972355 100644
--- a/lib/manager/composer/artifacts.spec.ts
+++ b/lib/manager/composer/artifacts.spec.ts
@@ -55,7 +55,7 @@ describe('.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('Current composer.lock' as any);
     platform.getRepoStatus.mockResolvedValue({ modified: [] } as StatusResult);
@@ -70,7 +70,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('uses hostRules to write auth.json', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('Current composer.lock' as any);
     const authConfig = {
@@ -93,7 +93,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('returns updated composer.lock', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     platform.getRepoStatus.mockResolvedValue({
@@ -110,7 +110,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('performs lockFileMaintenance', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     platform.getRepoStatus.mockResolvedValue({
@@ -131,7 +131,7 @@ describe('.updateArtifacts()', () => {
   });
   it('supports docker mode', async () => {
     await setUtilConfig({ ...config, binarySource: BinarySource.Docker });
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
 
     const execSnapshots = mockExecAll(exec);
 
@@ -147,7 +147,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('supports global mode', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     expect(
@@ -164,7 +164,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
@@ -178,7 +178,7 @@ describe('.updateArtifacts()', () => {
     ).toMatchSnapshot();
   });
   it('catches unmet requirements errors', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error(
         'fooYour requirements could not be resolved to an installable set of packages.bar'
@@ -194,7 +194,7 @@ describe('.updateArtifacts()', () => {
     ).toMatchSnapshot();
   });
   it('throws for disk space', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error(
         'vendor/composer/07fe2366/sebastianbergmann-php-code-coverage-c896779/src/Report/Html/Renderer/Template/js/d3.min.js:  write error (disk full?).  Continue? (y/n/^C) '
@@ -210,7 +210,7 @@ describe('.updateArtifacts()', () => {
     ).rejects.toThrow();
   });
   it('disables ignorePlatformReqs', async () => {
-    platform.getFile.mockResolvedValueOnce('Current composer.lock');
+    fs.readFile.mockResolvedValueOnce('Current composer.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('New composer.lock' as any);
     platform.getRepoStatus.mockResolvedValue({
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index 097dccfc08eab0d8772ddc1170b81a3f15e77caa..b856ee288cae2494371a56ccc33967301d49485a 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -12,6 +12,7 @@ import * as datasourcePackagist from '../../datasource/packagist';
 import { logger } from '../../logger';
 import { platform } from '../../platform';
 import { ExecOptions, exec } from '../../util/exec';
+import { deleteLocalFile, readLocalFile, writeLocalFile } from '../../util/fs';
 import * as hostRules from '../../util/host-rules';
 import { UpdateArtifact, UpdateArtifactsResult } from '../common';
 
@@ -30,7 +31,7 @@ export async function updateArtifacts({
   logger.debug(`Using composer cache ${cacheDir}`);
 
   const lockFileName = packageFileName.replace(/\.json$/, '.lock');
-  const existingLockFileContent = await platform.getFile(lockFileName);
+  const existingLockFileContent = await readLocalFile(lockFileName);
   if (!existingLockFileContent) {
     logger.debug('No composer.lock found');
     return null;
@@ -38,11 +39,9 @@ export async function updateArtifacts({
   const cwd = upath.join(config.localDir, upath.dirname(packageFileName));
   await fs.ensureDir(upath.join(cwd, 'vendor'));
   try {
-    const localPackageFileName = upath.join(config.localDir, packageFileName);
-    await fs.outputFile(localPackageFileName, newPackageFileContent);
-    const localLockFileName = upath.join(config.localDir, lockFileName);
+    await writeLocalFile(packageFileName, newPackageFileContent);
     if (config.isLockFileMaintenance) {
-      await fs.remove(localLockFileName);
+      await deleteLocalFile(lockFileName);
     }
     const authJson = {};
     let credentials = hostRules.find({
@@ -98,8 +97,7 @@ export async function updateArtifacts({
       logger.warn({ err }, 'Error setting registryUrls auth for composer');
     }
     if (authJson) {
-      const localAuthFileName = upath.join(cwd, 'auth.json');
-      await fs.outputFile(localAuthFileName, JSON.stringify(authJson));
+      await writeLocalFile('auth.json', JSON.stringify(authJson));
     }
     const execOptions: ExecOptions = {
       cwd,
@@ -137,7 +135,7 @@ export async function updateArtifacts({
       {
         file: {
           name: lockFileName,
-          contents: await fs.readFile(localLockFileName, 'utf8'),
+          contents: await readLocalFile(lockFileName),
         },
       },
     ];
diff --git a/lib/manager/gomod/artifacts.spec.ts b/lib/manager/gomod/artifacts.spec.ts
index 05136fad911512478a1896def482702551c06141..cbb15ef524bad885e260ffda21a4cb01f393b1db 100644
--- a/lib/manager/gomod/artifacts.spec.ts
+++ b/lib/manager/gomod/artifacts.spec.ts
@@ -76,7 +76,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: [],
@@ -92,7 +92,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('returns updated go.sum', async () => {
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['go.sum'],
@@ -110,7 +110,7 @@ describe('.updateArtifacts()', () => {
   });
   it('supports docker mode without credentials', async () => {
     await setUtilConfig({ ...config, binarySource: BinarySource.Docker });
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['go.sum'],
@@ -130,7 +130,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('supports global mode', async () => {
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['go.sum'],
@@ -154,7 +154,7 @@ describe('.updateArtifacts()', () => {
     hostRules.find.mockReturnValueOnce({
       token: 'some-token',
     });
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['go.sum'],
@@ -178,12 +178,13 @@ describe('.updateArtifacts()', () => {
     hostRules.find.mockReturnValueOnce({
       token: 'some-token',
     });
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValueOnce({
       modified: ['go.sum'],
     } as StatusResult);
     fs.readFile.mockResolvedValueOnce('New go.sum 1' as any);
+    fs.readFile.mockResolvedValueOnce(null as any); // vendor modules filename
     fs.readFile.mockResolvedValueOnce('New go.sum 2' as any);
     fs.readFile.mockResolvedValueOnce('New go.sum 3' as any);
     try {
@@ -207,7 +208,7 @@ describe('.updateArtifacts()', () => {
   });
   it('catches errors', async () => {
     const execSnapshots = mockExecAll(exec);
-    platform.getFile.mockResolvedValueOnce('Current go.sum');
+    fs.readFile.mockResolvedValueOnce('Current go.sum' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('This update totally doesnt work');
     });
diff --git a/lib/manager/gomod/artifacts.ts b/lib/manager/gomod/artifacts.ts
index ae27390e95a2509509681bad49ba465f44e013b0..8b120171b9c220a4429714a5e5706a9ae407a7b5 100644
--- a/lib/manager/gomod/artifacts.ts
+++ b/lib/manager/gomod/artifacts.ts
@@ -41,7 +41,7 @@ export async function updateArtifacts({
   logger.debug(`Using GOPATH: ${goPath}`);
 
   const sumFileName = goModFileName.replace(/\.mod$/, '.sum');
-  const existingGoSumContent = await platform.getFile(sumFileName);
+  const existingGoSumContent = await readLocalFile(sumFileName);
   if (!existingGoSumContent) {
     logger.debug('No go.sum found');
     return null;
@@ -96,7 +96,7 @@ export async function updateArtifacts({
     const vendorDir = join(dirname(goModFileName), 'vendor/');
     const vendorModulesFileName = join(vendorDir, 'modules.txt');
     // istanbul ignore if
-    if (await platform.getFile(vendorModulesFileName)) {
+    if (await readLocalFile(vendorModulesFileName)) {
       args = 'mod vendor';
       logger.debug({ cmd, args }, 'go mod vendor command');
       await exec(`${cmd} ${args}`, execOptions);
diff --git a/lib/manager/mix/artifacts.spec.ts b/lib/manager/mix/artifacts.spec.ts
index 867d3bb8661f25d4501b28943cfcce31b41ca989..f35afd6434c56e78401d1c1eb1971bc8b33784d0 100644
--- a/lib/manager/mix/artifacts.spec.ts
+++ b/lib/manager/mix/artifacts.spec.ts
@@ -2,19 +2,16 @@ import { exec as _exec } from 'child_process';
 import _fs from 'fs-extra';
 import { envMock, mockExecAll } from '../../../test/execUtil';
 import { mocked } from '../../../test/util';
-import { platform as _platform } from '../../platform';
 import { BinarySource } from '../../util/exec/common';
 import * as _env from '../../util/exec/env';
 import { updateArtifacts } from '.';
 
 const fs: jest.Mocked<typeof _fs> = _fs as any;
 const exec: jest.Mock<typeof _exec> = _exec as any;
-const platform = mocked(_platform);
 const env = mocked(_env);
 
 jest.mock('fs-extra');
 jest.mock('child_process');
-jest.mock('../../platform');
 jest.mock('../../util/exec/env');
 
 const config = {
@@ -72,7 +69,7 @@ describe('.updateArtifacts()', () => {
     ).toBeNull();
   });
   it('returns null if unchanged', async () => {
-    platform.getFile.mockResolvedValueOnce('Current mix.lock');
+    fs.readFile.mockResolvedValueOnce('Current mix.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockResolvedValueOnce('Current mix.lock' as any);
     expect(
@@ -86,7 +83,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('returns updated mix.lock', async () => {
-    platform.getFile.mockResolvedValueOnce('Old mix.lock');
+    fs.readFile.mockResolvedValueOnce('Old mix.lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockResolvedValueOnce('New mix.lock' as any);
     expect(
@@ -103,7 +100,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockResolvedValueOnce('Current mix.lock');
+    fs.readFile.mockResolvedValueOnce('Current mix.lock' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
diff --git a/lib/manager/mix/artifacts.ts b/lib/manager/mix/artifacts.ts
index 610d471f09ffc2160a31ad04e9be1ce9efc7e767..c037f01da1896f18f5fac16c3331baf22b96a799 100644
--- a/lib/manager/mix/artifacts.ts
+++ b/lib/manager/mix/artifacts.ts
@@ -2,9 +2,9 @@ import fs from 'fs-extra';
 import { quote } from 'shlex';
 import upath from 'upath';
 import { logger } from '../../logger';
-import { platform } from '../../platform';
 import { exec } from '../../util/exec';
 import { BinarySource } from '../../util/exec/common';
+import { readLocalFile } from '../../util/fs';
 import { UpdateArtifact, UpdateArtifactsResult } from '../common';
 
 export async function updateArtifacts({
@@ -41,7 +41,7 @@ export async function updateArtifacts({
     ];
   }
 
-  const existingLockFileContent = await platform.getFile(lockFileName);
+  const existingLockFileContent = await readLocalFile(lockFileName, 'utf8');
   if (!existingLockFileContent) {
     logger.debug('No mix.lock found');
     return null;
diff --git a/lib/manager/pipenv/artifacts.spec.ts b/lib/manager/pipenv/artifacts.spec.ts
index 691787cbeb99c141d17100affcf53e14ceda3573..a9a89b5cbc95631d48e9e189121d086fd08c7635 100644
--- a/lib/manager/pipenv/artifacts.spec.ts
+++ b/lib/manager/pipenv/artifacts.spec.ts
@@ -63,7 +63,7 @@ describe('.updateArtifacts()', () => {
   });
   it('returns null if unchanged', async () => {
     pipFileLock._meta.requires.python_full_version = '3.7.6';
-    platform.getFile.mockResolvedValueOnce(JSON.stringify(pipFileLock));
+    fs.readFile.mockResolvedValueOnce(JSON.stringify(pipFileLock) as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce(JSON.stringify(pipFileLock) as any);
     expect(
@@ -77,7 +77,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('handles no constraint', async () => {
-    platform.getFile.mockResolvedValueOnce('unparseable pipfile lock');
+    fs.readFile.mockResolvedValueOnce('unparseable pipfile lock' as any);
     const execSnapshots = mockExecAll(exec);
     fs.readFile.mockReturnValueOnce('unparseable pipfile lock' as any);
     expect(
@@ -91,7 +91,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('returns updated Pipfile.lock', async () => {
-    platform.getFile.mockResolvedValueOnce('current pipfile.lock');
+    fs.readFile.mockResolvedValueOnce('current pipfile.lock' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValue({
       modified: ['Pipfile.lock'],
@@ -110,7 +110,7 @@ describe('.updateArtifacts()', () => {
   it('supports docker mode', async () => {
     await setUtilConfig(dockerConfig);
     pipFileLock._meta.requires.python_version = '3.7';
-    platform.getFile.mockResolvedValueOnce(JSON.stringify(pipFileLock));
+    fs.readFile.mockResolvedValueOnce(JSON.stringify(pipFileLock) as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValue({
       modified: ['Pipfile.lock'],
@@ -127,7 +127,7 @@ describe('.updateArtifacts()', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
   it('catches errors', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
+    fs.readFile.mockResolvedValueOnce('Current Pipfile.lock' as any);
     fs.outputFile.mockImplementationOnce(() => {
       throw new Error('not found');
     });
@@ -141,7 +141,7 @@ describe('.updateArtifacts()', () => {
     ).toMatchSnapshot();
   });
   it('returns updated Pipenv.lock when doing lockfile maintenance', async () => {
-    platform.getFile.mockResolvedValueOnce('Current Pipfile.lock');
+    fs.readFile.mockResolvedValueOnce('Current Pipfile.lock' as any);
     const execSnapshots = mockExecAll(exec);
     platform.getRepoStatus.mockResolvedValue({
       modified: ['Pipfile.lock'],
diff --git a/lib/manager/pipenv/artifacts.ts b/lib/manager/pipenv/artifacts.ts
index 67c3a80762e91f87c2af675637f08110222e7f83..9e33a4dd91b4d709a390cc3c826361ffd7dfe271 100644
--- a/lib/manager/pipenv/artifacts.ts
+++ b/lib/manager/pipenv/artifacts.ts
@@ -3,6 +3,7 @@ import { join } from 'upath';
 import { logger } from '../../logger';
 import { platform } from '../../platform';
 import { ExecOptions, exec } from '../../util/exec';
+import { readLocalFile } from '../../util/fs';
 import {
   UpdateArtifact,
   UpdateArtifactsConfig,
@@ -47,7 +48,7 @@ export async function updateArtifacts({
   logger.debug('Using pipenv cache ' + cacheDir);
 
   const lockFileName = pipfileName + '.lock';
-  const existingLockFileContent = await platform.getFile(lockFileName);
+  const existingLockFileContent = await readLocalFile(lockFileName, 'utf8');
   if (!existingLockFileContent) {
     logger.debug('No Pipfile.lock found');
     return null;
diff --git a/lib/util/fs.ts b/lib/util/fs.ts
index 0bcbd47dacde51ec9e7fd5f43b7241d63e8ba2e4..1a472d65028ec369666bb12e12a235bd41545384 100644
--- a/lib/util/fs.ts
+++ b/lib/util/fs.ts
@@ -1,4 +1,4 @@
-import { outputFile, readFile, remove } from 'fs-extra';
+import * as fs from 'fs-extra';
 import { join, parse } from 'upath';
 import { RenovateConfig } from '../config/common';
 import { logger } from '../logger';
@@ -32,7 +32,7 @@ export async function readLocalFile(
 ): Promise<string | Buffer> {
   const localFileName = join(localDir, fileName);
   try {
-    const fileContent = await readFile(localFileName, encoding);
+    const fileContent = await fs.readFile(localFileName, encoding);
     return fileContent;
   } catch (err) {
     logger.trace({ err }, 'Error reading local file');
@@ -45,9 +45,9 @@ export async function writeLocalFile(
   fileContent: string
 ): Promise<void> {
   const localFileName = join(localDir, fileName);
-  await outputFile(localFileName, fileContent);
+  await fs.outputFile(localFileName, fileContent);
 }
 
 export async function deleteLocalFile(fileName: string): Promise<void> {
-  await remove(fileName);
+  await fs.remove(fileName);
 }