Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add add-caching command #3350

Merged
merged 3 commits into from Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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);
};
157 changes: 157 additions & 0 deletions core/lerna/commands/add-caching/index.js
@@ -0,0 +1,157 @@
// @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"
);
// 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",
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
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)\n",
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
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: `Where within a particular project directory does the "${scriptName}" script write its outputs?\n`,
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
default: "dist",
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
validate: (input) => {
if (!input) {
return "Please provide a project relative path";
}
return true;
},
},
]);
}

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"
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
);
}

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)) {
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",
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
"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.