@mnci/cli 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -14
- package/dist/cli.js +84 -21
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ first-party (or established community) Nx equivalent:
|
|
|
29
29
|
```sh
|
|
30
30
|
mnci new my-repo # create a monorepo (prompts scope + registry)
|
|
31
31
|
mnci new my-repo --yes --registry npm --scope @my
|
|
32
|
+
mnci new my-repo --yes --registry npm --scope @my --nx-cloud # opt in to Nx Cloud
|
|
32
33
|
|
|
33
34
|
cd my-repo
|
|
34
35
|
mnci add react-app web # @nx/react (Vite + Jest)
|
|
@@ -43,6 +44,7 @@ mnci add python-app svc # app -> apps/ (wheel, zipped into the drop)
|
|
|
43
44
|
mnci add python-function-app fn # Azure Functions (Python v2) -> apps/
|
|
44
45
|
mnci add python-lib shared # publishable -> python-packages/ (twine upload)
|
|
45
46
|
mnci add python-internal-lib core # private shared lib -> libs/
|
|
47
|
+
mnci add python-vendor shared --lib core # wire core's module into shared's built wheel
|
|
46
48
|
|
|
47
49
|
mnci upgrade # re-apply the latest overlay (see below)
|
|
48
50
|
mnci upgrade --agent windows-latest # ...with an explicit override
|
|
@@ -59,6 +61,7 @@ each a single cross-platform command:
|
|
|
59
61
|
| `npm run affected` | `nx affected -t lint,test,build` (vs `main`) |
|
|
60
62
|
| `npm run graph` | `nx graph` |
|
|
61
63
|
| `npm run release:preview` | `nx release --dry-run` |
|
|
64
|
+
| `npm run python:install` | fixed Python toolchain (ruff/pytest/build/twine) + editable-install every Python project — the same two guards CI runs, for local dev |
|
|
62
65
|
| `prepare` | `husky` (commit-msg lint hook) |
|
|
63
66
|
|
|
64
67
|
## What `new` actually does
|
|
@@ -340,6 +343,30 @@ only for `github`/`both` — an `azure`-only workspace gets no
|
|
|
340
343
|
`.github/dependabot.yml`, matching every other GitHub-only file this CLI
|
|
341
344
|
writes.
|
|
342
345
|
|
|
346
|
+
### Nx Cloud (`--nx-cloud`, opt-in)
|
|
347
|
+
|
|
348
|
+
`mnci new` never connects to Nx Cloud unless asked — `--nx-cloud` (or
|
|
349
|
+
answering "yes" to the interactive prompt) opts in; the flagless/`--yes`
|
|
350
|
+
default stays fully disconnected, exactly as before this existed. When
|
|
351
|
+
opted in, `mnci` passes `create-nx-workspace` a **named** `--nxCloud`
|
|
352
|
+
provider value derived from the chosen `--ci` (`azure`→`azure`,
|
|
353
|
+
`github`/`both`→`github`) — never the bare `--nxCloud=yes`. Verified
|
|
354
|
+
empirically: bare `yes` prompts "Will you be using GitHub as your git
|
|
355
|
+
hosting provider?" even with `--no-interactive` set, and exits without
|
|
356
|
+
creating the workspace at all when stdin isn't a TTY — a real
|
|
357
|
+
`create-nx-workspace` inconsistency, not something `mnci` can configure
|
|
358
|
+
around. The named-provider value sidesteps it and completes non-interactively
|
|
359
|
+
every time. The only visible effect of *which* named value is chosen is a
|
|
360
|
+
throwaway CI workflow file `create-nx-workspace` writes as a side effect of
|
|
361
|
+
Cloud setup — this CLI's own overlay unconditionally overwrites whatever
|
|
362
|
+
lands at that path immediately after, so the pipeline you actually get is
|
|
363
|
+
always the same one described above, Nx Cloud or not.
|
|
364
|
+
|
|
365
|
+
Connecting still requires finishing setup in a browser: `create-nx-workspace`
|
|
366
|
+
prints a `https://cloud.nx.app/connect/…` URL to complete linking the
|
|
367
|
+
workspace to an Nx Cloud account (remote caching, CI insights, `nx
|
|
368
|
+
fix-ci`) — `mnci` does not automate that step.
|
|
369
|
+
|
|
343
370
|
## Dependency & risk notes
|
|
344
371
|
|
|
345
372
|
Being upfront about what mnci leans on, so it's a conscious trade-off rather
|
|
@@ -395,9 +422,10 @@ than a surprise:
|
|
|
395
422
|
Python project workspace-wide (see "Workspace-wide install" above),
|
|
396
423
|
straight into whatever `<python>` resolves to on the agent (`python3` on
|
|
397
424
|
POSIX, `python` on Windows — see above); locally, create your own venv
|
|
398
|
-
(`python3 -m venv` / `python -m venv` on Windows) and
|
|
399
|
-
|
|
400
|
-
|
|
425
|
+
(`python3 -m venv` / `python -m venv` on Windows) and run
|
|
426
|
+
`npm run python:install` to reproduce the same two installs — the root
|
|
427
|
+
script chains the identical two guards CI runs (see the scripts table
|
|
428
|
+
above).
|
|
401
429
|
|
|
402
430
|
## How Node apps work (plain `@nx/node:application`, no Azure Functions plugin)
|
|
403
431
|
|
|
@@ -534,18 +562,21 @@ identically to a Linux/macOS one.
|
|
|
534
562
|
<name>` just like the TS apps.
|
|
535
563
|
- **Internal-lib vendoring** replaces `@nxlv/python`'s `bundleLocalDependencies`:
|
|
536
564
|
plain pip has no bundled-local-dependency feature, so a project that imports
|
|
537
|
-
a workspace-internal Python library needs a
|
|
565
|
+
a workspace-internal Python library needs a `vendor` entry (under
|
|
538
566
|
`[tool.mnci-python-pip]`) in its own `pyproject.toml` (the pip-world
|
|
539
|
-
counterpart of
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
567
|
+
counterpart of a `dependencies = [...]` entry — neither mnci nor the plugin
|
|
568
|
+
wires cross-project Python dependencies automatically). `mnci add
|
|
569
|
+
python-vendor <consumer> --lib <name>` automates writing that entry —
|
|
570
|
+
idempotent (safe to run twice), and works on any consumer with a
|
|
571
|
+
`pyproject.toml` (app, publishable lib, or another internal lib), not just
|
|
572
|
+
apps. The plugin's `build` executor reads the entry, resolves the named
|
|
573
|
+
project's root via the **Nx project graph**, copies its module into a
|
|
574
|
+
staged copy of the consuming project, and builds from there — so the
|
|
575
|
+
resulting wheel contains the vendored module as a real top-level package.
|
|
576
|
+
Verified empirically that this does **not** reproduce the old
|
|
577
|
+
`@nxlv/python` bug where combining a vendored internal lib and a real
|
|
578
|
+
external dependency on the same project silently dropped the external one
|
|
579
|
+
from the wheel's metadata — both survive correctly.
|
|
549
580
|
- **Workspace-wide install** (mnci's own CI step, not the plugin's) — pip has
|
|
550
581
|
no npm-workspaces-style hoisting, so mnci writes one: a guarded step
|
|
551
582
|
editable-installs every Python project (`apps/*`, `python-packages/*`,
|
package/dist/cli.js
CHANGED
|
@@ -35,13 +35,13 @@ __export(cli_exports, {
|
|
|
35
35
|
main: () => main
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(cli_exports);
|
|
38
|
-
var
|
|
38
|
+
var import_node_fs4 = require("fs");
|
|
39
39
|
var import_node_path12 = require("path");
|
|
40
40
|
var import_commander = require("commander");
|
|
41
41
|
|
|
42
42
|
// src/commands/add.ts
|
|
43
43
|
var import_node_path7 = require("path");
|
|
44
|
-
var
|
|
44
|
+
var import_prompts4 = require("@inquirer/prompts");
|
|
45
45
|
|
|
46
46
|
// src/nx.ts
|
|
47
47
|
var import_cross_spawn = __toESM(require("cross-spawn"));
|
|
@@ -100,6 +100,12 @@ async function promptCi() {
|
|
|
100
100
|
]
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
async function promptNxCloud() {
|
|
104
|
+
return await (0, import_prompts.confirm)({
|
|
105
|
+
message: "Connect this workspace to Nx Cloud (remote caching + CI insights)?",
|
|
106
|
+
default: false
|
|
107
|
+
});
|
|
108
|
+
}
|
|
103
109
|
async function promptStack() {
|
|
104
110
|
const linter = await (0, import_prompts.select)({
|
|
105
111
|
message: "Linter",
|
|
@@ -385,6 +391,7 @@ function markPublic(manifestPath) {
|
|
|
385
391
|
}
|
|
386
392
|
|
|
387
393
|
// src/commands/add/python.ts
|
|
394
|
+
var import_node_fs2 = require("fs");
|
|
388
395
|
var import_node_path5 = require("path");
|
|
389
396
|
function ensurePython(workspaceRoot) {
|
|
390
397
|
const hasPython = runShell("python3", ["--version"], workspaceRoot) === 0 || runShell("python", ["--version"], workspaceRoot) === 0;
|
|
@@ -476,9 +483,57 @@ function addPythonInternalLib(workspaceRoot, name) {
|
|
|
476
483
|
ensureRequirementsDev(workspaceRoot);
|
|
477
484
|
runNx(["g", "@mnci/nx-python-pip:internal-library", name, `--directory=libs/${name}`, "--no-interactive"], workspaceRoot);
|
|
478
485
|
}
|
|
486
|
+
var PYTHON_PROJECT_DIRS = ["apps", "python-packages", "libs"];
|
|
487
|
+
function findPythonProjectDirectory(workspaceRoot, name) {
|
|
488
|
+
return PYTHON_PROJECT_DIRS.find((directory) => fileExists((0, import_node_path5.join)(workspaceRoot, directory, name, "pyproject.toml")));
|
|
489
|
+
}
|
|
490
|
+
function parseVendorEntries(pyprojectToml) {
|
|
491
|
+
const match = /^\s*vendor\s*=\s*\[([^\]]*)\]/m.exec(pyprojectToml);
|
|
492
|
+
if (!match) {
|
|
493
|
+
return [];
|
|
494
|
+
}
|
|
495
|
+
return match[1].split(",").map((entry) => entry.trim().replaceAll(/^["']|["']$/g, "")).filter(Boolean);
|
|
496
|
+
}
|
|
497
|
+
function addVendorEntry(pyprojectToml, lib) {
|
|
498
|
+
const existing = parseVendorEntries(pyprojectToml);
|
|
499
|
+
if (existing.length > 0) {
|
|
500
|
+
const merged = [...existing, lib].map((name) => `"${name}"`).join(", ");
|
|
501
|
+
return pyprojectToml.replace(/^(\s*vendor\s*=\s*)\[([^\]]*)\]/m, (_match, prefix) => `${prefix}[${merged}]`);
|
|
502
|
+
}
|
|
503
|
+
const table = `[tool.mnci-python-pip]
|
|
504
|
+
vendor = ["${lib}"]
|
|
505
|
+
|
|
506
|
+
`;
|
|
507
|
+
return pyprojectToml.includes("[tool.pytest.ini_options]") ? pyprojectToml.replace("[tool.pytest.ini_options]", () => `${table}[tool.pytest.ini_options]`) : `${pyprojectToml}
|
|
508
|
+
${table}`;
|
|
509
|
+
}
|
|
510
|
+
async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
|
|
511
|
+
const lib = options.lib ?? (kindProvided ? void 0 : await promptText("Internal Python library to vendor (an existing libs/<name>)"));
|
|
512
|
+
if (!lib) {
|
|
513
|
+
throw new Error("`add python-vendor` needs the library to vendor: pass --lib <name> (an existing libs/<name> internal library).");
|
|
514
|
+
}
|
|
515
|
+
const consumerDirectory = findPythonProjectDirectory(workspaceRoot, consumer);
|
|
516
|
+
if (!consumerDirectory) {
|
|
517
|
+
throw new Error(`No Python project named '${consumer}' with a pyproject.toml found (checked apps/, python-packages/, libs/). A Python function app has no pyproject.toml \u2014 there is nothing to vendor into.`);
|
|
518
|
+
}
|
|
519
|
+
if (!fileExists((0, import_node_path5.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
|
|
520
|
+
throw new Error(`No internal Python library named '${lib}' found at libs/${lib}/pyproject.toml. Only an internal library (added via 'mnci add python-internal-lib') can be vendored.`);
|
|
521
|
+
}
|
|
522
|
+
if (consumerDirectory === "libs" && consumer === lib) {
|
|
523
|
+
throw new Error(`'${consumer}' cannot vendor itself.`);
|
|
524
|
+
}
|
|
525
|
+
const pyprojectPath = (0, import_node_path5.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
|
|
526
|
+
const pyprojectToml = (0, import_node_fs2.readFileSync)(pyprojectPath, "utf8");
|
|
527
|
+
if (parseVendorEntries(pyprojectToml).includes(lib)) {
|
|
528
|
+
logger.info(`'${consumer}' already vendors '${lib}' \u2014 nothing to do.`);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
writeFileEnsured(pyprojectPath, addVendorEntry(pyprojectToml, lib));
|
|
532
|
+
logger.success(`'${consumer}' now vendors '${lib}' \u2014 its wheel will include '${lib}''s module on the next build.`);
|
|
533
|
+
}
|
|
479
534
|
|
|
480
535
|
// src/commands/add/reactApp.ts
|
|
481
|
-
var
|
|
536
|
+
var import_node_fs3 = require("fs");
|
|
482
537
|
var import_node_path6 = require("path");
|
|
483
538
|
function ensurePlugin2(workspaceRoot, packageName) {
|
|
484
539
|
if (hasPlugin(workspaceRoot, packageName)) {
|
|
@@ -521,7 +576,7 @@ function allowEnvFiles(workspaceRoot) {
|
|
|
521
576
|
return;
|
|
522
577
|
}
|
|
523
578
|
const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
|
|
524
|
-
const current = (0,
|
|
579
|
+
const current = (0, import_node_fs3.readFileSync)(gitignorePath, "utf8");
|
|
525
580
|
if (current.includes(marker)) {
|
|
526
581
|
return;
|
|
527
582
|
}
|
|
@@ -563,7 +618,8 @@ var PROJECT_KINDS = [
|
|
|
563
618
|
"python-app",
|
|
564
619
|
"python-function-app",
|
|
565
620
|
"python-lib",
|
|
566
|
-
"python-internal-lib"
|
|
621
|
+
"python-internal-lib",
|
|
622
|
+
"python-vendor"
|
|
567
623
|
];
|
|
568
624
|
async function runAdd(kind, name, options) {
|
|
569
625
|
const workspaceRoot = process.cwd();
|
|
@@ -572,7 +628,7 @@ async function runAdd(kind, name, options) {
|
|
|
572
628
|
}
|
|
573
629
|
const stack = readWorkspaceStack(workspaceRoot);
|
|
574
630
|
const kindProvided = kind !== void 0;
|
|
575
|
-
const resolvedKind = kind ?? await (0,
|
|
631
|
+
const resolvedKind = kind ?? await (0, import_prompts4.select)({
|
|
576
632
|
message: "What kind of project?",
|
|
577
633
|
choices: PROJECT_KINDS.map((value) => ({ name: value, value }))
|
|
578
634
|
});
|
|
@@ -624,6 +680,11 @@ async function runAdd(kind, name, options) {
|
|
|
624
680
|
addPythonInternalLib(workspaceRoot, resolvedName);
|
|
625
681
|
break;
|
|
626
682
|
}
|
|
683
|
+
case "python-vendor": {
|
|
684
|
+
await addPythonVendor(workspaceRoot, resolvedName, options, kindProvided);
|
|
685
|
+
syncProjectReferences(workspaceRoot);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
627
688
|
default: {
|
|
628
689
|
const exhaustive = resolvedKind;
|
|
629
690
|
throw new Error(`Unknown project kind '${exhaustive}'. Expected one of: ${PROJECT_KINDS.join(", ")}.`);
|
|
@@ -653,7 +714,7 @@ function markPrivate(manifestPath) {
|
|
|
653
714
|
|
|
654
715
|
// src/commands/interactive.ts
|
|
655
716
|
var import_node_path10 = require("path");
|
|
656
|
-
var
|
|
717
|
+
var import_prompts7 = require("@inquirer/prompts");
|
|
657
718
|
|
|
658
719
|
// src/commands/new.ts
|
|
659
720
|
var import_node_path9 = require("path");
|
|
@@ -730,15 +791,13 @@ var ROOT_SCRIPTS = {
|
|
|
730
791
|
prepare: "husky"
|
|
731
792
|
};
|
|
732
793
|
function rootScripts(stack) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
}
|
|
741
|
-
return { ...ROOT_SCRIPTS };
|
|
794
|
+
const scripts = stack.linter === "oxlint" ? {
|
|
795
|
+
...ROOT_SCRIPTS,
|
|
796
|
+
lint: "oxlint",
|
|
797
|
+
format: "oxfmt -c oxfmt.config.mts .",
|
|
798
|
+
"format:check": "oxfmt -c oxfmt.config.mts --check ."
|
|
799
|
+
} : { ...ROOT_SCRIPTS };
|
|
800
|
+
return { ...scripts, "python:install": `${PYTHON_INSTALL_GUARD} && ${PYTHON_WORKSPACE_INSTALL_GUARD}` };
|
|
742
801
|
}
|
|
743
802
|
function generatorDefaults(stack) {
|
|
744
803
|
const shared = { linter: stack.linter === "oxlint" ? "none" : "eslint", unitTestRunner: stack.testRunner };
|
|
@@ -1142,6 +1201,9 @@ function applyOverlay(workspaceRoot, options) {
|
|
|
1142
1201
|
}
|
|
1143
1202
|
|
|
1144
1203
|
// src/commands/new.ts
|
|
1204
|
+
function nxCloudProviderValue(ci) {
|
|
1205
|
+
return ci === "azure" ? "azure" : "github";
|
|
1206
|
+
}
|
|
1145
1207
|
async function resolveStack(options) {
|
|
1146
1208
|
const fromFlags = { linter: options.linter, testRunner: options.testRunner };
|
|
1147
1209
|
const complete = Boolean(fromFlags.linter && fromFlags.testRunner);
|
|
@@ -1190,6 +1252,7 @@ async function runNew(name, options) {
|
|
|
1190
1252
|
const agent = options.agent ?? (options.yes ? "ubuntu-latest" : await promptText("CI build agent/runner (vmImage, GitHub Actions runner label, or self-hosted pool name)", "ubuntu-latest"));
|
|
1191
1253
|
const variableGroup = ci === "github" ? options.variableGroup ?? "Build" : options.variableGroup ?? (options.yes ? "Build" : await promptText("Azure DevOps variable group holding the npm PAT", "Build"));
|
|
1192
1254
|
const stack = await resolveStack(options);
|
|
1255
|
+
const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
|
|
1193
1256
|
logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
|
|
1194
1257
|
runNpx([
|
|
1195
1258
|
"--yes",
|
|
@@ -1197,7 +1260,7 @@ async function runNew(name, options) {
|
|
|
1197
1260
|
workspaceName,
|
|
1198
1261
|
"--preset=ts",
|
|
1199
1262
|
"--pm=npm",
|
|
1200
|
-
"--nxCloud=skip",
|
|
1263
|
+
nxCloud ? `--nxCloud=${nxCloudProviderValue(ci)}` : "--nxCloud=skip",
|
|
1201
1264
|
"--no-interactive"
|
|
1202
1265
|
], process.cwd());
|
|
1203
1266
|
const workspaceRoot = (0, import_node_path9.join)(process.cwd(), workspaceName);
|
|
@@ -1222,7 +1285,7 @@ async function runInteractive() {
|
|
|
1222
1285
|
const inWorkspace = fileExists((0, import_node_path10.join)(process.cwd(), "nx.json"));
|
|
1223
1286
|
const newChoice = { name: "Create a new monorepo", value: "new" };
|
|
1224
1287
|
const addChoice = { name: "Add a project to this workspace", value: "add" };
|
|
1225
|
-
const action = await (0,
|
|
1288
|
+
const action = await (0, import_prompts7.select)({
|
|
1226
1289
|
message: "What would you like to do?",
|
|
1227
1290
|
choices: inWorkspace ? [addChoice, newChoice] : [newChoice, addChoice]
|
|
1228
1291
|
});
|
|
@@ -1290,7 +1353,7 @@ function runUpgrade(workspaceRoot, options) {
|
|
|
1290
1353
|
// src/cli.ts
|
|
1291
1354
|
function readVersion() {
|
|
1292
1355
|
try {
|
|
1293
|
-
const package_ = JSON.parse((0,
|
|
1356
|
+
const package_ = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path12.join)(__dirname, "..", "package.json"), "utf8"));
|
|
1294
1357
|
return package_.version ?? "0.0.0";
|
|
1295
1358
|
} catch {
|
|
1296
1359
|
return "0.0.0";
|
|
@@ -1299,13 +1362,13 @@ function readVersion() {
|
|
|
1299
1362
|
function buildProgram() {
|
|
1300
1363
|
const program = new import_commander.Command();
|
|
1301
1364
|
program.name("mnci").description("MoNecromanCI \u2014 a thin CLI over official Nx plugins").version(readVersion(), "-v, --version", "display the version");
|
|
1302
|
-
program.command("new").argument("[name]", "workspace name").description("Create a new monorepo (Nx TS preset + release/pipeline overlay)").option("-y, --yes", "accept defaults for anything not passed as a flag").option("--scope <scope>", "npm scope for publishable packages (e.g. @demo)").option("--registry <kind>", "azure-artifacts | npm").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option("--agent <pool>", "CI build agent: a vmImage (e.g. ubuntu-latest) or self-hosted pool name").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--linter <linter>", "linter: eslint | oxlint").option("--test-runner <runner>", "unit-test runner: jest | vitest").action(async (name, options) => {
|
|
1365
|
+
program.command("new").argument("[name]", "workspace name").description("Create a new monorepo (Nx TS preset + release/pipeline overlay)").option("-y, --yes", "accept defaults for anything not passed as a flag").option("--scope <scope>", "npm scope for publishable packages (e.g. @demo)").option("--registry <kind>", "azure-artifacts | npm").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option("--agent <pool>", "CI build agent: a vmImage (e.g. ubuntu-latest) or self-hosted pool name").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--linter <linter>", "linter: eslint | oxlint").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").action(async (name, options) => {
|
|
1303
1366
|
await runNew(name, options);
|
|
1304
1367
|
});
|
|
1305
1368
|
program.command("upgrade").description("Re-apply the latest MoNecromanCI overlay to this workspace (release config, pipeline, npmrc, commitlint, husky hook, curated scripts)").option("--scope <scope>", "npm scope for publishable packages (overrides the persisted value)").option("--registry <kind>", "azure-artifacts | npm (overrides the persisted value)").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option("--agent <pool>", "CI build agent (overrides the persisted value)").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both (overrides the persisted value)").option("--linter <linter>", "linter: eslint | oxlint (overrides the persisted value)").option("--test-runner <runner>", "unit-test runner: jest | vitest (overrides the persisted value)").action((options) => {
|
|
1306
1369
|
runUpgrade(process.cwd(), options);
|
|
1307
1370
|
});
|
|
1308
|
-
program.command("add").addArgument(new import_commander.Argument("[kind]", "project kind").choices(PROJECT_KINDS)).argument("[name]", "project name").description("Add a project by delegating to the matching Nx plugin generator").option("--scope <scope>", "npm scope for a publishable lib (defaults to @<workspace name>)").option("--framework <framework>", "node-app only: express | fastify | koa | nest | none (default: none)").action(async (kind, name, options) => {
|
|
1371
|
+
program.command("add").addArgument(new import_commander.Argument("[kind]", "project kind").choices(PROJECT_KINDS)).argument("[name]", "project name").description("Add a project by delegating to the matching Nx plugin generator").option("--scope <scope>", "npm scope for a publishable lib (defaults to @<workspace name>)").option("--framework <framework>", "node-app only: express | fastify | koa | nest | none (default: none)").option("--lib <name>", "python-vendor only: the internal Python library (libs/<name>) to vendor into <name>").action(async (kind, name, options) => {
|
|
1309
1372
|
await runAdd(kind, name, options);
|
|
1310
1373
|
});
|
|
1311
1374
|
program.action(async () => {
|