jazelle/index.js (316 lines of code) (raw):

// @flow const {resolve} = require('path'); const {getRootDir} = require('./utils/get-root-dir.js'); const {parse} = require('./utils/parse-argv.js'); const {cli} = require('./utils/cli.js'); const {version} = require('./commands/version.js'); const {init} = require('./commands/init.js'); const {scaffold} = require('./commands/scaffold.js'); const {install} = require('./commands/install.js'); const {ci} = require('./commands/ci.js'); const {add} = require('./commands/add.js'); const {remove} = require('./commands/remove.js'); const {upgrade} = require('./commands/upgrade.js'); const {dedupe} = require('./commands/dedupe.js'); const {prune} = require('./commands/prune.js'); const {purge} = require('./commands/purge.js'); const {check} = require('./commands/check.js'); const {outdated} = require('./commands/outdated.js'); const {resolutions} = require('./commands/resolutions.js'); const {align} = require('./commands/align.js'); const {localize} = require('./commands/localize.js'); const {changes} = require('./commands/changes.js'); const {plan} = require('./commands/plan.js'); const {batch} = require('./commands/batch.js'); const {build} = require('./commands/build.js'); const {dev} = require('./commands/dev.js'); const {test} = require('./commands/test.js'); const {lint} = require('./commands/lint.js'); const {flow} = require('./commands/flow.js'); const {start} = require('./commands/start.js'); const {node} = require('./commands/node.js'); const {yarn} = require('./commands/yarn.js'); const {exec} = require('./commands/exec.js'); const {each} = require('./commands/each.js'); const {binPath} = require('./commands/bin-path.js'); const {bazel} = require('./commands/bazel.js'); const {bump} = require('./commands/bump.js'); const {doctor} = require('./commands/doctor.js'); const {script} = require('./commands/script.js'); const { reportMismatchedTopLevelDeps, } = require('./utils/report-mismatched-top-level-deps.js'); const {getBinaryPath} = require('./utils/binary-paths.js'); const {findChangedTargets} = require('./utils/find-changed-targets.js'); const {getTestGroups} = require('./utils/get-test-groups.js'); /*:: export type RunCLI = (Array<string>) => Promise<void>; */ const runCLI /*: RunCLI */ = async argv => { const [command, ...rest] = argv; const args = parse(rest); args.cwd = args.cwd ? resolve(process.cwd(), args.cwd) : process.cwd(); setGlobalEnvVars(args); await cli( command, args, { version: [`Display the version number`, version], init: [ `Initializes a workspace`, async () => init({cwd: process.cwd()}), // actually runs from bin/cli.sh because it needs to generate Bazel files ], setup: [ `Installs Jazelle hermetically`, // installation happens in bin/cli.sh, nothing to do here async () => {}, ], scaffold: [ `Scaffolds a project from a template`, async ({from, to, name}) => scaffold({ root: await rootOf(args), cwd: process.cwd(), from, to, name, }), ], install: [ `Install all dependencies for a project, modifying lockfiles and Bazel BUILD files if necessary --cwd [cwd] Project directory to use`, async ({cwd}) => install({root: await rootOf(args), cwd}), ], ci: [ `Install all dependencies for a project without modifying source files --cwd [cwd] Project directory to use`, async ({cwd}) => ci({root: await rootOf(args), cwd}), ], add: [ `Install a package and any packages that it depends on [deps...] Package(s) to add at a specific version. ie., foo@1.2.3 --dev Whether to install as devDependency --cwd [cwd] Project directory to use`, async ({cwd, dev}) => add({ root: await rootOf(args), cwd, args: rest.filter(arg => arg != '--dev'), // if dev is passed before name, resolve to correct value dev: Boolean(dev), // FIXME all args can technically be boolean, but we don't want Flow complaining about it everywhere }), ], remove: [ `Remove a package [deps...] Package(s) to remove --cwd [cwd] Project directory to use`, async ({cwd, name}) => remove({root: await rootOf(args), cwd, args: rest}), ], upgrade: [ `Upgrade a package version across all projects [args...] Packages to upgrade and optionally their version ranges. e.g., foo@^1.2.3 bar@^1.2.3`, async () => upgrade({root: await rootOf(args), args: rest}), ], dedupe: [ `Dedupe transitive deps across all projects`, async () => dedupe({root: await rootOf(args)}), ], prune: [ `Prune unused transitive deps`, async () => prune({root: await rootOf(args)}), ], purge: [ `Remove generated files (i.e. node_modules folders and bazel output files)`, async ({force}) => purge({root: await rootOf(args), force: Boolean(force)}), ], check: [ `Display deps w/ multiple versions installed across projects --json Whether to print as JSON (e.g. for piping to jq) --all Includes all dependencies, including those with only a single version installed`, async ({json, all}) => check({ root: await rootOf(args), json: Boolean(json), all: Boolean(all), }), ], outdated: [ `Displays deps whose version is behind the latest version`, async () => outdated({root: await rootOf(args)}), ], resolutions: [ `Displays list of yarn resolutions`, async () => console.log(await resolutions({root: await rootOf(args)})), ], align: [ `Align a project's dependency versions to respect the version policy, if there is one --cwd [cwd] Project directory to use`, async ({cwd}) => await align({root: await rootOf(args), cwd}), ], localize: [ `Align dependency versions to local versions, if a local version exists`, async () => await localize({root: await rootOf(args)}), ], changes: [ `Lists Bazel test targets that changed given a list of changed files [files] A file containing a list of changed files (one per line). Defaults to stdin --format [format] 'targets' or 'dirs'. Defaults to 'targets'`, async ({name, format = 'targets'}) => changes({root: await rootOf(args), files: name, format}), ], plan: [ `Outputs a plan that can be passed to \`jazelle batch\` for parallelizing a group of tests across workers [targets] A file containing a list of targets (typically from \`jazelle changes\`). Defaults to stdin --nodes [nodes] The number of nodes (i.e. cloud machines). Defaults to 1`, async ({name, workers, nodes}) => plan({root: await rootOf(args), targets: name, workers, nodes}), ], batch: [ `Runs a plan from \`jazelle plan\`, parallelizing tests across workers [plan] A file containing a plan (typically from \`jazelle plan\`). Defaults to stdin --index Which group of tests to execute. Defaults to 0 --cores [cores] Number of CPUs to use. Defaults to \`os.cpus().length\``, async ({name, index, cores}) => batch({root: await rootOf(args), plan: name, index, cores}), ], build: [ `Build a project --cwd [cwd] Project directory to use`, async ({cwd}) => build({root: await rootOf(args), cwd}), ], dev: [ `Run a project --cwd [cwd] Project directory to use`, async ({cwd}) => dev({root: await rootOf(args), cwd, args: rest}), ], test: [ `Test a project --cwd [cwd] Project directory to use`, async ({cwd}) => test({root: await rootOf(args), cwd, args: rest}), ], lint: [ `Lint a project --cwd [cwd] Project directory to use`, async ({cwd}) => lint({root: await rootOf(args), cwd, args: rest}), ], flow: [ `Typecheck a project --cwd [cwd] Project directory to use`, async ({cwd}) => flow({root: await rootOf(args), cwd, args: rest}), ], start: [ `Run a project --cwd [cwd] Project directory to use`, async ({cwd}) => start({root: await rootOf(args), cwd, args: rest}), ], 'bin-path': [ `Print the local path of a binary [name] 'bazel', 'node', or 'yarn'`, async ({name}) => binPath(name), ], bazel: [ `Run a Bazel command [args...] A space separated list of arguments`, async ({cwd}) => bazel({root: await rootOf(args).catch(() => cwd), args: rest}), ], node: [ `Runs Node [args...] A space separated list of arguments --cwd [cwd] Project directory to use`, async ({cwd}) => node({cwd, args: rest}), ], yarn: [ `Runs a Yarn command [name] A yarn command name [args...] A space separated list of arguments --cwd [cwd] Project directory to use`, async ({cwd}) => yarn({cwd, args: rest}), ], exec: [ `Runs a bash script [args...] A space separated list of arguments --cwd [cwd] Project directory to use`, async ({cwd}) => exec({root: await rootOf(args), cwd, args: rest}), ], each: [ `Runs a script in each project [args...] A space separated list of arguments`, async ({cwd}) => each({root: await rootOf(args), cwd, args: rest}), ], bump: [ `Bump version for the specified package, plus changed dependencies [type] major, premajor, minor, preminor, patch, prepatch, prerelease or none --frozenPackageJson If true, throws if changes to package.json are required --cwd [cwd] Project directory to use`, async ({cwd, name: type, frozenPackageJson: frozen}) => bump({ root: await rootOf(args), cwd, type: type || frozen, // if frozen is passed before type, resolve to correct value frozenPackageJson: Boolean(frozen), }), ], doctor: [ `Provides advice for some types of issues --cwd [cwd] Project directory to use`, async ({cwd}) => doctor({root: await rootOf(args), cwd}), ], script: [ `Runs a npm script [args...] A space separated list of arguments --cwd [cwd] Project directory to use`, async ({cwd}) => script({ root: await rootOf(args), cwd, args: rest, }), ], }, async ({cwd}) => script({ root: await rootOf(args), cwd, args: [command, ...rest], }) ); }; function setGlobalEnvVars(args) { // INIT_CWD allows all subprocess to access the initial working directory. process.env.INIT_CWD = args.cwd; } async function rootOf(args) { return getRootDir({dir: args.cwd}); } // FIXME eslint is being dumb in CI // eslint-disable-next-line jest/no-export module.exports = { runCLI, version: require('./package.json').version, init, scaffold, install, ci, add, remove, upgrade, dedupe, prune, purge, check: reportMismatchedTopLevelDeps, outdated, resolutions, align, localize, changes: findChangedTargets, plan: getTestGroups, batch, build, dev, test, lint, flow, start, binPath: getBinaryPath, bazel, node, yarn, bump, doctor, script, getRootDir, };