2017-02-14 07:08:40 +00:00
|
|
|
const logger = require('winston');
|
|
|
|
const path = require('path');
|
|
|
|
const handlebars = require('handlebars');
|
|
|
|
const packageJsonHelper = require('../helpers/package-json');
|
|
|
|
const yarnHelper = require('../helpers/yarn');
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
getParentBranch,
|
|
|
|
getYarnLockFile,
|
|
|
|
ensureBranch,
|
2017-04-17 02:54:42 +00:00
|
|
|
maintainYarnLock,
|
2017-02-14 07:08:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
async function getParentBranch(branchName, config) {
|
|
|
|
// Check if branch exists
|
|
|
|
if (await config.api.branchExists(branchName) === false) {
|
|
|
|
logger.verbose(`Creating new branch ${branchName}`);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
logger.debug(`${branchName} already exists`);
|
|
|
|
// Check for existing PR
|
|
|
|
const pr = await config.api.getBranchPr(branchName);
|
|
|
|
// Decide if we need to rebase
|
|
|
|
if (!pr) {
|
|
|
|
logger.debug(`No PR found for ${branchName}`);
|
|
|
|
// We can't tell if this branch can be rebased so better not
|
|
|
|
return branchName;
|
|
|
|
}
|
|
|
|
if (pr.isUnmergeable) {
|
|
|
|
logger.debug('PR is unmergeable');
|
|
|
|
if (pr.canRebase) {
|
|
|
|
// Only supported by GitHub
|
|
|
|
// Setting parentBranch back to undefined means that we'll use the default branch
|
|
|
|
logger.debug(`Rebasing branch ${branchName}`);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
// Don't do anything different, but warn
|
|
|
|
logger.verbose(`Cannot rebase branch ${branchName}`);
|
|
|
|
}
|
|
|
|
if (pr.isStale && config.rebaseStalePrs) {
|
|
|
|
logger.verbose(`Existing PR for ${branchName} is stale`);
|
|
|
|
if (pr.canRebase) {
|
|
|
|
// Only supported by GitHub
|
|
|
|
// Setting parentBranch back to undefined means that we'll use the default branch
|
|
|
|
logger.debug(`Rebasing branch ${branchName}`);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
// Don't do anything different, but warn
|
|
|
|
logger.verbose(`Cannot rebase branch ${branchName}`);
|
|
|
|
}
|
|
|
|
logger.debug(`Existing ${branchName} does not need rebasing`);
|
|
|
|
return branchName;
|
|
|
|
}
|
|
|
|
|
2017-04-15 18:32:01 +00:00
|
|
|
async function getYarnLockFile(packageFile, packageContent, api) {
|
2017-02-14 07:08:40 +00:00
|
|
|
// Detect if a yarn.lock file is in use
|
2017-04-15 18:32:01 +00:00
|
|
|
const yarnLockFileName = path.join(path.dirname(packageFile), 'yarn.lock');
|
|
|
|
if (!await api.getFileContent(yarnLockFileName)) {
|
2017-02-14 07:08:40 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-04-15 18:32:01 +00:00
|
|
|
// Copy over custom config commitFiles
|
|
|
|
const npmrcContent = await api.getFileContent('.npmrc');
|
|
|
|
const yarnrcContent = await api.getFileContent('.yarnrc');
|
2017-02-14 07:08:40 +00:00
|
|
|
// Generate yarn.lock using shell command
|
|
|
|
const newYarnLockContent =
|
2017-04-15 18:32:01 +00:00
|
|
|
await yarnHelper.generateLockFile(packageContent, npmrcContent, yarnrcContent);
|
2017-02-14 07:08:40 +00:00
|
|
|
// Return file object
|
|
|
|
return ({
|
|
|
|
name: yarnLockFileName,
|
|
|
|
contents: newYarnLockContent,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-04-17 02:54:42 +00:00
|
|
|
async function maintainYarnLock(inputConfig) {
|
|
|
|
logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`);
|
|
|
|
const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile);
|
|
|
|
const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock');
|
|
|
|
logger.debug(`Checking for ${yarnLockFileName}`);
|
|
|
|
const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName);
|
|
|
|
logger.silly(`existingYarnLock:\n${existingYarnLock}`);
|
|
|
|
if (!existingYarnLock) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
logger.debug('Found existing yarn.lock file');
|
|
|
|
const newYarnLock =
|
|
|
|
await getYarnLockFile(inputConfig.packageFile, packageContent, inputConfig.api);
|
|
|
|
logger.silly(`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;
|
|
|
|
}
|
|
|
|
|
2017-02-14 07:08:40 +00:00
|
|
|
// Ensure branch exists with appropriate content
|
2017-04-15 18:32:01 +00:00
|
|
|
async function ensureBranch(upgrades) {
|
2017-04-15 20:06:15 +00:00
|
|
|
logger.debug(`ensureBranch(${JSON.stringify(upgrades)})`);
|
2017-04-15 18:32:01 +00:00
|
|
|
// Use the first upgrade for all the templates
|
|
|
|
const branchName = handlebars.compile(upgrades[0].branchName)(upgrades[0]);
|
2017-02-14 07:08:40 +00:00
|
|
|
// parentBranch is the branch we will base off
|
|
|
|
// If undefined, this will mean the defaultBranch
|
2017-04-15 18:32:01 +00:00
|
|
|
const parentBranch = await module.exports.getParentBranch(branchName, upgrades[0]);
|
|
|
|
const commitMessage = handlebars.compile(upgrades[0].commitMessage)(upgrades[0]);
|
|
|
|
const api = upgrades[0].api;
|
|
|
|
const packageFiles = {};
|
2017-04-17 02:54:42 +00:00
|
|
|
const commitFiles = [];
|
2017-04-15 18:32:01 +00:00
|
|
|
for (const upgrade of upgrades) {
|
2017-04-17 02:54:42 +00:00
|
|
|
if (upgrade.upgradeType === 'maintainYarnLock') {
|
|
|
|
const newYarnLock = await maintainYarnLock(upgrade);
|
|
|
|
if (newYarnLock) {
|
|
|
|
commitFiles.push(newYarnLock);
|
|
|
|
}
|
2017-04-15 18:32:01 +00:00
|
|
|
} else {
|
2017-04-17 02:54:42 +00:00
|
|
|
// See if this is the first time editing this file
|
|
|
|
if (!packageFiles[upgrade.packageFile]) {
|
|
|
|
// If we are rebasing then existing content will be from master
|
|
|
|
packageFiles[upgrade.packageFile] =
|
|
|
|
await api.getFileContent(upgrade.packageFile, parentBranch);
|
|
|
|
}
|
|
|
|
const newContent = packageJsonHelper.setNewValue(
|
|
|
|
packageFiles[upgrade.packageFile],
|
|
|
|
upgrade.depType,
|
|
|
|
upgrade.depName,
|
|
|
|
upgrade.newVersion);
|
|
|
|
if (packageFiles[upgrade.packageFile] === newContent) {
|
|
|
|
logger.debug('packageFile content unchanged');
|
|
|
|
delete packageFiles[upgrade.packageFile];
|
|
|
|
} else {
|
|
|
|
logger.debug('Updating packageFile content');
|
|
|
|
packageFiles[upgrade.packageFile] = newContent;
|
|
|
|
}
|
2017-04-15 18:32:01 +00:00
|
|
|
}
|
2017-02-14 07:08:40 +00:00
|
|
|
}
|
2017-04-15 18:32:01 +00:00
|
|
|
if (Object.keys(packageFiles).length > 0) {
|
2017-04-17 02:54:42 +00:00
|
|
|
logger.debug(`${Object.keys(packageFiles).length} package file(s) need updating.`);
|
2017-04-15 18:32:01 +00:00
|
|
|
for (const packageFile of Object.keys(packageFiles)) {
|
2017-04-17 02:54:42 +00:00
|
|
|
logger.debug(`Adding ${packageFile}`);
|
2017-04-15 18:32:01 +00:00
|
|
|
commitFiles.push({
|
|
|
|
name: packageFile,
|
|
|
|
contents: packageFiles[packageFile],
|
|
|
|
});
|
|
|
|
const yarnLockFile =
|
|
|
|
await module.exports.getYarnLockFile(packageFile, packageFiles[packageFile], api);
|
|
|
|
if (yarnLockFile) {
|
|
|
|
// Add new yarn.lock file too
|
2017-04-17 02:54:42 +00:00
|
|
|
logger.debug(`Adding ${yarnLockFile.name}`);
|
2017-04-15 18:32:01 +00:00
|
|
|
commitFiles.push(yarnLockFile);
|
|
|
|
}
|
|
|
|
}
|
2017-04-17 02:54:42 +00:00
|
|
|
}
|
|
|
|
if (commitFiles.length) {
|
|
|
|
logger.debug(`Commit ${commitFiles.length} files to branch ${branchName}`);
|
2017-04-15 18:32:01 +00:00
|
|
|
// API will know whether to create new branch or not
|
|
|
|
await api.commitFilesToBranch(branchName, commitFiles, commitMessage, parentBranch);
|
2017-04-17 02:54:42 +00:00
|
|
|
return true;
|
2017-02-14 07:08:40 +00:00
|
|
|
}
|
2017-04-17 02:54:42 +00:00
|
|
|
logger.debug(`No files to commit to branch ${branchName}`);
|
2017-04-17 04:46:24 +00:00
|
|
|
return api.branchExists(branchName);
|
2017-02-14 07:08:40 +00:00
|
|
|
}
|