mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-09 13:26:10 +00:00
de0f02d00a
Previously, templates were in a subdirectory of `packages/embark`. Reorganize them so that they are member packages of the monorepo. This allows them to cleanly depend on other members of the monorepo, e.g. `embarkjs-connector-web3`. It is desirable for the templates, in the context of the monorepo, to specify embark as a dependency, to take advantage of `npx embark test` (and it's a "forward looking" setup re: how we plan to evolve embark). However, if embark were to specify the template packages as dependencies a circular relationship would be introduced, which is [unsupported by Lerna][circular]. Therefore, revise the template generator so that all templates are resolved / fetched at runtime, i.e. `boilerplate`, `demo`, and `simple` are no longer "built-ins" *per se*. This change won't be apparent to embark's users, but it does mean that the template generator won't work (in a production install of embark) if it can't connect to the npm registry, i.e. when the user runs `embark demo` or `embark new [--simple]`. When embark is inside the monorepo, templates are resolved and copied from the yarn workspace rather than being fetched from the registry, which is convenient for development. Also, any template dependencies that are members of the monorepo are linked into the copied template's `node_modules` rather than being installed from the registry, again for convenience. During template generation, remove scripts and dependencies that pertain only to membership in the monorepo; for now, that involves removing embark as a dependency since we're not quite ready for that arrangement to be the default, i.e. outside of the monorepo. Refactor the root scripts so that more of them can consistently be used with Lerna's filter options, e.g. `--scope` and `--ignore`. "Combo" scripts that don't support filtering generally have a `:full` postfix. Flip `clean` and `reset` scripts at the root and in the member packages for consistency re: Lerna's notion of `clean` and embark's notion of `reset`. Have each package run its `reset` script when its `clean` script is invoked (and that's all for now), relying on `lerna clean` to delete packages' `node_modules` in view of how Lerna's topological sorting works. Lift the implementation of `embark reset` into a private package in `packages/embark-reset` and make it a bundled dependency of embark. Packages in `dapps/*` depend on `embark-reset` directly and make use of it with `npx embark-reset` (but only in monorepo context). This removes a "wart" where reboots could show errors when embark's sources aren't already built in `packages/embark/dist`. Users will not notice any difference since `embark reset` works as before, transparently making use of the `embark-reset` package. The only downside to having it be a bundled dependency of embark is that bundled deps have all of their `node_modules` included in the tarball built with `npm pack` (that's why having the templates as bundled dependencies of embark isn't a viable approach). However, `embark-reset` only has one dependency, `rimraf`, which is a tiny module, so the cost seems acceptable. As part of the reorganization, move `test_dapps` into `dapps/tests` and `packages/embark/templates` into `dapps/templates`. Keep the directory names short but revise the package names to facilitate simple filtering with `embark-dapp-*`. Consolidate `.yarnrc` and `.gitignore` and clean up some redundant ignore listings. Scripts run with `--scope embark-dapp-*` use `--concurrency=1` to avoid conflicts that could arise over network ports. The `ci:full` and `qa:full` scripts use `--concurrency=1` in all scopes, for two reasons: resource limitations on Travis and AppVeyor result in slower runs with concurrency >1, and if something fails in those contexts it's easier to see what went wrong when Lerna's output isn't interleaved from a bunch of scripts in `packages/*`. Bump the Lerna version. [circular]: https://github.com/lerna/lerna/issues/1198#issuecomment-442278902
212 lines
6.5 KiB
JavaScript
212 lines
6.5 KiB
JavaScript
/* global __dirname process require */
|
||
|
||
const chalk = require('chalk');
|
||
const {execSync} = require('child_process');
|
||
const minimist = require('minimist');
|
||
const path = require('path');
|
||
const {prompt} = require('promptly');
|
||
const semver = require('semver');
|
||
|
||
const args = minimist(process.argv.slice(2));
|
||
|
||
const DEFAULT_BUMP = null;
|
||
const bump = args._[0] || DEFAULT_BUMP;
|
||
|
||
const DEFAULT_COMMIT_MSG = `chore(release): %v`;
|
||
const commitMsg = args['commit-message'] || DEFAULT_COMMIT_MSG;
|
||
|
||
const DEFAULT_DIST_TAG = `latest`;
|
||
const distTag = args['dist-tag'] || DEFAULT_DIST_TAG;
|
||
|
||
const DEFAULT_GIT_REMOTE = `origin`;
|
||
const remote = args['git-remote'] || DEFAULT_GIT_REMOTE;
|
||
|
||
const DEFAULT_PRE_ID = null;
|
||
const preId = args.preid || DEFAULT_PRE_ID;
|
||
|
||
const DEFAULT_RELEASE_BRANCH = `master`;
|
||
const branch = args['release-branch'] || DEFAULT_RELEASE_BRANCH;
|
||
|
||
const DEFAULT_SIGN = false;
|
||
const sign = args.sign || DEFAULT_SIGN;
|
||
|
||
const cyan = (str) => chalk.cyan(str);
|
||
const execSyncInherit = (cmd) => execSync(cmd, {stdio: 'inherit'});
|
||
const log = (mark, str, which = 'log') => console[which](
|
||
mark, str.filter(s => !!s).join(` `)
|
||
);
|
||
const logError = (...str) => log(chalk.red(`✘`), str, 'error');
|
||
const logInfo = (...str) => log(chalk.blue(`ℹ`), str);
|
||
const logSuccess = (...str) => log(chalk.green(`✔`), str);
|
||
const logWarning = (...str) => log(chalk.yellow('‼︎'), str);
|
||
|
||
const failMsg = `${chalk.red(`RELEASE FAILED!`)} Stopping right here.`;
|
||
|
||
const reportSetting = (desc, val, def) => {
|
||
logInfo(`${desc} is set to ${cyan(val)}${val === def ? ` (default).`: `.`}`);
|
||
};
|
||
|
||
const runCommand = (cmd, inherit = true, display) => {
|
||
logInfo(`Running command ${cyan(display || cmd)}.`);
|
||
let out;
|
||
if (inherit) {
|
||
execSyncInherit(cmd);
|
||
} else {
|
||
out = execSync(cmd);
|
||
}
|
||
return out;
|
||
};
|
||
|
||
(async () => {
|
||
try {
|
||
let DEFAULT_REGISTRY, registry;
|
||
const lernaJsonPath = path.join(__dirname, '../lerna.json');
|
||
try {
|
||
const lernaJson = require(lernaJsonPath);
|
||
|
||
DEFAULT_REGISTRY = lernaJson.command.publish.registry;
|
||
if (!DEFAULT_REGISTRY) throw new Error('missing registry in lerna.json');
|
||
registry = args.registry || DEFAULT_REGISTRY;
|
||
} catch (e) {
|
||
console.error(e.stack);
|
||
logError(
|
||
`Could not read values from ${cyan(lernaJsonPath)}.`,
|
||
`Please check the error above.`
|
||
);
|
||
throw new Error();
|
||
}
|
||
|
||
logInfo(`Checking the working tree...`);
|
||
|
||
try {
|
||
runCommand(`npm run --silent cwtree`, true, `npm run cwtree`);
|
||
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();
|
||
}
|
||
|
||
reportSetting(`Release branch`, branch, DEFAULT_RELEASE_BRANCH);
|
||
logInfo(`Determining the current branch...`);
|
||
|
||
let currentBranch;
|
||
try {
|
||
currentBranch = runCommand(`git rev-parse --abbrev-ref HEAD`, false)
|
||
.toString()
|
||
.trim();
|
||
} catch (e) {
|
||
logError(`Could not determine the branch. Please check the error above.`);
|
||
throw new Error();
|
||
}
|
||
|
||
if (currentBranch === branch) {
|
||
logSuccess(`Current branch and release branch are the same.`);
|
||
} else {
|
||
logError(
|
||
`Current branch ${cyan(currentBranch)} is not the same as release`,
|
||
`branch ${cyan(branch)}. Please checkout the release branch before`,
|
||
`rerunning this script or rerun with`,
|
||
`${cyan(`--release-branch ${currentBranch}`)}.`
|
||
);
|
||
throw new Error();
|
||
}
|
||
|
||
reportSetting(`Git remote`, remote, DEFAULT_GIT_REMOTE);
|
||
logInfo(
|
||
`Fetching commits from ${cyan(remote)}`,
|
||
`to compare local and remote branches...`
|
||
);
|
||
|
||
try {
|
||
runCommand(`git fetch ${remote}`, false);
|
||
} catch (e) {
|
||
logError(`Could not fetch latest commits. Please check the error above.`);
|
||
throw new Error();
|
||
}
|
||
|
||
let localRef, remoteRef;
|
||
try {
|
||
localRef = runCommand(`git rev-parse ${branch}`, false).toString().trim();
|
||
remoteRef = (
|
||
runCommand(`git rev-parse ${remote}/${branch}`, false).toString().trim()
|
||
);
|
||
} catch (e) {
|
||
logError(`A problem occured. Please check the error above.`);
|
||
throw new Error();
|
||
}
|
||
|
||
if (localRef === remoteRef) {
|
||
logSuccess(`Local branch is in sync with remote branch.`);
|
||
} else {
|
||
logError(
|
||
`Local branch ${cyan(branch)} is not in sync with`,
|
||
`${cyan(`${remote}/${branch}`)}.`,
|
||
`Please sync branches before rerunning this script.`
|
||
);
|
||
throw new Error();
|
||
}
|
||
|
||
logInfo(
|
||
`It's time to run the QA suite, this will take awhile...`
|
||
);
|
||
|
||
try {
|
||
runCommand(`npm run qa:full`);
|
||
logSuccess(`All steps succeeded in the QA suite.`);
|
||
} catch (e) {
|
||
logError(`A step failed in the QA suite. Please check the error above.`);
|
||
throw new Error();
|
||
}
|
||
|
||
logInfo(`Publishing with Lerna...`);
|
||
if (bump) reportSetting(`Version bump`, bump, DEFAULT_BUMP);
|
||
if (preId) reportSetting(`Prerelease identifier`, preId, DEFAULT_PRE_ID);
|
||
reportSetting(`Package distribution tag`, distTag, DEFAULT_DIST_TAG);
|
||
reportSetting(`Commit message format`, commitMsg, DEFAULT_COMMIT_MSG);
|
||
reportSetting(`Signature option`, sign, DEFAULT_SIGN);
|
||
reportSetting(`Package registry`, registry, DEFAULT_REGISTRY);
|
||
|
||
const lernaPublish = [
|
||
`lerna publish`,
|
||
bump || ``,
|
||
(preId && `--preid ${preId}`) || ``,
|
||
`--dist-tag ${distTag}`,
|
||
`--conventional-commits`,
|
||
`--message "${commitMsg}"`,
|
||
(sign && `--sign-git-commit`) || ``,
|
||
(sign && `--sign-git-tag`) || ``,
|
||
`--git-remote ${remote}`,
|
||
`--registry ${registry}`
|
||
].filter(str => !!str).join(` `);
|
||
|
||
try {
|
||
runCommand(lernaPublish);
|
||
if (localRef ===
|
||
runCommand(`git rev-parse ${branch}`, false).toString().trim()) {
|
||
logWarning(
|
||
chalk.yellow(`RELEASE STOPPED!`),
|
||
`No commit or tag was created. No packages were published.`
|
||
);
|
||
process.exit(0);
|
||
}
|
||
} catch (e) {
|
||
console.error();
|
||
logError(`A problem occured. Please check the error above.`);
|
||
throw new Error();
|
||
}
|
||
|
||
logSuccess(`${chalk.green(`RELEASE SUCCEEDED!`)} Woohoo! Done.`);
|
||
} catch (e) {
|
||
logError(
|
||
failMsg,
|
||
`Make sure to clean up the working tree and local/remote commits and`,
|
||
`tags as necessary. Check the package registry to verify no packages`,
|
||
`were published.`
|
||
);
|
||
process.exit(1);
|
||
}
|
||
})();
|