Skip to content

Commit

Permalink
feat(core): add add-caching command (lerna#3350)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesHenry authored and Ross Rhodes committed Jan 3, 2023
1 parent d570bb4 commit 504add1
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 0 deletions.
19 changes: 19 additions & 0 deletions core/lerna/commands/add-caching/command.js
@@ -0,0 +1,19 @@
// @ts-check

"use strict";

/**
* @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module
*/
exports.command = "add-caching";

exports.describe = "Interactive prompt to generate task runner configuration";

exports.builder = (yargs) => {
return yargs;
};

exports.handler = function handler(argv) {
// eslint-disable-next-line global-require
return require(".")(argv);
};
158 changes: 158 additions & 0 deletions core/lerna/commands/add-caching/index.js
@@ -0,0 +1,158 @@
// @ts-check

"use strict";

const { Command } = require("@lerna/command");
const { writeJsonFile, readJsonFile, workspaceRoot, joinPathFragments } = require("@nrwl/devkit");
const inquirer = require("inquirer");
const log = require("npmlog");

module.exports = factory;

function factory(argv) {
return new AddCachingCommand(argv);
}

class AddCachingCommand extends Command {
constructor(argv) {
super(argv, { skipValidations: true });
}

initialize() {
if (this.options.useNx === false) {
this.logger.error(
"add-caching",
"The `add-caching` command is only available when using the Nx task runner (do not set `useNx` to `false` in `lerna.json`)"
);
// eslint-disable-next-line no-process-exit
process.exit(1);
}

const packages = this.packageGraph?.rawPackageList || [];
const uniqueScriptNames = new Set();
for (const pkg of packages) {
for (const scriptName of Object.keys(pkg.scripts || {})) {
uniqueScriptNames.add(scriptName);
}
}
this.uniqueScriptNames = Array.from(uniqueScriptNames);
}

async execute() {
this.logger.info(
"add-caching",
"Please answer the following questions about the scripts found in your workspace in order to generate task runner configuration"
);
process.stdout.write("\n");

log.pause();

const { targetDefaults } = await inquirer.prompt([
{
type: "checkbox",
name: "targetDefaults",
message: "Which of the following scripts need to be run in deterministic/topoglogical order?\n",
choices: this.uniqueScriptNames,
},
]);

const { cacheableOperations } = await inquirer.prompt([
{
type: "checkbox",
name: "cacheableOperations",
message:
"Which of the following scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)\n",
choices: this.uniqueScriptNames,
},
]);

const scriptOutputs = {};

for (const scriptName of cacheableOperations) {
// eslint-disable-next-line no-await-in-loop
scriptOutputs[scriptName] = await inquirer.prompt([
{
type: "input",
name: scriptName,
message: `Does the "${scriptName}" script create any outputs? If not, leave blank, otherwise provide a path relative to a project root (e.g. dist, lib, build, coverage)\n`,
},
]);
}

log.resume();

process.stdout.write("\n");

this.convertAnswersToNxConfig({ cacheableOperations, targetDefaults, scriptOutputs });

this.logger.success("add-caching", "Successfully updated task runner configuration in `nx.json`");

this.logger.info(
"add-caching",
"Learn more about task runner configuration here: https://lerna.js.org/docs/concepts/task-pipeline-configuration"
);
this.logger.info(
"add-caching",
"Note that the legacy task runner options of --sort, --no-sort and --parallel no longer apply. Learn more here: https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks"
);
}

convertAnswersToNxConfig(answers) {
const nxJsonPath = joinPathFragments(workspaceRoot, "nx.json");
let nxJson = {};
try {
nxJson = readJsonFile(nxJsonPath);
// eslint-disable-next-line no-empty
} catch {}

nxJson.tasksRunnerOptions = nxJson.tasksRunnerOptions || {};
nxJson.tasksRunnerOptions.default = nxJson.tasksRunnerOptions.default || {};
nxJson.tasksRunnerOptions.default.runner =
nxJson.tasksRunnerOptions.default.runner || "nx/tasks-runners/default";
nxJson.tasksRunnerOptions.default.options = nxJson.tasksRunnerOptions.default.options || {};

if (nxJson.tasksRunnerOptions.default.options.cacheableOperations) {
this.logger.warn(
"add-caching",
"The `tasksRunnerOptions.default.cacheableOperations` property already exists in `nx.json` and will be overwritten by your answers"
);
}

nxJson.tasksRunnerOptions.default.options.cacheableOperations = answers.cacheableOperations;

if (nxJson.targetDefaults) {
this.logger.warn(
"add-caching",
"The `targetDefaults` property already exists in `nx.json` and will be overwritten by your answers"
);
}

nxJson.targetDefaults = nxJson.targetDefaults || {};

for (const scriptName of answers.targetDefaults) {
nxJson.targetDefaults[scriptName] = nxJson.targetDefaults[scriptName] || {};
nxJson.targetDefaults[scriptName] = { dependsOn: [`^${scriptName}`] };
}

for (const [scriptName, scriptAnswerData] of Object.entries(answers.scriptOutputs)) {
if (!scriptAnswerData[scriptName]) {
// eslint-disable-next-line no-continue
continue;
}
nxJson.targetDefaults[scriptName] = nxJson.targetDefaults[scriptName] || {};
nxJson.targetDefaults[scriptName].outputs = [`{projectRoot}/${scriptAnswerData[scriptName]}`];
}

writeJsonFile(nxJsonPath, nxJson);
}

// eslint-disable-next-line class-methods-use-this
normalizePathInput(pathInput) {
if (pathInput.startsWith("/")) {
return pathInput.substring(1);
}
return pathInput;
}
}

module.exports.AddCachingCommand = AddCachingCommand;
2 changes: 2 additions & 0 deletions core/lerna/index.js
Expand Up @@ -21,6 +21,7 @@ const runCmd = require("@lerna/run/command");
const versionCmd = require("@lerna/version/command");

const repairCmd = require("./commands/repair/command");
const addCachingCmd = require("./commands/add-caching/command");

const pkg = require("./package.json");

Expand All @@ -34,6 +35,7 @@ function main(argv) {
// @ts-ignore
return cli()
.command(addCmd)
.command(addCachingCmd)
.command(bootstrapCmd)
.command(changedCmd)
.command(cleanCmd)
Expand Down
1 change: 1 addition & 0 deletions core/lerna/package.json
Expand Up @@ -61,6 +61,7 @@
"@lerna/version": "file:../../commands/version",
"@nrwl/devkit": ">=14.8.1 < 16",
"import-local": "^3.0.2",
"inquirer": "^8.2.4",
"npmlog": "^6.0.2",
"nx": ">=14.8.1 < 16",
"typescript": "^3 || ^4"
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 504add1

Please sign in to comment.