renovate/lib/worker.js
Renovate Bot 5ebff14931 Update dependency prettier to version 1.3.1 (#199)
* Update dependency prettier to version 1.3.1

* Run eslint-fix
2017-05-10 09:26:08 +02:00

232 lines
7.6 KiB
JavaScript

const logger = require('winston');
const stringify = require('json-stringify-pretty-compact');
const handlebars = require('handlebars');
const versionsHelper = require('./helpers/versions');
const packageJson = require('./helpers/package-json');
const npmApi = require('./api/npm');
const prWorker = require('./workers/pr');
const branchWorker = require('./workers/branch');
let config;
module.exports = {
processPackageFile,
findUpgrades,
processUpgrades,
updateBranch,
assignDepConfigs,
getDepTypeConfig,
};
// This function manages the queue per-package file
async function processPackageFile(repoName, packageFile, packageConfig) {
// Initialize globals
config = Object.assign({}, packageConfig);
config.packageFile = packageFile;
logger.info(`Processing ${repoName} ${packageFile}`);
const packageContent = await config.api.getFileJson(packageFile);
// Check for renovate config inside the package.json
if (packageContent.renovate) {
logger.debug(
`package.json>renovate config: ${stringify(packageContent.renovate)}`
);
Object.assign(config, packageContent.renovate, { repoConfigured: true });
}
// Now check if config is disabled
if (config.enabled === false) {
logger.info('Config is disabled. Skipping');
return [];
}
const depTypes = config.depTypes.map(depType => {
if (typeof depType === 'string') {
return depType;
}
return depType.depType;
});
// Extract all dependencies from the package.json
let dependencies = await packageJson.extractDependencies(
packageContent,
depTypes
);
// Filter out ignored dependencies
dependencies = dependencies.filter(
dependency => config.ignoreDeps.indexOf(dependency.depName) === -1
);
dependencies = assignDepConfigs(config, dependencies);
// Find all upgrades for remaining dependencies
const upgrades = await findUpgrades(dependencies);
// Process all upgrades sequentially
if (config.maintainYarnLock) {
const upgrade = Object.assign({}, config, {
upgradeType: 'maintainYarnLock',
});
upgrade.upgradeType = 'maintainYarnLock';
upgrade.commitMessage = upgrade.yarnMaintenanceCommitMessage;
upgrade.branchName = upgrade.yarnMaintenanceBranchName;
upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
upgrade.prBody = upgrade.yarnMaintenancePrBody;
upgrades.push(upgrade);
}
return upgrades;
}
// Add custom config for each dep
function assignDepConfigs(inputConfig, deps) {
return deps.map(dep => {
const returnDep = Object.assign({}, dep);
returnDep.config = Object.assign(
{},
inputConfig,
getDepTypeConfig(inputConfig.depTypes, dep.depType)
);
let packageRuleApplied = false;
if (returnDep.config.packages) {
// Loop through list looking for match
// Exit after first match
returnDep.config.packages.forEach(packageConfig => {
if (!packageRuleApplied) {
const pattern =
packageConfig.packagePattern || `^${packageConfig.packageName}$`;
const packageRegex = new RegExp(pattern);
if (dep.depName.match(packageRegex)) {
packageRuleApplied = true;
Object.assign(returnDep.config, packageConfig);
delete returnDep.config.packageName;
delete returnDep.config.packagePattern;
}
}
});
}
delete returnDep.config.depType;
delete returnDep.config.depTypes;
delete returnDep.config.enabled;
delete returnDep.config.onboarding;
delete returnDep.config.token;
delete returnDep.config.packageFiles;
delete returnDep.config.logLevel;
delete returnDep.config.repoConfigured;
delete returnDep.config.ignoreDeps;
delete returnDep.config.packages;
delete returnDep.config.maintainYarnLock;
delete returnDep.config.yarnMaintenanceBranchName;
delete returnDep.config.yarnMaintenanceCommitMessage;
delete returnDep.config.yarnMaintenancePrTitle;
delete returnDep.config.yarnMaintenancePrBody;
return returnDep;
});
}
function getDepTypeConfig(depTypes, depTypeName) {
let depTypeConfig = {};
if (depTypes) {
depTypes.forEach(depType => {
if (typeof depType !== 'string' && depType.depType === depTypeName) {
depTypeConfig = depType;
}
});
}
return depTypeConfig;
}
async function findUpgrades(dependencies) {
const allUpgrades = [];
// findDepUpgrades can add more than one upgrade to allUpgrades
async function findDepUpgrades(dep) {
const npmDependency = await npmApi.getDependency(dep.depName);
const upgrades = await versionsHelper.determineUpgrades(
npmDependency,
dep.currentVersion,
dep.config
);
if (upgrades.length > 0) {
logger.verbose(`${dep.depName}: Upgrades = ${JSON.stringify(upgrades)}`);
upgrades.forEach(upgrade => {
allUpgrades.push(Object.assign({}, dep, upgrade));
});
} else {
logger.verbose(`${dep.depName}: No upgrades required`);
}
}
const promiseArray = dependencies.map(dep => findDepUpgrades(dep));
// Use Promise.all to execute npm queries in parallel
await Promise.all(promiseArray);
// Return the upgrade array once all Promises are complete
return allUpgrades;
}
async function processUpgrades(upgrades) {
if (upgrades.length) {
logger.verbose('Processing upgrades');
} else {
logger.verbose('No upgrades to process');
}
logger.verbose(`All upgrades: ${JSON.stringify(upgrades)}`);
const branchUpgrades = {};
for (const upgrade of upgrades) {
const flattened = Object.assign({}, upgrade.config, upgrade);
delete flattened.config;
if (flattened.upgradeType === 'pin') {
flattened.isPin = true;
} else if (flattened.upgradeType === 'major') {
flattened.isMajor = true;
} else if (flattened.upgradeType === 'minor') {
flattened.isMinor = true;
}
// Check whether to use a group name
if (flattened.groupName) {
flattened.groupSlug =
flattened.groupSlug ||
flattened.groupName.toLowerCase().replace(/[^a-z0-9+]+/g, '-');
flattened.branchName = flattened.groupBranchName;
flattened.commitMessage = flattened.groupCommitMessage;
flattened.prTitle = flattened.groupPrTitle;
flattened.prBody = flattened.groupPrBody;
}
const branchName = handlebars.compile(flattened.branchName)(flattened);
if (!branchUpgrades[branchName]) {
branchUpgrades[branchName] = [];
}
branchUpgrades[branchName].push(flattened);
}
logger.verbose(`Branched upgrades: ${JSON.stringify(branchUpgrades)}`);
for (const branch of Object.keys(branchUpgrades)) {
await module.exports.updateBranch(branchUpgrades[branch]);
}
}
async function updateBranch(upgrades) {
// Use templates to generate strings
const upgrade0 = upgrades[0];
const branchName = handlebars.compile(upgrade0.branchName)(upgrade0);
const prTitle = handlebars.compile(upgrade0.prTitle)(upgrade0);
logger.verbose(`branchName '${branchName}' length is ${upgrades.length}`);
try {
if (
upgrade0.upgradeType !== 'maintainYarnLock' &&
upgrade0.groupName === null &&
!upgrade0.recreateClosed &&
(await upgrade0.api.checkForClosedPr(branchName, prTitle))
) {
logger.verbose(
`Skipping ${branchName} upgrade as matching closed PR already existed`
);
return;
}
const branchCreated = await branchWorker.ensureBranch(upgrades);
if (branchCreated) {
const pr = await prWorker.ensurePr(upgrade0);
if (pr) {
await prWorker.checkAutoMerge(pr, upgrade0);
}
}
} catch (error) {
logger.error(`Error updating branch ${branchName}: ${error}`);
// Don't throw here - we don't want to stop the other renovations
}
}