renovate/lib/workers/branch/yarn.js
Rhys Arkins 9af6117386 fix(lockFiles): Pass NODE_ENV=dev to npm and yarn installs
Without this setting, it can result in an incomplete `package-lock.json` if renovate is run on a system with NODE_ENV=production set.

Fixes #517
2017-07-24 08:10:42 +02:00

130 lines
3.8 KiB
JavaScript

const logger = require('../../logger');
const fs = require('fs');
const cp = require('child_process');
const tmp = require('tmp');
const path = require('path');
module.exports = {
generateLockFile,
getLockFile,
maintainLockFile,
};
const yarnVersion = '0.27.5';
async function generateLockFile(
newPackageJson,
npmrcContent,
yarnrcContent,
cacheFolder
) {
logger.debug('Generating new yarn.lock file');
const tmpDir = tmp.dirSync({ unsafeCleanup: true });
let yarnLock;
try {
fs.writeFileSync(path.join(tmpDir.name, 'package.json'), newPackageJson);
if (npmrcContent) {
fs.writeFileSync(path.join(tmpDir.name, '.npmrc'), npmrcContent);
}
if (yarnrcContent) {
const filteredYarnrc = yarnrcContent.replace(
'--install.pure-lockfile true',
''
);
fs.writeFileSync(path.join(tmpDir.name, '.yarnrc'), filteredYarnrc);
}
logger.debug('Spawning yarn install');
// Use an embedded yarn
const yarnBin = path.join(
__dirname,
'../../../bin',
`yarn-${yarnVersion}.js`
);
const yarnOptions = [yarnBin, 'install', '--ignore-scripts'];
if (cacheFolder && cacheFolder.length) {
logger.debug(`Setting yarn cache folder to ${cacheFolder}`);
yarnOptions.push(`--cache-folder ${cacheFolder}`);
}
const result = cp.spawnSync('node', yarnOptions, {
cwd: tmpDir.name,
shell: true,
env: Object.assign({}, process.env, { NODE_ENV: 'dev' }),
});
logger.debug(String(result.stdout));
logger.debug(String(result.stderr));
yarnLock = fs.readFileSync(path.join(tmpDir.name, 'yarn.lock'));
} catch (error) /* istanbul ignore next */ {
try {
tmpDir.removeCallback();
} catch (err2) {
logger.warn(`Failed to remove tmpDir ${tmpDir.name}`);
}
throw error;
}
try {
tmpDir.removeCallback();
} catch (err2) {
logger.warn(`Failed to remove tmpDir ${tmpDir.name}`);
}
return yarnLock;
}
async function getLockFile(packageFile, packageContent, api, cacheFolder) {
// Detect if a yarn.lock file is in use
const yarnLockFileName = path.join(path.dirname(packageFile), 'yarn.lock');
if (!await api.getFileContent(yarnLockFileName)) {
return null;
}
// Copy over custom config commitFiles
const npmrcContent = await api.getFileContent('.npmrc');
const yarnrcContent = await api.getFileContent('.yarnrc');
// Generate yarn.lock using shell command
const newYarnLockContent = await module.exports.generateLockFile(
packageContent,
npmrcContent,
yarnrcContent,
cacheFolder
);
// Return file object
return {
name: yarnLockFileName,
contents: newYarnLockContent,
};
}
async function maintainLockFile(inputConfig) {
logger.trace({ config: inputConfig }, `maintainLockFile`);
const packageContent = await inputConfig.api.getFileContent(
inputConfig.packageFile
);
const yarnLockFileName = path.join(
path.dirname(inputConfig.packageFile),
'yarn.lock'
);
logger.debug(`Checking for ${yarnLockFileName}`);
let existingYarnLock = await inputConfig.api.getFileContent(
yarnLockFileName,
inputConfig.branchName
);
if (!existingYarnLock) {
existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName);
}
logger.trace(`existingYarnLock:\n${existingYarnLock}`);
if (!existingYarnLock) {
return null;
}
logger.debug('Found existing yarn.lock file');
const newYarnLock = await module.exports.getLockFile(
inputConfig.packageFile,
packageContent,
inputConfig.api,
inputConfig.yarnCacheFolder
);
logger.trace(`newYarnLock:\n${newYarnLock.contents}`);
if (existingYarnLock.toString() === newYarnLock.contents.toString()) {
logger.debug('Yarn lock file does not need updating');
return null;
}
logger.debug('Yarn lock needs updating');
return newYarnLock;
}