diff --git a/lib/workers/branch/index.js b/lib/workers/branch/index.js index 326ef2cfcb221531df451c5190ab5fb9ce9d671a..f208d60df6e3a9bbca46c38c8b6b83fe36c43604 100644 --- a/lib/workers/branch/index.js +++ b/lib/workers/branch/index.js @@ -1,3 +1,4 @@ +const path = require('path'); const handlebars = require('handlebars'); const packageJsonHelper = require('./package-json'); const npm = require('./npm'); @@ -153,6 +154,7 @@ async function ensureBranch(config) { }); try { const yarnLockFile = await yarn.getLockFile( + path.join(config.tmpDir.name, path.dirname(packageFile)), packageFile, packageFiles[packageFile], api, @@ -164,6 +166,7 @@ async function ensureBranch(config) { commitFiles.push(yarnLockFile); } const packageLockFile = await npm.getLockFile( + path.join(config.tmpDir.name, path.dirname(packageFile)), packageFile, packageFiles[packageFile], api, diff --git a/lib/workers/branch/npm.js b/lib/workers/branch/npm.js index 78c1cf86e23678823a05201d5a0988c7917ccce5..9de0b9b52e26c09a8d8975011382b4bf752b89b1 100644 --- a/lib/workers/branch/npm.js +++ b/lib/workers/branch/npm.js @@ -1,6 +1,5 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const cp = require('child_process'); -const tmp = require('tmp'); const path = require('path'); module.exports = { @@ -9,19 +8,21 @@ module.exports = { maintainLockFile, }; -async function generateLockFile(newPackageJson, npmrcContent, logger) { +async function generateLockFile(tmpDir, newPackageJson, npmrcContent, logger) { logger.debug('Generating new package-lock.json file'); - const tmpDir = tmp.dirSync({ unsafeCleanup: true }); let packageLock; let result = {}; try { - fs.writeFileSync(path.join(tmpDir.name, 'package.json'), newPackageJson); + await fs.outputFile(path.join(tmpDir, 'package.json'), newPackageJson); if (npmrcContent) { - fs.writeFileSync(path.join(tmpDir.name, '.npmrc'), npmrcContent); + await fs.outputFile(path.join(tmpDir, '.npmrc'), npmrcContent); } - logger.debug('Spawning npm install'); + await fs.remove(path.join(tmpDir, 'package-lock.json')); + logger.debug( + `Spawning npm install to generate ${tmpDir}/package-lock.json` + ); result = cp.spawnSync('npm', ['install', '--ignore-scripts'], { - cwd: tmpDir.name, + cwd: tmpDir, shell: true, env: { ...process.env, ...{ NODE_ENV: 'dev' } }, }); @@ -29,7 +30,7 @@ async function generateLockFile(newPackageJson, npmrcContent, logger) { { stdout: String(result.stdout), stderr: String(result.stderr) }, 'npm install complete' ); - packageLock = fs.readFileSync(path.join(tmpDir.name, 'package-lock.json')); + packageLock = fs.readFileSync(path.join(tmpDir, 'package-lock.json')); } catch (err) /* istanbul ignore next */ { logger.warn( { @@ -41,22 +42,13 @@ async function generateLockFile(newPackageJson, npmrcContent, logger) { }, 'Error generating package-lock.json' ); - try { - tmpDir.removeCallback(); - } catch (err2) { - logger.warn(`Failed to remove tmpDir ${tmpDir.name}`); - } throw Error('Error generating lock file'); } - try { - tmpDir.removeCallback(); - } catch (err2) { - logger.warn(`Failed to remove tmpDir ${tmpDir.name}`); - } return packageLock; } async function getLockFile( + tmpDir, packageFile, packageContent, api, @@ -86,6 +78,7 @@ async function getLockFile( const npmrcContent = await api.getFileContent('.npmrc'); // Generate package-lock.json using shell command const newPackageLockContent = await module.exports.generateLockFile( + tmpDir, packageContent, npmrcContent, logger @@ -117,6 +110,7 @@ async function maintainLockFile(inputConfig) { } logger.debug('Found existing package-lock.json file'); const newPackageLock = await module.exports.getLockFile( + path.join(inputConfig.tmpDir.name, path.dirname(inputConfig.packageFile)), inputConfig.packageFile, packageContent, inputConfig.api, diff --git a/lib/workers/branch/yarn.js b/lib/workers/branch/yarn.js index 8bde6804efa697a99631b6259130f19c71131320..02405837c142e21a1cfe0555606d6a68c5d9f759 100644 --- a/lib/workers/branch/yarn.js +++ b/lib/workers/branch/yarn.js @@ -1,6 +1,5 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const cp = require('child_process'); -const tmp = require('tmp'); const path = require('path'); module.exports = { @@ -12,28 +11,29 @@ module.exports = { const yarnVersion = '0.27.5'; async function generateLockFile( + tmpDir, newPackageJson, npmrcContent, yarnrcContent, logger ) { logger.debug('Generating new yarn.lock file'); - const tmpDir = tmp.dirSync({ unsafeCleanup: true }); let yarnLock; let result = {}; try { - fs.writeFileSync(path.join(tmpDir.name, 'package.json'), newPackageJson); + await fs.outputFile(path.join(tmpDir, 'package.json'), newPackageJson); if (npmrcContent) { - fs.writeFileSync(path.join(tmpDir.name, '.npmrc'), npmrcContent); + await fs.outputFile(path.join(tmpDir, '.npmrc'), npmrcContent); } if (yarnrcContent) { const filteredYarnrc = yarnrcContent.replace( '--install.pure-lockfile true', '' ); - fs.writeFileSync(path.join(tmpDir.name, '.yarnrc'), filteredYarnrc); + await fs.outputFile(path.join(tmpDir, '.yarnrc'), filteredYarnrc); } - logger.debug('Spawning yarn install'); + await fs.remove(path.join(tmpDir, 'yarn.lock')); + logger.debug(`Spawning yarn install to create ${tmpDir}/yarn.lock`); // Use an embedded yarn const yarnBin = path.join( __dirname, @@ -42,13 +42,13 @@ async function generateLockFile( ); const yarnOptions = [yarnBin, 'install', '--ignore-scripts']; result = cp.spawnSync('node', yarnOptions, { - cwd: tmpDir.name, + cwd: tmpDir, shell: true, env: { ...process.env, ...{ NODE_ENV: 'dev' } }, }); logger.debug(String(result.stdout)); logger.debug(String(result.stderr)); - yarnLock = fs.readFileSync(path.join(tmpDir.name, 'yarn.lock')); + yarnLock = fs.readFileSync(path.join(tmpDir, 'yarn.lock')); } catch (err) /* istanbul ignore next */ { logger.warn( { @@ -61,22 +61,12 @@ async function generateLockFile( }, 'Error generating yarn.lock' ); - try { - tmpDir.removeCallback(); - } catch (err2) { - logger.warn(`Failed to remove tmpDir ${tmpDir.name}`); - } throw Error('Error generating lock file'); } - try { - tmpDir.removeCallback(); - } catch (err2) { - logger.warn(`Failed to remove tmpDir ${tmpDir.name}`); - } return yarnLock; } -async function getLockFile(packageFile, packageContent, api, logger) { +async function getLockFile(tmpDir, packageFile, packageContent, api, logger) { // Detect if a yarn.lock file is in use const yarnLockFileName = path.join(path.dirname(packageFile), 'yarn.lock'); if (!await api.getFileContent(yarnLockFileName)) { @@ -87,6 +77,7 @@ async function getLockFile(packageFile, packageContent, api, logger) { const yarnrcContent = await api.getFileContent('.yarnrc'); // Generate yarn.lock using shell command const newYarnLockContent = await module.exports.generateLockFile( + tmpDir, packageContent, npmrcContent, yarnrcContent, @@ -123,6 +114,7 @@ async function maintainLockFile(inputConfig) { } logger.debug('Found existing yarn.lock file'); const newYarnLock = await module.exports.getLockFile( + path.join(inputConfig.tmpDir.name, path.dirname(inputConfig.packageFile)), inputConfig.packageFile, packageContent, inputConfig.api, diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js index 72db87b59484c66c65fce8f48470cfd883001205..c1dd05a1ba7ee9bae4a525afeac1c22d3efe6ae4 100644 --- a/lib/workers/repository/index.js +++ b/lib/workers/repository/index.js @@ -1,3 +1,4 @@ +const tmp = require('tmp'); const presets = require('../../config/presets'); // Workers const branchWorker = require('../branch'); @@ -14,6 +15,7 @@ module.exports = { async function renovateRepository(repoConfig, token) { let config = { ...repoConfig }; const { logger } = config; + config.tmpDir = tmp.dirSync({ unsafeCleanup: true }); config.errors = []; config.warnings = []; logger.trace({ config }, 'renovateRepository'); @@ -125,4 +127,5 @@ async function renovateRepository(repoConfig, token) { logger.debug({ err }); } } + config.tmpDir.removeCallback(); } diff --git a/package.json b/package.json index f65608f3dd6df6c3a55e13d99bceba13a41fea8b..210830d57c73299afa5216a223c69be24e8d5be3 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "changelog": "1.4.0", "commander": "2.11.0", "conventional-commits-detector": "0.1.1", + "fs-extra": "4.0.1", "gh-got": "6.0.0", "github-url-from-git": "1.5.0", "gl-got": "7.0.0", @@ -115,8 +116,12 @@ ":automergeBranchPush", "group:monorepos" ], - "labels": ["ready"], - "assignees": ["rarkins"] + "labels": [ + "ready" + ], + "assignees": [ + "rarkins" + ] }, "release": { "verifyConditions": "condition-circle" diff --git a/test/workers/branch/__snapshots__/npm.spec.js.snap b/test/workers/branch/__snapshots__/npm.spec.js.snap index d43fb2cd393e4aa20a89af17600d1b4851e9e6f2..2ab30bd6047ab3b2b1715ba253bc764122ff6cc7 100644 --- a/test/workers/branch/__snapshots__/npm.spec.js.snap +++ b/test/workers/branch/__snapshots__/npm.spec.js.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getLockFile(packageFile, packageContent, api, npmVersion) throws if no npm 1`] = `[Error: Need to generate package-lock.json but npm is not installed]`; +exports[`getLockFile throws if no npm 1`] = `[Error: Need to generate package-lock.json but npm is not installed]`; -exports[`getLockFile(packageFile, packageContent, api, npmVersion) throws if wrong npm version 1`] = `[Error: Need to generate package-lock.json but npm version is "4.0.0"]`; +exports[`getLockFile throws if wrong npm version 1`] = `[Error: Need to generate package-lock.json but npm version is "4.0.0"]`; diff --git a/test/workers/branch/index.spec.js b/test/workers/branch/index.spec.js index b0d29ff8a6858d70e44a128e0b64b322c53d6ae2..aef038de9e393e1b64e7ca16b873e7d82c3989d1 100644 --- a/test/workers/branch/index.spec.js +++ b/test/workers/branch/index.spec.js @@ -121,6 +121,7 @@ describe('workers/branch', () => { config.api.getBranchStatus = jest.fn(); config.api.getBranchStatusCheck = jest.fn(); config.api.setBranchStatus = jest.fn(); + config.tmpDir = { name: 'some-dir' }; config.depName = 'dummy'; config.currentVersion = '1.0.0'; config.newVersion = '1.1.0'; diff --git a/test/workers/branch/npm.spec.js b/test/workers/branch/npm.spec.js index 022a9767d7a8aa4c74adbae59a11f804cb4004ea..023fd67c35cff9b8bfb510bcfc9850106eab49cd 100644 --- a/test/workers/branch/npm.spec.js +++ b/test/workers/branch/npm.spec.js @@ -1,17 +1,16 @@ const npmHelper = require('../../../lib/workers/branch/npm'); const logger = require('../../_fixtures/logger'); -jest.mock('fs'); +jest.mock('fs-extra'); jest.mock('child_process'); -jest.mock('tmp'); -const fs = require('fs'); +const fs = require('fs-extra'); const cp = require('child_process'); -const tmp = require('tmp'); -describe('generateLockFile(newPackageJson, npmrcContent, logger)', () => { - tmp.dirSync = jest.fn(() => ({ name: 'somedir' })); - fs.writeFileSync = jest.fn(); +const tmpDir = { name: 'some-dir' }; + +describe('generateLockFile', () => { + fs.outputFile = jest.fn(); fs.readFileSync = jest.fn(() => 'package-lock-contents'); cp.spawnSync = jest.fn(() => ({ stdout: '', @@ -19,17 +18,17 @@ describe('generateLockFile(newPackageJson, npmrcContent, logger)', () => { })); it('generates lock files', async () => { const packageLock = await npmHelper.generateLockFile( - 'package-json-contents', + tmpDir.name, + {}, 'npmrc-contents', logger ); - expect(tmp.dirSync.mock.calls.length).toEqual(1); - expect(fs.writeFileSync.mock.calls.length).toEqual(2); + expect(fs.outputFile.mock.calls.length).toEqual(2); expect(fs.readFileSync.mock.calls.length).toEqual(1); expect(packageLock).toEqual('package-lock-contents'); }); }); -describe('getLockFile(packageFile, packageContent, api, npmVersion)', () => { +describe('getLockFile', () => { let api; beforeEach(() => { api = { @@ -38,7 +37,9 @@ describe('getLockFile(packageFile, packageContent, api, npmVersion)', () => { }); it('returns null if no existing package-lock.json', async () => { api.getFileContent.mockReturnValueOnce(false); - expect(await npmHelper.getLockFile('package.json', '', api)).toBe(null); + expect(await npmHelper.getLockFile(tmpDir, 'package.json', '', api)).toBe( + null + ); }); it('returns package-lock.json file', async () => { api.getFileContent.mockReturnValueOnce('Existing package-lock.json'); @@ -50,14 +51,14 @@ describe('getLockFile(packageFile, packageContent, api, npmVersion)', () => { contents: 'New package-lock.json', }; expect( - await npmHelper.getLockFile('package.json', '', api, '5.0.4') + await npmHelper.getLockFile(tmpDir, 'package.json', '', api, '5.0.4') ).toMatchObject(packageLockFile); }); it('throws if no npm', async () => { api.getFileContent.mockReturnValueOnce('Existing package-lock.json'); let e; try { - await npmHelper.getLockFile('package.json', '', api, ''); + await npmHelper.getLockFile(tmpDir, 'package.json', '', api, ''); } catch (err) { e = err; } @@ -67,7 +68,7 @@ describe('getLockFile(packageFile, packageContent, api, npmVersion)', () => { api.getFileContent.mockReturnValueOnce('Existing package-lock.json'); let e; try { - await npmHelper.getLockFile('package.json', '', api, '4.0.0'); + await npmHelper.getLockFile(tmpDir, 'package.json', '', api, '4.0.0'); } catch (err) { e = err; } @@ -75,7 +76,7 @@ describe('getLockFile(packageFile, packageContent, api, npmVersion)', () => { }); }); -describe('maintainLockFile(inputConfig)', () => { +describe('maintainLockFile', () => { let config; beforeEach(() => { config = { logger }; @@ -86,6 +87,7 @@ describe('maintainLockFile(inputConfig)', () => { config.versions = { npm: '5.3.0', }; + config.tmpDir = tmpDir; config.api.getFileContent.mockReturnValueOnce('oldPackageContent'); npmHelper.getLockFile = jest.fn(); }); diff --git a/test/workers/branch/yarn.spec.js b/test/workers/branch/yarn.spec.js index d05815cde5e7852eb30cc8193fc651d7ecf9360d..4877659df4e7e4bce10edce331beb142e7f69deb 100644 --- a/test/workers/branch/yarn.spec.js +++ b/test/workers/branch/yarn.spec.js @@ -1,17 +1,16 @@ const yarnHelper = require('../../../lib/workers/branch/yarn'); const logger = require('../../_fixtures/logger'); -jest.mock('fs'); +jest.mock('fs-extra'); jest.mock('child_process'); -jest.mock('tmp'); -const fs = require('fs'); +const fs = require('fs-extra'); const cp = require('child_process'); -const tmp = require('tmp'); -describe('generateLockFile(newPackageJson, npmrcContent, yarnrcContent, logger)', () => { - tmp.dirSync = jest.fn(() => ({ name: 'somedir' })); - fs.writeFileSync = jest.fn(); +const tmpDir = { name: 'some-dir' }; + +describe('generateLockFile', () => { + fs.outputFile = jest.fn(); fs.readFileSync = jest.fn(() => 'yarn-lock-contents'); cp.spawnSync = jest.fn(() => ({ stdout: '', @@ -19,18 +18,18 @@ describe('generateLockFile(newPackageJson, npmrcContent, yarnrcContent, logger)' })); it('generates lock files', async () => { const yarnLock = await yarnHelper.generateLockFile( - 'package-json-contents', + tmpDir.name, + {}, 'npmrc-contents', 'yarnrc-contents', logger ); - expect(tmp.dirSync.mock.calls.length).toEqual(1); - expect(fs.writeFileSync.mock.calls.length).toEqual(3); + expect(fs.outputFile.mock.calls.length).toEqual(3); expect(fs.readFileSync.mock.calls.length).toEqual(1); expect(yarnLock).toEqual('yarn-lock-contents'); }); }); -describe('getLockFile(packageJson, config)', () => { +describe('getLockFile', () => { let api; beforeEach(() => { api = { @@ -39,9 +38,9 @@ describe('getLockFile(packageJson, config)', () => { }); it('returns null if no existing yarn.lock', async () => { api.getFileContent.mockReturnValueOnce(false); - expect(await yarnHelper.getLockFile('package.json', '', api, '')).toBe( - null - ); + expect( + await yarnHelper.getLockFile(tmpDir, 'package.json', '', api, '') + ).toBe(null); }); it('returns yarn.lock file', async () => { api.getFileContent.mockReturnValueOnce('Existing yarn.lock'); @@ -54,12 +53,12 @@ describe('getLockFile(packageJson, config)', () => { contents: 'New yarn.lock', }; expect( - await yarnHelper.getLockFile('package.json', '', api, '') + await yarnHelper.getLockFile(tmpDir, 'package.json', '', api, '') ).toMatchObject(yarnLockFile); }); }); -describe('maintainLockFile(inputConfig)', () => { +describe('maintainLockFile', () => { let config; beforeEach(() => { config = { logger }; @@ -67,6 +66,7 @@ describe('maintainLockFile(inputConfig)', () => { config.api = { getFileContent: jest.fn(), }; + config.tmpDir = tmpDir; config.api.getFileContent.mockReturnValueOnce('oldPackageContent'); yarnHelper.getLockFile = jest.fn(); }); diff --git a/yarn.lock b/yarn.lock index c463d9b06f7aa692341ce37de85f40893b98609d..9f1a04757c6be62685e10d7828c09810722e5f22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,6 +1363,14 @@ from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" +fs-extra@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + fs-readdir-recursive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" @@ -2317,6 +2325,12 @@ json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -3998,6 +4012,10 @@ underscore.string@~2.2.0rc: version "2.2.1" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.2.1.tgz#d7c0fa2af5d5a1a67f4253daee98132e733f0f19" +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"