2017-11-01 09:31:56 +00:00
|
|
|
const minimatch = require('minimatch');
|
2018-03-03 13:39:39 +00:00
|
|
|
const { mergeChildConfig } = require('../config');
|
|
|
|
const { checkMonorepos } = require('../manager/npm/monorepos');
|
2017-11-01 09:31:56 +00:00
|
|
|
|
2018-03-03 13:39:39 +00:00
|
|
|
const managers = {};
|
2018-03-28 13:24:42 +00:00
|
|
|
const managerList = [
|
|
|
|
'bazel',
|
2018-03-28 18:12:56 +00:00
|
|
|
'circleci',
|
2018-03-28 13:24:42 +00:00
|
|
|
'docker',
|
|
|
|
'docker-compose',
|
|
|
|
'meteor',
|
|
|
|
'npm',
|
|
|
|
'nvm',
|
|
|
|
'travis',
|
|
|
|
];
|
2018-03-03 13:39:39 +00:00
|
|
|
for (const manager of managerList) {
|
|
|
|
// eslint-disable-next-line global-require,import/no-dynamic-require
|
|
|
|
managers[manager] = require(`./${manager}`);
|
|
|
|
}
|
2017-10-25 04:48:08 +00:00
|
|
|
|
2017-10-24 11:50:07 +00:00
|
|
|
module.exports = {
|
2017-10-25 04:00:07 +00:00
|
|
|
detectPackageFiles,
|
2018-03-03 13:39:39 +00:00
|
|
|
extractDependencies,
|
2018-03-04 15:09:12 +00:00
|
|
|
getManager,
|
2017-10-24 11:50:07 +00:00
|
|
|
getPackageUpdates,
|
2017-10-25 04:48:08 +00:00
|
|
|
getUpdatedPackageFiles,
|
2018-03-03 13:39:39 +00:00
|
|
|
resolvePackageFiles,
|
2017-10-24 11:50:07 +00:00
|
|
|
};
|
|
|
|
|
2017-11-03 08:25:18 +00:00
|
|
|
async function detectPackageFiles(config) {
|
2017-11-05 12:51:29 +00:00
|
|
|
logger.debug('detectPackageFiles()');
|
|
|
|
logger.trace({ config });
|
2017-11-03 08:25:18 +00:00
|
|
|
let packageFiles = [];
|
2017-11-07 10:46:10 +00:00
|
|
|
const fileList = (await platform.getFileList()).filter(
|
2017-11-01 09:31:56 +00:00
|
|
|
file =>
|
|
|
|
!config.ignorePaths.some(
|
|
|
|
ignorePath => file.includes(ignorePath) || minimatch(file, ignorePath)
|
|
|
|
)
|
2017-10-25 04:00:07 +00:00
|
|
|
);
|
2018-03-03 13:39:39 +00:00
|
|
|
for (const manager of managerList) {
|
|
|
|
logger.debug(`Detecting package files (${manager})`);
|
2018-03-30 15:00:51 +00:00
|
|
|
const { parentManager } = managers[manager];
|
|
|
|
// Check if the user has a whitelist of managers
|
|
|
|
if (
|
|
|
|
config.enabledManagers &&
|
|
|
|
config.enabledManagers.length &&
|
|
|
|
!(
|
|
|
|
config.enabledManagers.includes(manager) ||
|
|
|
|
config.enabledManagers.includes(parentManager)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
logger.debug(manager + ' is not on the enabledManagers list');
|
|
|
|
continue; // eslint-disable-line no-continue
|
|
|
|
}
|
|
|
|
// Check if the manager is manually disabled
|
2018-04-09 06:17:57 +00:00
|
|
|
if (config[manager].enabled === false) {
|
2018-03-21 05:02:54 +00:00
|
|
|
logger.debug(manager + ' is disabled');
|
2018-03-05 13:56:21 +00:00
|
|
|
continue; // eslint-disable-line no-continue
|
|
|
|
}
|
2018-04-03 04:52:04 +00:00
|
|
|
// Check if the parent is manually disabled
|
|
|
|
if (parentManager && config[parentManager].enabled === false) {
|
|
|
|
logger.debug(manager + ' parentManager is disabled');
|
|
|
|
continue; // eslint-disable-line no-continue
|
|
|
|
}
|
2018-04-09 06:17:57 +00:00
|
|
|
const files = [];
|
2018-04-18 19:19:00 +00:00
|
|
|
const { filePattern } = managers[manager];
|
|
|
|
logger.debug(`Using ${manager} file pattern: ${filePattern.toString()}`);
|
|
|
|
const allfiles = fileList.filter(file => file.match(filePattern));
|
2018-04-09 06:17:57 +00:00
|
|
|
logger.debug(`Found ${allfiles.length} files`);
|
|
|
|
for (const file of allfiles) {
|
|
|
|
const { contentPattern } = managers[manager];
|
|
|
|
if (contentPattern) {
|
|
|
|
const content = await platform.getFile(file);
|
|
|
|
if (content && content.match(contentPattern)) {
|
2018-03-04 19:03:52 +00:00
|
|
|
files.push(file);
|
|
|
|
}
|
2018-04-09 06:17:57 +00:00
|
|
|
} else {
|
|
|
|
files.push(file);
|
2018-03-04 19:03:52 +00:00
|
|
|
}
|
2018-03-04 15:34:55 +00:00
|
|
|
}
|
2018-03-03 13:39:39 +00:00
|
|
|
if (files.length) {
|
|
|
|
logger.info({ manager, files }, `Detected package files`);
|
2018-03-28 17:53:42 +00:00
|
|
|
packageFiles = packageFiles.concat(
|
|
|
|
files.map(packageFile => ({ packageFile, manager }))
|
|
|
|
);
|
2018-03-03 13:39:39 +00:00
|
|
|
}
|
2017-12-07 08:22:10 +00:00
|
|
|
}
|
2018-04-18 19:19:00 +00:00
|
|
|
logger.trace({ packageFiles }, 'All detected package files');
|
2017-11-03 08:25:18 +00:00
|
|
|
return packageFiles;
|
2017-10-25 04:00:07 +00:00
|
|
|
}
|
|
|
|
|
2018-03-03 13:39:39 +00:00
|
|
|
function extractDependencies(packageContent, config) {
|
|
|
|
logger.debug('manager.extractDependencies()');
|
|
|
|
return managers[config.manager].extractDependencies(packageContent, config);
|
|
|
|
}
|
|
|
|
|
2017-11-03 10:56:25 +00:00
|
|
|
function getPackageUpdates(config) {
|
2018-03-27 19:57:02 +00:00
|
|
|
logger.trace({ config }, 'manager.getPackageUpdates()');
|
2018-02-28 18:01:35 +00:00
|
|
|
const { manager } = config;
|
2018-03-03 13:39:39 +00:00
|
|
|
if (!managerList.includes(manager)) {
|
|
|
|
throw new Error('Unsupported package manager');
|
2017-10-24 11:50:07 +00:00
|
|
|
}
|
2018-03-03 13:39:39 +00:00
|
|
|
return managers[manager].getPackageUpdates(config);
|
2017-10-24 11:50:07 +00:00
|
|
|
}
|
2017-10-25 04:48:08 +00:00
|
|
|
|
|
|
|
async function getUpdatedPackageFiles(config) {
|
2018-03-03 13:39:39 +00:00
|
|
|
logger.debug('manager.getUpdatedPackageFiles()');
|
|
|
|
logger.trace({ config });
|
2017-10-25 04:48:08 +00:00
|
|
|
const updatedPackageFiles = {};
|
|
|
|
|
|
|
|
for (const upgrade of config.upgrades) {
|
2018-02-28 18:01:35 +00:00
|
|
|
const { manager } = upgrade;
|
2017-10-25 04:48:08 +00:00
|
|
|
if (upgrade.type !== 'lockFileMaintenance') {
|
|
|
|
const existingContent =
|
|
|
|
updatedPackageFiles[upgrade.packageFile] ||
|
2017-11-08 11:23:32 +00:00
|
|
|
(await platform.getFile(upgrade.packageFile, config.parentBranch));
|
2017-10-25 04:48:08 +00:00
|
|
|
let newContent = existingContent;
|
2018-03-30 04:05:00 +00:00
|
|
|
newContent = await managers[manager].updateDependency(
|
2018-03-03 13:39:39 +00:00
|
|
|
existingContent,
|
|
|
|
upgrade
|
|
|
|
);
|
2017-10-25 04:48:08 +00:00
|
|
|
if (!newContent) {
|
2017-12-27 14:20:32 +00:00
|
|
|
if (config.parentBranch) {
|
2017-10-25 04:48:08 +00:00
|
|
|
logger.info('Rebasing branch after error updating content');
|
|
|
|
return getUpdatedPackageFiles({
|
|
|
|
...config,
|
|
|
|
parentBranch: undefined,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
throw new Error('Error updating branch content and cannot rebase');
|
|
|
|
}
|
|
|
|
if (newContent !== existingContent) {
|
2017-12-27 14:20:32 +00:00
|
|
|
if (config.parentBranch) {
|
2017-10-25 04:48:08 +00:00
|
|
|
// This ensure it's always 1 commit from Renovate
|
|
|
|
logger.info('Need to update package file so will rebase first');
|
|
|
|
return getUpdatedPackageFiles({
|
|
|
|
...config,
|
|
|
|
parentBranch: undefined,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
logger.debug('Updating packageFile content');
|
|
|
|
updatedPackageFiles[upgrade.packageFile] = newContent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
parentBranch: config.parentBranch, // Need to overwrite original config
|
|
|
|
updatedPackageFiles: Object.keys(updatedPackageFiles).map(packageFile => ({
|
|
|
|
name: packageFile,
|
|
|
|
contents: updatedPackageFiles[packageFile],
|
|
|
|
})),
|
|
|
|
};
|
|
|
|
}
|
2018-03-03 13:39:39 +00:00
|
|
|
|
2018-03-04 15:09:12 +00:00
|
|
|
function getManager(filename) {
|
|
|
|
for (const manager of managerList) {
|
|
|
|
if (filename.match(managers[manager].filePattern)) {
|
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2018-03-03 13:39:39 +00:00
|
|
|
async function resolvePackageFiles(config) {
|
|
|
|
logger.debug('manager.resolvePackageFile()');
|
|
|
|
logger.trace({ config });
|
|
|
|
const allPackageFiles =
|
|
|
|
config.packageFiles && config.packageFiles.length
|
|
|
|
? config.packageFiles
|
|
|
|
: await detectPackageFiles(config);
|
|
|
|
logger.debug({ allPackageFiles }, 'allPackageFiles');
|
2018-03-30 05:38:38 +00:00
|
|
|
async function resolvePackageFile(p) {
|
|
|
|
let packageFile = typeof p === 'string' ? { packageFile: p } : p;
|
2018-03-03 13:39:39 +00:00
|
|
|
const fileName = packageFile.packageFile.split('/').pop();
|
2018-03-04 15:09:12 +00:00
|
|
|
packageFile.manager = packageFile.manager || getManager(fileName);
|
2018-03-30 05:38:38 +00:00
|
|
|
const { manager } = packageFile;
|
|
|
|
if (!manager) {
|
2018-03-03 13:39:39 +00:00
|
|
|
// Config error
|
|
|
|
const error = new Error('config-validation');
|
|
|
|
error.configFile = packageFile.packageFile;
|
|
|
|
error.validationError = 'Unknown file type';
|
|
|
|
error.validationMessage =
|
|
|
|
'Please correct the file name in your packageFiles array';
|
|
|
|
throw error;
|
|
|
|
}
|
2018-03-30 05:38:38 +00:00
|
|
|
if (managers[manager].resolvePackageFile) {
|
|
|
|
return managers[manager].resolvePackageFile(config, packageFile);
|
|
|
|
}
|
|
|
|
const { parentManager } = managers[manager];
|
|
|
|
const parentManagerConfig = parentManager ? config[parentManager] : {};
|
|
|
|
const managerConfig = mergeChildConfig(
|
|
|
|
parentManagerConfig,
|
|
|
|
config[manager]
|
|
|
|
);
|
|
|
|
packageFile = mergeChildConfig(managerConfig, packageFile);
|
|
|
|
logger.debug(
|
|
|
|
`Resolving packageFile ${JSON.stringify(packageFile.packageFile)}`
|
2018-03-03 13:39:39 +00:00
|
|
|
);
|
2018-03-30 05:38:38 +00:00
|
|
|
packageFile.content = await platform.getFile(packageFile.packageFile);
|
|
|
|
if (!packageFile.content) {
|
|
|
|
logger.debug('No packageFile content');
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return packageFile;
|
2018-03-03 13:39:39 +00:00
|
|
|
}
|
|
|
|
// TODO: throttle how many we resolve in parallel
|
|
|
|
const queue = allPackageFiles.map(p => resolvePackageFile(p));
|
|
|
|
let packageFiles = (await Promise.all(queue)).filter(p => p !== null);
|
|
|
|
logger.debug('Checking against path rules');
|
|
|
|
packageFiles = packageFiles.map(pf => {
|
|
|
|
let packageFile = { ...pf };
|
|
|
|
for (const pathRule of config.pathRules) {
|
|
|
|
/* eslint-disable no-loop-func */
|
|
|
|
if (
|
|
|
|
pathRule.paths.some(
|
|
|
|
rulePath =>
|
|
|
|
packageFile.packageFile.includes(rulePath) ||
|
|
|
|
minimatch(packageFile.packageFile, rulePath)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
logger.debug({ pathRule, packageFile }, 'Matched pathRule');
|
|
|
|
packageFile = mergeChildConfig(packageFile, pathRule);
|
|
|
|
delete packageFile.paths;
|
|
|
|
}
|
|
|
|
/* eslint-enable */
|
|
|
|
}
|
|
|
|
return packageFile;
|
|
|
|
});
|
|
|
|
|
|
|
|
return checkMonorepos({ ...config, packageFiles });
|
|
|
|
}
|