2017-02-14 07:08:40 +00:00
|
|
|
const handlebars = require('handlebars');
|
2017-06-29 05:29:41 +00:00
|
|
|
const changelogHelper = require('./changelog');
|
2017-06-22 13:14:42 +00:00
|
|
|
const showdown = require('showdown');
|
|
|
|
|
|
|
|
const converter = new showdown.Converter();
|
|
|
|
converter.setFlavor('github');
|
2017-02-14 07:08:40 +00:00
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
ensurePr,
|
2017-04-20 11:01:23 +00:00
|
|
|
checkAutoMerge,
|
2017-02-14 07:08:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Ensures that PR exists with matching title/body
|
2017-07-07 09:45:48 +00:00
|
|
|
async function ensurePr(inputConfig, logger, errors, warnings) {
|
|
|
|
logger.trace({ config: inputConfig }, 'ensurePr');
|
2017-06-13 09:08:37 +00:00
|
|
|
// If there is a group, it will use the config of the first upgrade in the array
|
2017-07-07 09:45:48 +00:00
|
|
|
const config = Object.assign({}, inputConfig);
|
|
|
|
const upgrades = config.upgrades;
|
2017-06-13 14:49:27 +00:00
|
|
|
config.upgrades = [];
|
2017-07-07 09:45:48 +00:00
|
|
|
const branchName = config.branchName;
|
2017-07-05 05:02:25 +00:00
|
|
|
const branchStatus = await config.api.getBranchStatus(
|
|
|
|
branchName,
|
|
|
|
config.requiredStatusChecks
|
|
|
|
);
|
2017-04-17 04:46:24 +00:00
|
|
|
|
2017-06-08 04:18:21 +00:00
|
|
|
// Only create a PR if a branch automerge has failed
|
|
|
|
if (config.automergeEnabled && config.automergeType.startsWith('branch')) {
|
2017-06-16 13:24:59 +00:00
|
|
|
logger.debug(
|
|
|
|
`Branch is configured for branch automerge, branchStatus is: ${branchStatus}`
|
|
|
|
);
|
|
|
|
if (branchStatus === 'failure') {
|
2017-06-08 04:18:21 +00:00
|
|
|
logger.debug(`Branch tests failed, so will create PR`);
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2017-04-17 04:46:24 +00:00
|
|
|
if (config.prCreation === 'status-success') {
|
|
|
|
logger.debug('Checking branch combined status');
|
|
|
|
if (branchStatus !== 'success') {
|
|
|
|
logger.debug(`Branch status is "${branchStatus}" - not creating PR`);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
logger.debug('Branch status success');
|
|
|
|
} else if (config.prCreation === 'not-pending') {
|
|
|
|
logger.debug('Checking branch combined status');
|
|
|
|
if (branchStatus === 'pending' || branchStatus === 'running') {
|
|
|
|
logger.debug(`Branch status is "${branchStatus}" - not creating PR`);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
logger.debug('Branch status success');
|
|
|
|
}
|
|
|
|
|
2017-06-13 14:49:27 +00:00
|
|
|
const processedUpgrades = [];
|
|
|
|
|
2017-02-14 07:08:40 +00:00
|
|
|
// Get changelog and then generate template strings
|
2017-06-05 08:21:02 +00:00
|
|
|
for (const upgrade of upgrades) {
|
2017-06-13 14:49:27 +00:00
|
|
|
const upgradeKey = `${upgrade.depName}-${upgrade.changeLogFromVersion}-${upgrade.changeLogToVersion}`;
|
|
|
|
if (processedUpgrades.indexOf(upgradeKey) !== -1) {
|
|
|
|
continue; // eslint-disable-line no-continue
|
|
|
|
}
|
|
|
|
processedUpgrades.push(upgradeKey);
|
|
|
|
|
2017-06-13 09:08:37 +00:00
|
|
|
const logJSON = await changelogHelper.getChangeLogJSON(
|
2017-06-05 08:21:02 +00:00
|
|
|
upgrade.depName,
|
|
|
|
upgrade.changeLogFromVersion,
|
2017-06-22 07:03:36 +00:00
|
|
|
upgrade.changeLogToVersion,
|
|
|
|
logger
|
2017-06-05 08:21:02 +00:00
|
|
|
);
|
2017-06-13 09:08:37 +00:00
|
|
|
// Store changelog markdown for backwards compatibility
|
2017-06-15 18:57:18 +00:00
|
|
|
if (logJSON) {
|
|
|
|
upgrade.githubName = logJSON.project.github;
|
|
|
|
upgrade.releases = [];
|
|
|
|
logJSON.versions.forEach(version => {
|
|
|
|
const release = Object.assign({}, version);
|
|
|
|
release.date = version.date.toISOString().slice(0, 10);
|
|
|
|
release.commits = [];
|
|
|
|
if (release.changes) {
|
|
|
|
release.changes.forEach(change => {
|
|
|
|
const commit = Object.assign({}, change);
|
|
|
|
delete commit.date;
|
|
|
|
commit.shortSha = change.sha.slice(0, 7);
|
|
|
|
commit.url = `${logJSON.project.repository}/commit/${change.sha}`;
|
|
|
|
if (change.message) {
|
|
|
|
commit.message = change.message.split('\n')[0];
|
|
|
|
const re = /([\s(])#(\d+)([)\s]?)/g;
|
|
|
|
commit.message = commit.message.replace(
|
|
|
|
re,
|
|
|
|
`$1[#$2](${upgrade.repositoryUrl}/issues/$2)$3`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
release.commits.push(commit);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
upgrade.releases.push(release);
|
|
|
|
});
|
|
|
|
}
|
2017-06-13 14:49:27 +00:00
|
|
|
config.upgrades.push(upgrade);
|
2017-06-05 08:21:02 +00:00
|
|
|
}
|
2017-06-13 09:08:37 +00:00
|
|
|
|
|
|
|
// Update the config object
|
|
|
|
Object.assign(config, upgrades[0]);
|
2017-07-04 11:52:23 +00:00
|
|
|
if (errors && errors.length) {
|
|
|
|
config.hasErrors = true;
|
|
|
|
config.errors = errors;
|
|
|
|
}
|
|
|
|
if (warnings && warnings.length) {
|
|
|
|
config.hasWarnings = true;
|
|
|
|
config.warnings = warnings;
|
|
|
|
}
|
2017-06-13 09:08:37 +00:00
|
|
|
|
2017-02-14 07:08:40 +00:00
|
|
|
const prTitle = handlebars.compile(config.prTitle)(config);
|
2017-06-22 13:14:42 +00:00
|
|
|
const prBodyMarkdown = handlebars.compile(config.prBody)(config);
|
|
|
|
const prBody = converter.makeHtml(prBodyMarkdown);
|
2017-02-14 07:08:40 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
// Check if existing PR exists
|
|
|
|
const existingPr = await config.api.getBranchPr(branchName);
|
|
|
|
if (existingPr) {
|
|
|
|
// Check if existing PR needs updating
|
|
|
|
if (existingPr.title === prTitle && existingPr.body === prBody) {
|
2017-06-20 06:02:17 +00:00
|
|
|
logger.info(`${existingPr.displayNumber} does not need updating`);
|
2017-02-14 07:08:40 +00:00
|
|
|
return existingPr;
|
|
|
|
}
|
|
|
|
// PR must need updating
|
|
|
|
await config.api.updatePr(existingPr.number, prTitle, prBody);
|
|
|
|
logger.info(`Updated ${existingPr.displayNumber}`);
|
|
|
|
return existingPr;
|
|
|
|
}
|
|
|
|
logger.debug(`Creating PR for branch ${branchName}`);
|
|
|
|
const pr = await config.api.createPr(branchName, prTitle, prBody);
|
|
|
|
if (config.labels.length > 0) {
|
|
|
|
await config.api.addLabels(pr.number, config.labels);
|
|
|
|
}
|
2017-06-08 04:18:21 +00:00
|
|
|
// Skip assign and review if automerging PR
|
|
|
|
if (config.automergeEnabled && config.automergeType === 'pr') {
|
|
|
|
logger.debug(
|
|
|
|
`Skipping assignees and reviewers as automerge=${config.automerge}`
|
|
|
|
);
|
|
|
|
} else {
|
2017-04-21 05:23:36 +00:00
|
|
|
if (config.assignees.length > 0) {
|
|
|
|
await config.api.addAssignees(pr.number, config.assignees);
|
|
|
|
}
|
|
|
|
if (config.reviewers.length > 0) {
|
|
|
|
await config.api.addReviewers(pr.number, config.reviewers);
|
|
|
|
}
|
2017-02-14 07:08:40 +00:00
|
|
|
}
|
|
|
|
logger.info(`Created ${pr.displayNumber}`);
|
|
|
|
return pr;
|
|
|
|
} catch (error) {
|
|
|
|
logger.error('Failed to ensure PR:', error);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2017-04-20 11:01:23 +00:00
|
|
|
|
2017-06-22 07:03:36 +00:00
|
|
|
async function checkAutoMerge(pr, config, logger) {
|
2017-07-05 05:02:25 +00:00
|
|
|
logger.trace({ config }, 'checkAutoMerge');
|
2017-04-20 11:01:23 +00:00
|
|
|
logger.debug(`Checking #${pr.number} for automerge`);
|
2017-06-08 04:18:21 +00:00
|
|
|
if (config.automergeEnabled && config.automergeType === 'pr') {
|
2017-06-20 06:02:17 +00:00
|
|
|
logger.info('PR is configured for automerge');
|
2017-04-20 11:01:23 +00:00
|
|
|
// Return if PR not ready for automerge
|
2017-07-05 05:02:25 +00:00
|
|
|
if (pr.mergeable !== true) {
|
|
|
|
logger.info('PR is not mergeable');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (config.requiredStatusChecks && pr.mergeable_state === 'unstable') {
|
|
|
|
logger.info('PR mergeable state is unstable');
|
2017-04-20 11:01:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Check branch status
|
2017-07-05 05:02:25 +00:00
|
|
|
const branchStatus = await config.api.getBranchStatus(
|
|
|
|
pr.head.ref,
|
|
|
|
config.requiredStatusChecks
|
|
|
|
);
|
2017-04-20 11:01:23 +00:00
|
|
|
logger.debug(`branchStatus=${branchStatus}`);
|
|
|
|
if (branchStatus !== 'success') {
|
2017-06-20 06:02:17 +00:00
|
|
|
logger.info('Branch status is not "success"');
|
2017-04-20 11:01:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Let's merge this
|
|
|
|
logger.info(`Automerging #${pr.number}`);
|
|
|
|
await config.api.mergePr(pr);
|
|
|
|
} else {
|
2017-06-20 06:02:17 +00:00
|
|
|
logger.debug('No automerge');
|
2017-04-20 11:01:23 +00:00
|
|
|
}
|
|
|
|
}
|