embark/scripts/release.js

190 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* global process require */
const chalk = require('chalk');
const {execSync} = require('child_process');
const minimist = require('minimist');
const {prompt} = require('promptly');
const standardVersion = require('standard-version');
const args = minimist(process.argv.slice(2));
const DEFAULT_UPSTREAM_REPO_BRANCH = 'master';
const DEFAULT_UPSTREAM_REPO_ORIGIN = 'origin';
const branch = args['repo-branch'] || DEFAULT_UPSTREAM_REPO_BRANCH;
const origin = args['repo-origin'] || DEFAULT_UPSTREAM_REPO_ORIGIN;
const distTag = args['npm-dist-tag'];
const dryRun = args['dry-run'];
const prerelease = args.prerelease;
const releaseAs = args['release-as'];
const sign = args.sign;
// eslint-disable-next-line no-confusing-arrow
const dryRunMaybe = () => dryRun ? leftPad1(chalk.yellow('(DRY RUN)')) : '';
const execSyncInherit = (cmd) => execSync(cmd, {stdio: 'inherit'});
// eslint-disable-next-line no-confusing-arrow
const leftPad1 = (str) => ' ' + str;
// eslint-disable-next-line no-confusing-arrow
const leftPad1Maybe = (str) => str ? leftPad1(str) : str;
const log = (mark, str) => console.log(mark, str.filter(s => !!s).join(' '));
const logError = (...str) => log(chalk.red('✘'), str);
const logInfo = (...str) => log(chalk.blue(''), str);
const logSuccess = (...str) => log(chalk.green('✔'), str);
const logWarning = (...str) => log(chalk.yellow('‼︎'), str);
const yesNoValidator = (input) => {
const _input = input && input[0].toLowerCase();
if (!['y', 'n'].includes(_input)) {
throw new Error(chalk.red('✘') + leftPad1(`Please answer [y]es or [n]o.`));
}
return _input;
};
const promptOpts = {default: 'blank', validator: yesNoValidator};
const proceedAnywayPrompt = async () => {
let answer = await prompt(
`${chalk.yellow('⁉︎')} Proceed anyway? [y/n]`,
promptOpts
);
if (answer === 'n') {
logWarning(`Stopping right here.`);
process.exit(0);
}
};
const dryRunPrompt = async () => {
let answer = await prompt(
`${chalk.blue('⁇')} This is ${chalk.yellow('NOT')} a --dry-run.` +
leftPad1(`Did you complete a successful --dry-run first? [y/n]`),
promptOpts
);
if (answer === 'n') await proceedAnywayPrompt();
};
(async () => {
try {
if (!dryRun) await dryRunPrompt();
logInfo(`Determining the current branch...`);
let currentBranch;
try {
currentBranch = execSync(`git rev-parse --abbrev-ref HEAD`)
.toString()
.trim();
} catch (e) {
logError(`Couldn't determine the branch. Please check the error above.`);
throw new Error();
}
if (currentBranch !== branch) {
logError(
`Current branch '${currentBranch}' is not the same as release branch`,
`'${branch}'. Please checkout the release branch before rerunning this`,
`script or rerun with '--repo-branch ${currentBranch}'.`
);
throw new Error();
}
logSuccess(`Current branch and release branch are the same.`);
logInfo(`Checking the working tree...`);
try {
execSyncInherit(`npm run --silent check-working-tree`);
logSuccess(`Working tree is clean.`);
} catch (e) {
logError(
`Working tree is dirty or has untracked files. Please make necessary`,
`changes or commits before rerunning this script.`
);
throw new Error();
}
logInfo(
`Fetching from origin '${origin}' to compare local and remote branches...`
);
try {
execSyncInherit(`git fetch ${origin}`);
} catch (e) {
logError(`Couldn't fetch latest commits. Please check the error above.`);
throw new Error();
}
let localRef, originRef;
try {
localRef = execSync(`git rev-parse ${branch}`).toString();
originRef = execSync(`git rev-parse ${origin}/${branch}`).toString();
} catch (e) {
logError(`A problem occured. Please check the error above.`);
throw new Error();
}
if (localRef !== originRef) {
logError(
`Local branch '${branch}' is not in sync with '${origin}/${branch}'.`,
`Please sync branches before rerunning this script.`
);
throw new Error();
}
logSuccess(`Local branch is in sync with remote branch.`);
logInfo(`Running Standard Version${dryRunMaybe()}...`);
await standardVersion({
dryRun,
prerelease,
releaseAs,
sign
});
logInfo(`Publishing new Embark version on npm${dryRunMaybe()}...`);
const npmPublishCommand = [
`npm publish`,
leftPad1Maybe(`${distTag ? `--tag ${distTag}` : ''}`),
leftPad1Maybe(`${dryRun ? '--dry-run' : ''}`)
].join('');
try {
execSyncInherit(npmPublishCommand);
logSuccess(`Successfully published latest version${dryRunMaybe()}.`);
} catch (e) {
logError(
`Couldn't publish version on npm${dryRunMaybe()}.`,
`Please check the error above.`
);
throw new Error();
}
logInfo(
`Pushing release commit and tag to origin '${origin}' on branch`,
`'${branch}'${dryRunMaybe()}...`
);
const gitPushCommand = [
`git push --follow-tags ${origin} ${branch}`,
leftPad1Maybe(`${dryRun ? '--dry-run' : ''}`)
].join('');
try {
execSyncInherit(gitPushCommand);
logSuccess(`Successfully pushed${dryRunMaybe()}.`);
} catch (e) {
logError(
`Couldn't push${dryRunMaybe()}. Please check the error above.`
);
throw new Error();
}
logSuccess(`Woohoo! Done${dryRunMaybe()}.`);
} catch (e) {
logError(
`Stopping right here${dryRunMaybe()}.`,
dryRun ? '' : `Make sure to clean up commits and tags as necessary.`
);
process.exit(1);
}
})();