@mnci/cli 4.44.0 → 4.46.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 +31 -0
- package/dist/cli.js +668 -229
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8417,7 +8417,7 @@ function checkReleaseTagsResolve(workspaceRoot, nxJson) {
|
|
|
8417
8417
|
check: "release tags resolve under each project's current name",
|
|
8418
8418
|
ok: stranded.length === 0,
|
|
8419
8419
|
detail: `${stranded.map((entry) => `${entry.project} has only ${entry.oldTag}`).join("; ")} - nx release finds no tag under the new name and would release from the disk version, a downgrade`,
|
|
8420
|
-
remedy: `
|
|
8420
|
+
remedy: `run \`mnci adopt --tags\` to create the baseline tag for each (${stranded.map((entry) => entry.newTag).join(", ")}) on the commit of its old tag, then push the tags`
|
|
8421
8421
|
};
|
|
8422
8422
|
}
|
|
8423
8423
|
function collectFindings(workspaceRoot) {
|
|
@@ -8485,6 +8485,536 @@ function runDoctor(workspaceRoot, options = {}) {
|
|
|
8485
8485
|
process.exitCode = 1;
|
|
8486
8486
|
}
|
|
8487
8487
|
|
|
8488
|
+
// src/repository-adoption/adopt-kinds.use-case.ts
|
|
8489
|
+
var import_node_fs31 = require("fs");
|
|
8490
|
+
var import_node_path36 = require("path");
|
|
8491
|
+
|
|
8492
|
+
// src/repository-adoption/clean-working-tree.validator.ts
|
|
8493
|
+
function requireCleanWorkingTree(repositoryRoot, capture = runCapture) {
|
|
8494
|
+
if (capture("git", ["rev-parse", "--is-inside-work-tree"], repositoryRoot).status !== 0) {
|
|
8495
|
+
throw new Error("This directory is not a git repository. Every adoption step is one diff to review, so it needs git.");
|
|
8496
|
+
}
|
|
8497
|
+
if (capture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "") {
|
|
8498
|
+
throw new Error("The working tree has uncommitted changes. Commit or stash them, so this step is one diff you can review or discard.");
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
|
|
8502
|
+
// src/repository-adoption/infer-project-kind.algorithm.ts
|
|
8503
|
+
var SERVER_FRAMEWORKS = ["express", "koa", "fastify", "@nestjs/core"];
|
|
8504
|
+
function declares(manifest, name) {
|
|
8505
|
+
return ["dependencies", "devDependencies", "peerDependencies"].some((key) => {
|
|
8506
|
+
const block = manifest[key];
|
|
8507
|
+
return typeof block === "object" && block !== null && Object.keys(block).includes(name);
|
|
8508
|
+
});
|
|
8509
|
+
}
|
|
8510
|
+
function inferNpm(evidence) {
|
|
8511
|
+
const { manifest, files } = evidence;
|
|
8512
|
+
const engines = manifest.engines;
|
|
8513
|
+
if (engines?.vscode !== void 0) {
|
|
8514
|
+
return { kind: "vscode-extension", certainty: "certain", reason: "engines.vscode is set" };
|
|
8515
|
+
}
|
|
8516
|
+
if (files.includes("host.json") || declares(manifest, "@azure/functions")) {
|
|
8517
|
+
return { kind: "node-function-app", certainty: "certain", reason: "an Azure Functions host.json or @azure/functions" };
|
|
8518
|
+
}
|
|
8519
|
+
const privatePackage = manifest.private === true;
|
|
8520
|
+
if (declares(manifest, "react") || declares(manifest, "react-dom")) {
|
|
8521
|
+
if (files.includes("index.html")) {
|
|
8522
|
+
return { kind: "react-app", certainty: "certain", reason: "React with an index.html entry" };
|
|
8523
|
+
}
|
|
8524
|
+
return { kind: privatePackage ? "react-internal-lib" : "react-lib", certainty: "certain", reason: `React without an index.html, ${privatePackage ? "private" : "publishable"}` };
|
|
8525
|
+
}
|
|
8526
|
+
const framework = SERVER_FRAMEWORKS.find((name) => declares(manifest, name));
|
|
8527
|
+
if (framework !== void 0) {
|
|
8528
|
+
return { kind: "node-app", certainty: "certain", reason: `a ${framework} server` };
|
|
8529
|
+
}
|
|
8530
|
+
const scripts = manifest.scripts;
|
|
8531
|
+
if (manifest.bin !== void 0 || scripts?.start !== void 0) {
|
|
8532
|
+
return { kind: "node-app", certainty: "guess", reason: "it has a bin or a start script, but no known server framework" };
|
|
8533
|
+
}
|
|
8534
|
+
if (privatePackage) {
|
|
8535
|
+
return { kind: "internal-lib", certainty: "certain", reason: "private, with no entry point of its own" };
|
|
8536
|
+
}
|
|
8537
|
+
const hasEntry = ["main", "module", "exports"].some((key) => manifest[key] !== void 0);
|
|
8538
|
+
return { kind: "npm-lib", certainty: hasEntry ? "certain" : "guess", reason: hasEntry ? "publishable, with a library entry" : "publishable, but no main, module or exports" };
|
|
8539
|
+
}
|
|
8540
|
+
function inferPython(evidence) {
|
|
8541
|
+
const { files, text } = evidence;
|
|
8542
|
+
if (files.includes("function_app.py") || files.includes("host.json")) {
|
|
8543
|
+
return { kind: "python-function-app", certainty: "certain", reason: "an Azure Functions function_app.py or host.json" };
|
|
8544
|
+
}
|
|
8545
|
+
if (text.includes("[project.scripts]") || files.includes("__main__.py")) {
|
|
8546
|
+
return { kind: "python-app", certainty: "guess", reason: "it declares a script or a __main__.py, which a library can too" };
|
|
8547
|
+
}
|
|
8548
|
+
if (text.includes("Private :: Do Not Upload")) {
|
|
8549
|
+
return { kind: "python-internal-lib", certainty: "certain", reason: "classified Private :: Do Not Upload" };
|
|
8550
|
+
}
|
|
8551
|
+
return { kind: "python-lib", certainty: "guess", reason: "a library, but internal or published is a choice only you can make" };
|
|
8552
|
+
}
|
|
8553
|
+
function inferFlutter(evidence) {
|
|
8554
|
+
if (evidence.hasProgram) {
|
|
8555
|
+
return { kind: "flutter-app", certainty: "certain", reason: "lib/main.dart is the entry point" };
|
|
8556
|
+
}
|
|
8557
|
+
const internal = /^publish_to:\s*['"]?none['"]?\s*$/m.test(evidence.text);
|
|
8558
|
+
return { kind: internal ? "flutter-internal-lib" : "flutter-lib", certainty: "certain", reason: internal ? "publish_to: none" : "publishable, with no entry point" };
|
|
8559
|
+
}
|
|
8560
|
+
function inferCsharp(evidence) {
|
|
8561
|
+
const { text } = evidence;
|
|
8562
|
+
if (/<OutputType>\s*Exe\s*<\/OutputType>/i.test(text)) {
|
|
8563
|
+
const functions = /Microsoft\.Azure\.Functions|Azure\.Functions\.Sdk/.test(text);
|
|
8564
|
+
return { kind: functions ? "csharp-function-app" : "csharp-app", certainty: "certain", reason: functions ? "an executable using the Azure Functions worker" : "an executable" };
|
|
8565
|
+
}
|
|
8566
|
+
if (/<IsPackable>\s*false\s*<\/IsPackable>/i.test(text)) {
|
|
8567
|
+
return { kind: "csharp-internal-lib", certainty: "certain", reason: "IsPackable is false" };
|
|
8568
|
+
}
|
|
8569
|
+
return { kind: "csharp-lib", certainty: "guess", reason: "a library, but internal or published is a choice only you can make" };
|
|
8570
|
+
}
|
|
8571
|
+
function inferGo(evidence) {
|
|
8572
|
+
if (evidence.hasProgram) {
|
|
8573
|
+
const functions = evidence.files.includes("host.json");
|
|
8574
|
+
return { kind: functions ? "go-function-app" : "go-app", certainty: "certain", reason: functions ? "package main with an Azure Functions host.json" : "a package main" };
|
|
8575
|
+
}
|
|
8576
|
+
return { kind: "go-lib", certainty: "guess", reason: "a library, but internal or published is a choice only you can make" };
|
|
8577
|
+
}
|
|
8578
|
+
function inferProjectKind(evidence) {
|
|
8579
|
+
switch (evidence.ecosystem) {
|
|
8580
|
+
case "npm": {
|
|
8581
|
+
return inferNpm(evidence);
|
|
8582
|
+
}
|
|
8583
|
+
case "pip": {
|
|
8584
|
+
return inferPython(evidence);
|
|
8585
|
+
}
|
|
8586
|
+
case "pub": {
|
|
8587
|
+
return inferFlutter(evidence);
|
|
8588
|
+
}
|
|
8589
|
+
case "nuget": {
|
|
8590
|
+
return inferCsharp(evidence);
|
|
8591
|
+
}
|
|
8592
|
+
case "go": {
|
|
8593
|
+
return inferGo(evidence);
|
|
8594
|
+
}
|
|
8595
|
+
}
|
|
8596
|
+
}
|
|
8597
|
+
|
|
8598
|
+
// src/repository-adoption/adopt-kinds.use-case.ts
|
|
8599
|
+
var TYPE_TAG = "type:";
|
|
8600
|
+
function readEvidence(repositoryRoot, location) {
|
|
8601
|
+
const directory = (0, import_node_path36.join)(repositoryRoot, location.dir);
|
|
8602
|
+
const files = (0, import_node_fs31.readdirSync)(directory);
|
|
8603
|
+
const manifest = location.ecosystem === "npm" ? readJson(location.manifestPath) : {};
|
|
8604
|
+
const text = location.ecosystem === "npm" ? "" : (0, import_node_fs31.readFileSync)(location.manifestPath, "utf8");
|
|
8605
|
+
let hasProgram = false;
|
|
8606
|
+
if (location.ecosystem === "go") {
|
|
8607
|
+
hasProgram = files.filter((file) => file.endsWith(".go")).some((file) => /^package main\b/m.test((0, import_node_fs31.readFileSync)((0, import_node_path36.join)(directory, file), "utf8")));
|
|
8608
|
+
} else if (location.ecosystem === "pub") {
|
|
8609
|
+
hasProgram = (0, import_node_fs31.existsSync)((0, import_node_path36.join)(directory, "lib", "main.dart"));
|
|
8610
|
+
}
|
|
8611
|
+
return { ecosystem: location.ecosystem, manifest, text, files, hasProgram };
|
|
8612
|
+
}
|
|
8613
|
+
function existingKind(directory) {
|
|
8614
|
+
const sources = [];
|
|
8615
|
+
if (fileExists((0, import_node_path36.join)(directory, "project.json"))) {
|
|
8616
|
+
sources.push(readJson((0, import_node_path36.join)(directory, "project.json")).tags ?? []);
|
|
8617
|
+
}
|
|
8618
|
+
if (fileExists((0, import_node_path36.join)(directory, "package.json"))) {
|
|
8619
|
+
sources.push(readJson((0, import_node_path36.join)(directory, "package.json")).nx?.tags ?? []);
|
|
8620
|
+
}
|
|
8621
|
+
return sources.flat().find((tag) => tag.startsWith(TYPE_TAG))?.slice(TYPE_TAG.length);
|
|
8622
|
+
}
|
|
8623
|
+
function writeKindTag(directory, name, kind) {
|
|
8624
|
+
const tag = `${TYPE_TAG}${kind}`;
|
|
8625
|
+
const projectJson = (0, import_node_path36.join)(directory, "project.json");
|
|
8626
|
+
const packageJson = (0, import_node_path36.join)(directory, "package.json");
|
|
8627
|
+
if (fileExists(projectJson)) {
|
|
8628
|
+
const project = readJson(projectJson);
|
|
8629
|
+
writeFileEnsured(projectJson, toJson({ ...project, tags: [...project.tags ?? [], tag] }));
|
|
8630
|
+
} else if (fileExists(packageJson)) {
|
|
8631
|
+
const manifest = readJson(packageJson);
|
|
8632
|
+
writeFileEnsured(packageJson, toJson({ ...manifest, nx: { ...manifest.nx, tags: [...manifest.nx?.tags ?? [], tag] } }));
|
|
8633
|
+
} else {
|
|
8634
|
+
writeFileEnsured(projectJson, toJson({ name, tags: [tag] }));
|
|
8635
|
+
}
|
|
8636
|
+
}
|
|
8637
|
+
function adoptKinds(repositoryRoot, overrides = {}, dependencies = {}) {
|
|
8638
|
+
requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
|
|
8639
|
+
const locations = locateProjects(repositoryRoot);
|
|
8640
|
+
const known = new Set(locations.map((location) => location.dir));
|
|
8641
|
+
for (const [dir, kind] of Object.entries(overrides)) {
|
|
8642
|
+
if (!known.has(dir)) {
|
|
8643
|
+
throw new Error(`--kind ${dir}=${kind}: no project at ${dir}. Projects found: ${[...known].join(", ")}`);
|
|
8644
|
+
}
|
|
8645
|
+
if (!PROJECT_KINDS.includes(kind)) {
|
|
8646
|
+
throw new Error(`--kind ${dir}=${kind}: ${kind} is not a kind. Kinds: ${PROJECT_KINDS.join(", ")}`);
|
|
8647
|
+
}
|
|
8648
|
+
}
|
|
8649
|
+
return locations.map((location) => {
|
|
8650
|
+
const directory = (0, import_node_path36.join)(repositoryRoot, location.dir);
|
|
8651
|
+
const present = existingKind(directory);
|
|
8652
|
+
if (present !== void 0) {
|
|
8653
|
+
return { dir: location.dir, outcome: "already", kind: present, reason: PROJECT_KINDS.includes(present) ? "it already has a type tag" : "it already has a type tag of its own, which is not an mnci kind name; left as it is" };
|
|
8654
|
+
}
|
|
8655
|
+
const chosen = overrides[location.dir];
|
|
8656
|
+
const proposal = chosen === void 0 ? inferProjectKind(readEvidence(repositoryRoot, location)) : { kind: chosen, certainty: "certain", reason: "named with --kind" };
|
|
8657
|
+
if (proposal.certainty === "guess") {
|
|
8658
|
+
return { dir: location.dir, outcome: "undecided", kind: proposal.kind, reason: proposal.reason };
|
|
8659
|
+
}
|
|
8660
|
+
writeKindTag(directory, location.name, proposal.kind);
|
|
8661
|
+
return { dir: location.dir, outcome: "tagged", kind: proposal.kind, reason: proposal.reason };
|
|
8662
|
+
}).toSorted((a, b) => a.dir.localeCompare(b.dir));
|
|
8663
|
+
}
|
|
8664
|
+
|
|
8665
|
+
// src/repository-adoption/adopt-overlay.use-case.ts
|
|
8666
|
+
var import_node_fs33 = require("fs");
|
|
8667
|
+
var import_node_path38 = require("path");
|
|
8668
|
+
|
|
8669
|
+
// src/workspace-upgrade/upgrade-workspace.use-case.ts
|
|
8670
|
+
var import_node_fs32 = require("fs");
|
|
8671
|
+
var import_node_path37 = require("path");
|
|
8672
|
+
function resolveRegistry(options, persisted) {
|
|
8673
|
+
if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
|
|
8674
|
+
const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
|
|
8675
|
+
const organization = options.organization ?? persistedAzure?.organization;
|
|
8676
|
+
const project = options.project ?? persistedAzure?.project;
|
|
8677
|
+
const artifactsFeed = options.artifactsFeed ?? persistedAzure?.artifactsFeed;
|
|
8678
|
+
if (!organization || !project || !artifactsFeed) {
|
|
8679
|
+
throw new Error(
|
|
8680
|
+
"Azure Artifacts registry needs --organization, --project and --artifacts-feed (none found in nx.json's persisted config either)."
|
|
8681
|
+
);
|
|
8682
|
+
}
|
|
8683
|
+
return { kind: "azure-artifacts", organization, project, artifactsFeed };
|
|
8684
|
+
}
|
|
8685
|
+
if (options.registry === "npm") {
|
|
8686
|
+
return { kind: "npm" };
|
|
8687
|
+
}
|
|
8688
|
+
if (persisted) {
|
|
8689
|
+
return persisted;
|
|
8690
|
+
}
|
|
8691
|
+
throw new Error(
|
|
8692
|
+
"No registry found in nx.json's persisted config. Pass --registry npm or --registry azure-artifacts (with --organization/--project/--artifacts-feed)."
|
|
8693
|
+
);
|
|
8694
|
+
}
|
|
8695
|
+
function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
8696
|
+
if (persisted.workspaceName) {
|
|
8697
|
+
return persisted.workspaceName;
|
|
8698
|
+
}
|
|
8699
|
+
try {
|
|
8700
|
+
const existing = (0, import_node_fs32.readdirSync)(workspaceRoot).find(
|
|
8701
|
+
(file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
|
|
8702
|
+
);
|
|
8703
|
+
if (existing) {
|
|
8704
|
+
return existing.replace(/\.code-workspace$/, "");
|
|
8705
|
+
}
|
|
8706
|
+
} catch {
|
|
8707
|
+
}
|
|
8708
|
+
return (0, import_node_path37.basename)(workspaceRoot);
|
|
8709
|
+
}
|
|
8710
|
+
function detectNpmAuth(workspaceRoot) {
|
|
8711
|
+
try {
|
|
8712
|
+
return (0, import_node_fs32.readFileSync)((0, import_node_path37.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
|
|
8713
|
+
} catch {
|
|
8714
|
+
return void 0;
|
|
8715
|
+
}
|
|
8716
|
+
}
|
|
8717
|
+
function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
8718
|
+
const scope = options.scope ?? persisted.scope;
|
|
8719
|
+
if (!scope) {
|
|
8720
|
+
throw new Error("No npm scope found in nx.json's persisted config. Pass --scope explicitly.");
|
|
8721
|
+
}
|
|
8722
|
+
const registry = resolveRegistry(options, persisted.registry);
|
|
8723
|
+
const ci = options.ci ?? persisted.ci;
|
|
8724
|
+
if (!ci) {
|
|
8725
|
+
throw new Error(
|
|
8726
|
+
"No CI provider found in nx.json's persisted config. Pass --ci azure|github|both explicitly."
|
|
8727
|
+
);
|
|
8728
|
+
}
|
|
8729
|
+
const agent = options.agent ?? persisted.agent;
|
|
8730
|
+
if (!agent) {
|
|
8731
|
+
throw new Error(
|
|
8732
|
+
"No CI build agent found in nx.json's persisted config. Pass --agent explicitly."
|
|
8733
|
+
);
|
|
8734
|
+
}
|
|
8735
|
+
const variableGroup = options.variableGroup ?? persisted.variableGroup ?? "Build";
|
|
8736
|
+
const detected = ci === "azure" && persisted.npmAuth === void 0 && options.npmAuth === void 0 ? detectNpmAuth(workspaceRoot) : void 0;
|
|
8737
|
+
if (detected) {
|
|
8738
|
+
logger.detail("keeping build-identity npm auth: azure-pipelines.yml already runs npmAuthenticate@0");
|
|
8739
|
+
}
|
|
8740
|
+
const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci, persisted.npmAuth ?? detected);
|
|
8741
|
+
const testRunner = options.testRunner ?? persisted.stack?.testRunner;
|
|
8742
|
+
if (!testRunner) {
|
|
8743
|
+
throw new Error(
|
|
8744
|
+
"No testRunner found in nx.json's persisted config. Pass --test-runner explicitly."
|
|
8745
|
+
);
|
|
8746
|
+
}
|
|
8747
|
+
return {
|
|
8748
|
+
workspaceName: resolveWorkspaceName(workspaceRoot, persisted),
|
|
8749
|
+
scope,
|
|
8750
|
+
registry,
|
|
8751
|
+
agent,
|
|
8752
|
+
variableGroup,
|
|
8753
|
+
ci,
|
|
8754
|
+
stack: { testRunner },
|
|
8755
|
+
...npmAuth && { npmAuth }
|
|
8756
|
+
};
|
|
8757
|
+
}
|
|
8758
|
+
function runUpgrade(workspaceRoot, options) {
|
|
8759
|
+
if (!fileExists((0, import_node_path37.join)(workspaceRoot, "nx.json"))) {
|
|
8760
|
+
throw new Error(
|
|
8761
|
+
`No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
|
|
8762
|
+
);
|
|
8763
|
+
}
|
|
8764
|
+
const persisted = readMnciConfig(workspaceRoot);
|
|
8765
|
+
const resolved = resolveOverlayOptions(workspaceRoot, options, persisted);
|
|
8766
|
+
logger.step("Re-applying the MoNecromanCI overlay");
|
|
8767
|
+
applyOverlay(workspaceRoot, resolved, logger.detail);
|
|
8768
|
+
const repaired = repairRollupSourceMaps(workspaceRoot);
|
|
8769
|
+
if (repaired.length > 0) {
|
|
8770
|
+
logger.step("Enabling source maps in rollup configs (breakpoints in .ts files)");
|
|
8771
|
+
for (const path of repaired) {
|
|
8772
|
+
logger.detail(`updated ${path}`);
|
|
8773
|
+
}
|
|
8774
|
+
}
|
|
8775
|
+
const repairedManifests = repairPublishableManifests(workspaceRoot);
|
|
8776
|
+
if (repairedManifests.length > 0) {
|
|
8777
|
+
logger.step("Repointing `types` at the real declaration file");
|
|
8778
|
+
for (const path of repairedManifests) {
|
|
8779
|
+
logger.detail(`updated ${path}`);
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
const lockfile = pruneStaleLocalRegistry(workspaceRoot);
|
|
8783
|
+
if (lockfile.stale) {
|
|
8784
|
+
logger.step("Dropping the unused local registry (verdaccio) from package-lock.json");
|
|
8785
|
+
if (lockfile.status !== 0) {
|
|
8786
|
+
logger.warn("npm could not re-resolve the lockfile; run `npm install --package-lock-only` once you are online.");
|
|
8787
|
+
}
|
|
8788
|
+
}
|
|
8789
|
+
const goApps = addGoPlatformTargets(workspaceRoot);
|
|
8790
|
+
if (goApps.length > 0) {
|
|
8791
|
+
logger.step("Adding the six-platform build to Go apps (build-all, package-all)");
|
|
8792
|
+
for (const path of goApps) {
|
|
8793
|
+
logger.detail(`updated ${path}`);
|
|
8794
|
+
}
|
|
8795
|
+
}
|
|
8796
|
+
const pinnedExtensions = pinVscodeExtensionProjectNames(workspaceRoot);
|
|
8797
|
+
if (pinnedExtensions.length > 0) {
|
|
8798
|
+
logger.step("Pinning the Nx project name of VS Code extensions (nx.name)");
|
|
8799
|
+
for (const path of pinnedExtensions) {
|
|
8800
|
+
logger.detail(`updated ${path}`);
|
|
8801
|
+
}
|
|
8802
|
+
}
|
|
8803
|
+
if (refreshVscodeExtensionScript(workspaceRoot)) {
|
|
8804
|
+
logger.step("Updating the VS Code extension packaging script");
|
|
8805
|
+
logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
|
|
8806
|
+
}
|
|
8807
|
+
if (refreshGoReleaseScript(workspaceRoot)) {
|
|
8808
|
+
logger.step("Updating the releasable Go app script");
|
|
8809
|
+
logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
|
|
8810
|
+
}
|
|
8811
|
+
if (hasGoProject(workspaceRoot) && registerNxGoPlugin(workspaceRoot)) {
|
|
8812
|
+
logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
|
|
8813
|
+
logger.detail("updated nx.json");
|
|
8814
|
+
}
|
|
8815
|
+
const addedDtsPlugins = addMissingDeclarationSpecifierPlugins(workspaceRoot);
|
|
8816
|
+
if (addedDtsPlugins.length > 0) {
|
|
8817
|
+
logger.step("Adding the declaration-specifier plugin to rollup configs that lacked it");
|
|
8818
|
+
for (const path of addedDtsPlugins) {
|
|
8819
|
+
logger.detail(`updated ${path}`);
|
|
8820
|
+
}
|
|
8821
|
+
}
|
|
8822
|
+
const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
|
|
8823
|
+
if (upgradedDtsPlugins.length > 0) {
|
|
8824
|
+
logger.step("Upgrading declaration specifiers to resolve under nodenext");
|
|
8825
|
+
for (const path of upgradedDtsPlugins) {
|
|
8826
|
+
logger.detail(`updated ${path}`);
|
|
8827
|
+
}
|
|
8828
|
+
}
|
|
8829
|
+
logger.step(
|
|
8830
|
+
"Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
|
|
8831
|
+
);
|
|
8832
|
+
runFormatter(workspaceRoot);
|
|
8833
|
+
const nxJson = readJson((0, import_node_path37.join)(workspaceRoot, "nx.json"));
|
|
8834
|
+
const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
|
|
8835
|
+
for (const entry of stranded) {
|
|
8836
|
+
logger.warn(`${entry.project} has release tags only under ${entry.oldTag}: nx release would restart it from its disk version. Run \`mnci adopt --tags\` before the next release to create ${entry.newTag} locally (\`mnci doctor\` lists them all).`);
|
|
8837
|
+
}
|
|
8838
|
+
logger.success("Done. Review the changes with `git diff` before committing.");
|
|
8839
|
+
logger.info("Run `npm install` and commit package-lock.json too: the overlay may have added or moved a dependency, and CI installs with `npm ci`, which refuses a stale lockfile.");
|
|
8840
|
+
}
|
|
8841
|
+
|
|
8842
|
+
// src/repository-adoption/adopt-overlay.use-case.ts
|
|
8843
|
+
function detectCiProvider(repositoryRoot) {
|
|
8844
|
+
const azure = (0, import_node_fs33.existsSync)((0, import_node_path38.join)(repositoryRoot, "azure-pipelines.yml"));
|
|
8845
|
+
const workflows = (0, import_node_path38.join)(repositoryRoot, ".github", "workflows");
|
|
8846
|
+
const github = (0, import_node_fs33.existsSync)(workflows) && (0, import_node_fs33.readdirSync)(workflows).some((file) => /\.ya?ml$/.test(file));
|
|
8847
|
+
if (azure && github) {
|
|
8848
|
+
return "both";
|
|
8849
|
+
}
|
|
8850
|
+
if (azure) {
|
|
8851
|
+
return "azure";
|
|
8852
|
+
}
|
|
8853
|
+
return github ? "github" : void 0;
|
|
8854
|
+
}
|
|
8855
|
+
function detectTestRunner(repositoryRoot) {
|
|
8856
|
+
const manifestPath = (0, import_node_path38.join)(repositoryRoot, "package.json");
|
|
8857
|
+
if (!fileExists(manifestPath)) {
|
|
8858
|
+
return void 0;
|
|
8859
|
+
}
|
|
8860
|
+
const manifest = readJson(manifestPath);
|
|
8861
|
+
const declared = new Set(Object.keys({ ...manifest.dependencies, ...manifest.devDependencies }));
|
|
8862
|
+
if (declared.has("vitest")) {
|
|
8863
|
+
return "vitest";
|
|
8864
|
+
}
|
|
8865
|
+
return declared.has("jest") ? "jest" : void 0;
|
|
8866
|
+
}
|
|
8867
|
+
function adoptOverlay(repositoryRoot, options, dependencies = {}) {
|
|
8868
|
+
requireCleanWorkingTree(repositoryRoot, dependencies.capture ?? runCapture);
|
|
8869
|
+
if (!fileExists((0, import_node_path38.join)(repositoryRoot, "nx.json"))) {
|
|
8870
|
+
throw new Error("There is no nx.json, so Nx is not set up here. Set it up first (`npx nx@latest init`); adopt does not install Nx yet.");
|
|
8871
|
+
}
|
|
8872
|
+
const persisted = readMnciConfig(repositoryRoot);
|
|
8873
|
+
const filled = {
|
|
8874
|
+
...options,
|
|
8875
|
+
ci: options.ci ?? (persisted.ci === void 0 ? detectCiProvider(repositoryRoot) : void 0),
|
|
8876
|
+
testRunner: options.testRunner ?? (persisted.stack?.testRunner === void 0 ? detectTestRunner(repositoryRoot) : void 0)
|
|
8877
|
+
};
|
|
8878
|
+
(dependencies.upgrade ?? runUpgrade)(repositoryRoot, filled);
|
|
8879
|
+
}
|
|
8880
|
+
|
|
8881
|
+
// src/repository-adoption/adopt-toolchain.use-case.ts
|
|
8882
|
+
var import_node_path40 = require("path");
|
|
8883
|
+
|
|
8884
|
+
// src/repository-adoption/align-nx-family.algorithm.ts
|
|
8885
|
+
var VERSION = /^[\^~]?(\d+)\.(\d+)\.(\d+)$/;
|
|
8886
|
+
function isNxFamily(name) {
|
|
8887
|
+
return name === "nx" || name.startsWith("@nx/");
|
|
8888
|
+
}
|
|
8889
|
+
function compare(left, right) {
|
|
8890
|
+
const a = left.split(".").map(Number);
|
|
8891
|
+
const b = right.split(".").map(Number);
|
|
8892
|
+
return a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || 0;
|
|
8893
|
+
}
|
|
8894
|
+
function chooseNxVersion(declared, published, requested) {
|
|
8895
|
+
const current = Object.entries(declared).filter(([name]) => isNxFamily(name)).map(([, range]) => VERSION.exec(range)).filter((match) => match !== null).map((match) => `${match[1]}.${match[2]}.${match[3]}`);
|
|
8896
|
+
if (current.length === 0) {
|
|
8897
|
+
return void 0;
|
|
8898
|
+
}
|
|
8899
|
+
if (requested !== void 0) {
|
|
8900
|
+
return requested;
|
|
8901
|
+
}
|
|
8902
|
+
const newest = current.toSorted((a, b) => compare(a, b)).at(-1);
|
|
8903
|
+
const major = newest.split(".", 1)[0];
|
|
8904
|
+
const candidates = published.filter((version) => /^\d+\.\d+\.\d+$/.test(version) && version.split(".", 1)[0] === major);
|
|
8905
|
+
return candidates.toSorted((a, b) => compare(a, b)).at(-1);
|
|
8906
|
+
}
|
|
8907
|
+
function alignNxFamily(dependencies, version) {
|
|
8908
|
+
const changed = [];
|
|
8909
|
+
const aligned = Object.fromEntries(Object.entries(dependencies).map(([name, range]) => {
|
|
8910
|
+
if (range !== version && isNxFamily(name)) {
|
|
8911
|
+
changed.push(name);
|
|
8912
|
+
return [name, version];
|
|
8913
|
+
}
|
|
8914
|
+
return [name, range];
|
|
8915
|
+
}));
|
|
8916
|
+
return { dependencies: aligned, changed };
|
|
8917
|
+
}
|
|
8918
|
+
|
|
8919
|
+
// src/repository-adoption/retire-tooling.use-case.ts
|
|
8920
|
+
var import_node_fs34 = require("fs");
|
|
8921
|
+
var import_node_path39 = require("path");
|
|
8922
|
+
var RETIRED_COMMAND = /\b(?:prettier|oxfmt|oxlint)\b/;
|
|
8923
|
+
function retireTooling(repositoryRoot) {
|
|
8924
|
+
const removed = [];
|
|
8925
|
+
for (const file of RETIRED_FORMATTER_FILES) {
|
|
8926
|
+
if (!fileExists((0, import_node_path39.join)(repositoryRoot, file))) {
|
|
8927
|
+
continue;
|
|
8928
|
+
}
|
|
8929
|
+
(0, import_node_fs34.rmSync)((0, import_node_path39.join)(repositoryRoot, file), { force: true });
|
|
8930
|
+
removed.push(file);
|
|
8931
|
+
}
|
|
8932
|
+
const hadRegistry = fileExists((0, import_node_path39.join)(repositoryRoot, ".verdaccio"));
|
|
8933
|
+
removeLocalRegistryScaffolding(repositoryRoot);
|
|
8934
|
+
if (hadRegistry) {
|
|
8935
|
+
removed.push(".verdaccio, its dependency and the local-registry target");
|
|
8936
|
+
}
|
|
8937
|
+
const manifestPath = (0, import_node_path39.join)(repositoryRoot, "package.json");
|
|
8938
|
+
if (!fileExists(manifestPath)) {
|
|
8939
|
+
return removed;
|
|
8940
|
+
}
|
|
8941
|
+
const manifest = readJson(manifestPath);
|
|
8942
|
+
for (const key of ["dependencies", "devDependencies"]) {
|
|
8943
|
+
const before = manifest[key];
|
|
8944
|
+
if (before === void 0) {
|
|
8945
|
+
continue;
|
|
8946
|
+
}
|
|
8947
|
+
const after = withoutRetiredFormatterDependencies(before);
|
|
8948
|
+
const kept = new Set(Object.keys(after));
|
|
8949
|
+
const dropped = Object.keys(before).filter((name) => !kept.has(name));
|
|
8950
|
+
removed.push(...dropped.map((name) => `${key}: ${name}`));
|
|
8951
|
+
manifest[key] = after;
|
|
8952
|
+
}
|
|
8953
|
+
const scripts = Object.entries(manifest.scripts ?? {});
|
|
8954
|
+
for (const [name, command] of scripts) {
|
|
8955
|
+
if (!RETIRED_COMMAND.test(command)) {
|
|
8956
|
+
continue;
|
|
8957
|
+
}
|
|
8958
|
+
Reflect.deleteProperty(manifest.scripts, name);
|
|
8959
|
+
removed.push(`script: ${name} (${command})`);
|
|
8960
|
+
}
|
|
8961
|
+
writeFileEnsured(manifestPath, toJson(manifest));
|
|
8962
|
+
return removed;
|
|
8963
|
+
}
|
|
8964
|
+
|
|
8965
|
+
// src/repository-adoption/adopt-toolchain.use-case.ts
|
|
8966
|
+
var MAX_AUDIT_FIX_PASSES = 4;
|
|
8967
|
+
function publishedNxVersions(repositoryRoot, capture) {
|
|
8968
|
+
const answer = capture("npm", ["view", "nx", "versions", "--json"], repositoryRoot);
|
|
8969
|
+
try {
|
|
8970
|
+
const parsed = JSON.parse(answer.stdout);
|
|
8971
|
+
return Array.isArray(parsed) ? parsed.filter((version) => typeof version === "string") : [];
|
|
8972
|
+
} catch {
|
|
8973
|
+
return [];
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
8976
|
+
function adoptToolchain(repositoryRoot, options = {}, dependencies = {}) {
|
|
8977
|
+
const run = dependencies.run ?? runShell;
|
|
8978
|
+
const capture = dependencies.capture ?? runCapture;
|
|
8979
|
+
const audit = dependencies.audit ?? ((root) => runAudit(root));
|
|
8980
|
+
const log = dependencies.log ?? ((message) => {
|
|
8981
|
+
console.log(message);
|
|
8982
|
+
});
|
|
8983
|
+
requireCleanWorkingTree(repositoryRoot, capture);
|
|
8984
|
+
const manifestPath = (0, import_node_path40.join)(repositoryRoot, "package.json");
|
|
8985
|
+
if (!fileExists(manifestPath)) {
|
|
8986
|
+
throw new Error("No package.json at the repository root.");
|
|
8987
|
+
}
|
|
8988
|
+
log("Removing retired tooling");
|
|
8989
|
+
const removed = retireTooling(repositoryRoot);
|
|
8990
|
+
const manifest = readJson(manifestPath);
|
|
8991
|
+
const version = chooseNxVersion({ ...manifest.dependencies, ...manifest.devDependencies }, publishedNxVersions(repositoryRoot, capture), options.nxVersion);
|
|
8992
|
+
const names = [];
|
|
8993
|
+
if (version !== void 0) {
|
|
8994
|
+
for (const key of ["dependencies", "devDependencies"]) {
|
|
8995
|
+
if (manifest[key] === void 0) {
|
|
8996
|
+
continue;
|
|
8997
|
+
}
|
|
8998
|
+
const result = alignNxFamily(manifest[key], version);
|
|
8999
|
+
manifest[key] = result.dependencies;
|
|
9000
|
+
names.push(...result.changed);
|
|
9001
|
+
}
|
|
9002
|
+
writeFileEnsured(manifestPath, toJson(manifest));
|
|
9003
|
+
}
|
|
9004
|
+
log("Installing, so the lockfile follows the manifest");
|
|
9005
|
+
run("npm", ["install", "--ignore-scripts", "--no-audit", "--no-fund"], repositoryRoot);
|
|
9006
|
+
pruneStaleLocalRegistry(repositoryRoot);
|
|
9007
|
+
let auditFixes = 0;
|
|
9008
|
+
let passes = audit(repositoryRoot) === 0;
|
|
9009
|
+
while (!passes && auditFixes < MAX_AUDIT_FIX_PASSES) {
|
|
9010
|
+
auditFixes += 1;
|
|
9011
|
+
log(`npm audit fix, pass ${auditFixes}`);
|
|
9012
|
+
run("npm", ["audit", "fix", "--no-fund"], repositoryRoot);
|
|
9013
|
+
passes = audit(repositoryRoot) === 0;
|
|
9014
|
+
}
|
|
9015
|
+
return { removed, aligned: { names, version }, auditFixes, auditPasses: passes };
|
|
9016
|
+
}
|
|
9017
|
+
|
|
8488
9018
|
// src/repository-adoption/create-baseline-tags.use-case.ts
|
|
8489
9019
|
function createBaselineTags(repositoryRoot, stranded) {
|
|
8490
9020
|
const result = { created: [], existing: [], failed: [] };
|
|
@@ -8501,8 +9031,8 @@ function createBaselineTags(repositoryRoot, stranded) {
|
|
|
8501
9031
|
}
|
|
8502
9032
|
|
|
8503
9033
|
// src/repository-adoption/inspect-repository.use-case.ts
|
|
8504
|
-
var
|
|
8505
|
-
var
|
|
9034
|
+
var import_node_fs35 = require("fs");
|
|
9035
|
+
var import_node_path41 = require("path");
|
|
8506
9036
|
var LOCKFILES = [
|
|
8507
9037
|
["package-lock.json", "npm"],
|
|
8508
9038
|
["pnpm-lock.yaml", "pnpm"],
|
|
@@ -8523,25 +9053,25 @@ function inspectRepository(repositoryRoot) {
|
|
|
8523
9053
|
const isGitRepo = inside.status === 0 && inside.stdout.trim() === "true";
|
|
8524
9054
|
const dirty = isGitRepo && runCapture("git", ["status", "--porcelain"], repositoryRoot).stdout.trim() !== "";
|
|
8525
9055
|
const tags = isGitRepo ? runCapture("git", ["tag", "--list"], repositoryRoot).stdout.split(/\r?\n/).filter(Boolean) : [];
|
|
8526
|
-
const manifestPath = (0,
|
|
9056
|
+
const manifestPath = (0, import_node_path41.join)(repositoryRoot, "package.json");
|
|
8527
9057
|
const manifest = fileExists(manifestPath) ? readJson(manifestPath) : {};
|
|
8528
|
-
const nxJsonPath = (0,
|
|
9058
|
+
const nxJsonPath = (0, import_node_path41.join)(repositoryRoot, "nx.json");
|
|
8529
9059
|
const nxJson = fileExists(nxJsonPath) ? readJson(nxJsonPath) : {};
|
|
8530
9060
|
const ci = [];
|
|
8531
9061
|
const pipelines = [];
|
|
8532
|
-
if ((0,
|
|
9062
|
+
if ((0, import_node_fs35.existsSync)((0, import_node_path41.join)(repositoryRoot, "azure-pipelines.yml"))) {
|
|
8533
9063
|
ci.push("azure");
|
|
8534
|
-
pipelines.push((0,
|
|
9064
|
+
pipelines.push((0, import_node_path41.join)(repositoryRoot, "azure-pipelines.yml"));
|
|
8535
9065
|
}
|
|
8536
|
-
const workflows = (0,
|
|
8537
|
-
if ((0,
|
|
8538
|
-
const files = (0,
|
|
9066
|
+
const workflows = (0, import_node_path41.join)(repositoryRoot, ".github", "workflows");
|
|
9067
|
+
if ((0, import_node_fs35.existsSync)(workflows)) {
|
|
9068
|
+
const files = (0, import_node_fs35.readdirSync)(workflows).filter((file) => /\.ya?ml$/.test(file));
|
|
8539
9069
|
if (files.length > 0) {
|
|
8540
9070
|
ci.push("github");
|
|
8541
|
-
pipelines.push(...files.map((file) => (0,
|
|
9071
|
+
pipelines.push(...files.map((file) => (0, import_node_path41.join)(workflows, file)));
|
|
8542
9072
|
}
|
|
8543
9073
|
}
|
|
8544
|
-
const rootFiles = (0,
|
|
9074
|
+
const rootFiles = (0, import_node_fs35.readdirSync)(repositoryRoot);
|
|
8545
9075
|
return {
|
|
8546
9076
|
isGitRepo,
|
|
8547
9077
|
dirty,
|
|
@@ -8552,7 +9082,7 @@ function inspectRepository(repositoryRoot) {
|
|
|
8552
9082
|
tagCount: tags.length,
|
|
8553
9083
|
strandedTags: isGitRepo ? locateStrandedReleaseTags(repositoryRoot, nxJson.release?.releaseTag?.pattern) : [],
|
|
8554
9084
|
ci,
|
|
8555
|
-
pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0,
|
|
9085
|
+
pipelineUsesMnci: pipelines.some((file) => /\bmnci ci\b/.test((0, import_node_fs35.readFileSync)(file, "utf8"))),
|
|
8556
9086
|
retiredTooling: [.../* @__PURE__ */ new Set([...rootFiles.filter((file) => RETIRED_FILE_PATTERN.test(file) || file === ".verdaccio"), ...retiredNamesIn(manifest)])],
|
|
8557
9087
|
personalFiles: PERSONAL_FILES.filter((file) => rootFiles.includes(file))
|
|
8558
9088
|
};
|
|
@@ -8582,7 +9112,7 @@ function judgeAdoption(facts) {
|
|
|
8582
9112
|
warning("nx.json already carries an mnci block, so this is an mnci workspace", "use `mnci upgrade`; adopt is for repositories mnci has not touched");
|
|
8583
9113
|
}
|
|
8584
9114
|
if (facts.nxVersion === void 0) {
|
|
8585
|
-
warning("Nx is not installed", "
|
|
9115
|
+
warning("Nx is not installed", "set Nx up first (`npx nx@latest init`); adopt does not install it yet, and the toolchain and overlay steps need an nx.json");
|
|
8586
9116
|
}
|
|
8587
9117
|
if (facts.strandedTags.length > 0) {
|
|
8588
9118
|
warning(
|
|
@@ -8609,6 +9139,18 @@ function reportAdoption(repositoryRoot) {
|
|
|
8609
9139
|
}
|
|
8610
9140
|
function runAdopt(repositoryRoot, options = {}) {
|
|
8611
9141
|
const report = reportAdoption(repositoryRoot);
|
|
9142
|
+
if (options.kinds === true) {
|
|
9143
|
+
runKinds2(repositoryRoot, options);
|
|
9144
|
+
return;
|
|
9145
|
+
}
|
|
9146
|
+
if (options.overlay === true) {
|
|
9147
|
+
runOverlay(repositoryRoot, options);
|
|
9148
|
+
return;
|
|
9149
|
+
}
|
|
9150
|
+
if (options.toolchain === true) {
|
|
9151
|
+
runToolchain(repositoryRoot, options);
|
|
9152
|
+
return;
|
|
9153
|
+
}
|
|
8612
9154
|
if (options.tags === true) {
|
|
8613
9155
|
runBaselineTags(repositoryRoot, report);
|
|
8614
9156
|
return;
|
|
@@ -8666,6 +9208,76 @@ function runBaselineTags(repositoryRoot, report) {
|
|
|
8666
9208
|
logger.info("A tag made under the new name at a LOWER version (for example @scope/x@0.0.5) stays; the baseline outranks it, and removing it from the remote is your call.");
|
|
8667
9209
|
}
|
|
8668
9210
|
}
|
|
9211
|
+
function runToolchain(repositoryRoot, options) {
|
|
9212
|
+
try {
|
|
9213
|
+
const result = adoptToolchain(repositoryRoot, { nxVersion: options.nx }, { log: (message) => {
|
|
9214
|
+
logger.step(message);
|
|
9215
|
+
} });
|
|
9216
|
+
for (const line of result.removed) {
|
|
9217
|
+
logger.info(`removed ${line}`);
|
|
9218
|
+
}
|
|
9219
|
+
if (result.aligned.version === void 0) {
|
|
9220
|
+
logger.info("Nx is not declared at the root, so there is no family to align.");
|
|
9221
|
+
} else {
|
|
9222
|
+
logger.info(`Nx family at ${result.aligned.version}${result.aligned.names.length > 0 ? ` (moved: ${result.aligned.names.join(", ")})` : " (already aligned)"}`);
|
|
9223
|
+
}
|
|
9224
|
+
if (result.auditPasses) {
|
|
9225
|
+
logger.success(`The audit gate passes${result.auditFixes > 0 ? ` after ${result.auditFixes} npm audit fix pass(es)` : ""}. Review with \`git diff\` and commit package.json and package-lock.json.`);
|
|
9226
|
+
} else {
|
|
9227
|
+
logger.error("The audit gate still fails after npm audit fix. Run `mnci ci audit` to see what is left; a targeted overrides entry is the usual answer.");
|
|
9228
|
+
process.exitCode = 1;
|
|
9229
|
+
}
|
|
9230
|
+
} catch (error) {
|
|
9231
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
9232
|
+
process.exitCode = 1;
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
9235
|
+
function runOverlay(repositoryRoot, options) {
|
|
9236
|
+
try {
|
|
9237
|
+
adoptOverlay(repositoryRoot, options);
|
|
9238
|
+
logger.info("Steps of your old pipeline that mnci does not recognise are in its slots (# mnci:slot); anything it could not carry over was listed above.");
|
|
9239
|
+
logger.info("Run `mnci doctor` to confirm the verify phase is active, then review with `git diff`.");
|
|
9240
|
+
} catch (error) {
|
|
9241
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
9242
|
+
process.exitCode = 1;
|
|
9243
|
+
}
|
|
9244
|
+
}
|
|
9245
|
+
function parseKindChoices(choices) {
|
|
9246
|
+
const parsed = {};
|
|
9247
|
+
for (const choice of choices) {
|
|
9248
|
+
const [dir, kind] = choice.split("=", 2);
|
|
9249
|
+
if (dir === "" || kind === void 0 || kind === "") {
|
|
9250
|
+
throw new Error(`--kind ${choice}: write it as <directory>=<kind>, for example --kind apps/api=node-app`);
|
|
9251
|
+
}
|
|
9252
|
+
parsed[dir] = kind;
|
|
9253
|
+
}
|
|
9254
|
+
return parsed;
|
|
9255
|
+
}
|
|
9256
|
+
function runKinds2(repositoryRoot, options) {
|
|
9257
|
+
try {
|
|
9258
|
+
const outcomes = adoptKinds(repositoryRoot, parseKindChoices(options.kind ?? []));
|
|
9259
|
+
for (const outcome of outcomes) {
|
|
9260
|
+
const line = `${outcome.dir.padEnd(30)} ${outcome.kind} (${outcome.reason})`;
|
|
9261
|
+
if (outcome.outcome === "tagged") {
|
|
9262
|
+
logger.success(`tagged ${line}`);
|
|
9263
|
+
} else if (outcome.outcome === "already") {
|
|
9264
|
+
logger.info(`kept ${line}`);
|
|
9265
|
+
} else {
|
|
9266
|
+
logger.warn(`guessed ${line}`);
|
|
9267
|
+
}
|
|
9268
|
+
}
|
|
9269
|
+
const undecided = outcomes.filter((outcome) => outcome.outcome === "undecided");
|
|
9270
|
+
if (undecided.length > 0) {
|
|
9271
|
+
logger.error(`${undecided.length} project(s) need you to choose. Run again with ${undecided.map((outcome) => `--kind ${outcome.dir}=${outcome.kind}`).join(" ")} to accept the guesses, or name another kind.`);
|
|
9272
|
+
process.exitCode = 1;
|
|
9273
|
+
} else {
|
|
9274
|
+
logger.success("Every project has a kind. Review with `git diff` and commit.");
|
|
9275
|
+
}
|
|
9276
|
+
} catch (error) {
|
|
9277
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
9278
|
+
process.exitCode = 1;
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
8669
9281
|
|
|
8670
9282
|
// src/command-catalog/command-groups.config.ts
|
|
8671
9283
|
var COMMAND_GROUPS = {
|
|
@@ -8738,13 +9350,15 @@ function runCommands(program, options) {
|
|
|
8738
9350
|
}
|
|
8739
9351
|
|
|
8740
9352
|
// src/workspace-info/list-projects.use-case.ts
|
|
8741
|
-
var
|
|
9353
|
+
var import_node_path42 = require("path");
|
|
8742
9354
|
var TYPE_TAG_PREFIX = "type:";
|
|
8743
9355
|
function listProjects(workspaceRoot) {
|
|
8744
9356
|
return locateProjects(workspaceRoot).map((location) => {
|
|
8745
|
-
const projectJsonPath = (0,
|
|
9357
|
+
const projectJsonPath = (0, import_node_path42.join)(workspaceRoot, location.dir, "project.json");
|
|
8746
9358
|
const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
|
|
8747
|
-
const
|
|
9359
|
+
const manifestPath = (0, import_node_path42.join)(workspaceRoot, location.dir, "package.json");
|
|
9360
|
+
const manifestTags = fileExists(manifestPath) ? readJson(manifestPath).nx?.tags ?? [] : [];
|
|
9361
|
+
const typeTag = [...project.tags ?? [], ...manifestTags].find((tag) => tag.startsWith(TYPE_TAG_PREFIX));
|
|
8748
9362
|
return {
|
|
8749
9363
|
name: location.name,
|
|
8750
9364
|
dir: location.dir,
|
|
@@ -8755,7 +9369,7 @@ function listProjects(workspaceRoot) {
|
|
|
8755
9369
|
}).toSorted((a, b) => a.dir.localeCompare(b.dir));
|
|
8756
9370
|
}
|
|
8757
9371
|
function runProjects(workspaceRoot, options) {
|
|
8758
|
-
if (!fileExists((0,
|
|
9372
|
+
if (!fileExists((0, import_node_path42.join)(workspaceRoot, "nx.json"))) {
|
|
8759
9373
|
throw new Error("No nx.json found here. Run `projects` from the workspace root.");
|
|
8760
9374
|
}
|
|
8761
9375
|
const projects = listProjects(workspaceRoot);
|
|
@@ -8769,11 +9383,11 @@ function runProjects(workspaceRoot, options) {
|
|
|
8769
9383
|
}
|
|
8770
9384
|
|
|
8771
9385
|
// src/workspace-info/read-workspace-info.use-case.ts
|
|
8772
|
-
var
|
|
9386
|
+
var import_node_path44 = require("path");
|
|
8773
9387
|
|
|
8774
9388
|
// src/cli-version/check-for-update.use-case.ts
|
|
8775
|
-
var
|
|
8776
|
-
var
|
|
9389
|
+
var import_node_fs36 = require("fs");
|
|
9390
|
+
var import_node_path43 = require("path");
|
|
8777
9391
|
var import_cross_spawn3 = __toESM(require("cross-spawn"));
|
|
8778
9392
|
var PACKAGE_NAME2 = "@mnci/cli";
|
|
8779
9393
|
var REGISTRY_TIMEOUT_MS = 2e3;
|
|
@@ -8832,8 +9446,8 @@ function releaseTriple(version) {
|
|
|
8832
9446
|
}
|
|
8833
9447
|
function readCliVersion(packageDirectory) {
|
|
8834
9448
|
try {
|
|
8835
|
-
const manifestPath = (0,
|
|
8836
|
-
const manifest = JSON.parse((0,
|
|
9449
|
+
const manifestPath = (0, import_node_path43.join)(packageDirectory, "..", "package.json");
|
|
9450
|
+
const manifest = JSON.parse((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
8837
9451
|
return manifest.version ?? "0.0.0";
|
|
8838
9452
|
} catch {
|
|
8839
9453
|
return "0.0.0";
|
|
@@ -8843,7 +9457,7 @@ function readCliVersion(packageDirectory) {
|
|
|
8843
9457
|
// src/workspace-info/read-workspace-info.use-case.ts
|
|
8844
9458
|
function readWorkspaceInfo(workspaceRoot, cliVersion) {
|
|
8845
9459
|
const latest = fetchLatestVersion() ?? null;
|
|
8846
|
-
const isWorkspace = fileExists((0,
|
|
9460
|
+
const isWorkspace = fileExists((0, import_node_path44.join)(workspaceRoot, "nx.json"));
|
|
8847
9461
|
return {
|
|
8848
9462
|
cli: {
|
|
8849
9463
|
version: cliVersion,
|
|
@@ -8864,8 +9478,8 @@ function runInfo(workspaceRoot, cliVersion, options) {
|
|
|
8864
9478
|
}
|
|
8865
9479
|
|
|
8866
9480
|
// src/workspace-creation/adopt-directory.use-case.ts
|
|
8867
|
-
var
|
|
8868
|
-
var
|
|
9481
|
+
var import_node_fs37 = require("fs");
|
|
9482
|
+
var import_node_path45 = require("path");
|
|
8869
9483
|
var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
8870
9484
|
var AGENT_AND_CI_ENTRIES = [
|
|
8871
9485
|
"AGENTS.md",
|
|
@@ -8896,13 +9510,13 @@ var PREFLIGHT_BLOCKERS = [
|
|
|
8896
9510
|
"packages"
|
|
8897
9511
|
];
|
|
8898
9512
|
function assertAdoptableDirectory(target) {
|
|
8899
|
-
if (!(0,
|
|
9513
|
+
if (!(0, import_node_fs37.existsSync)(target)) {
|
|
8900
9514
|
throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
|
|
8901
9515
|
}
|
|
8902
|
-
if (!(0,
|
|
9516
|
+
if (!(0, import_node_fs37.statSync)(target).isDirectory()) {
|
|
8903
9517
|
throw new Error(`--into '${target}' is not a directory.`);
|
|
8904
9518
|
}
|
|
8905
|
-
const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0,
|
|
9519
|
+
const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs37.existsSync)((0, import_node_path45.join)(target, entry)));
|
|
8906
9520
|
if (blockers.length > 0) {
|
|
8907
9521
|
throw new Error(
|
|
8908
9522
|
`--into '${target}' already holds ${blockers.join(", ")}, so it is a project already. Use \`mnci upgrade\` to re-apply the overlay to an existing workspace, or point --into at an empty checkout.`
|
|
@@ -8910,15 +9524,15 @@ function assertAdoptableDirectory(target) {
|
|
|
8910
9524
|
}
|
|
8911
9525
|
}
|
|
8912
9526
|
function mergeGitignore(generatedFile, targetFile) {
|
|
8913
|
-
const existing = (0,
|
|
9527
|
+
const existing = (0, import_node_fs37.readFileSync)(targetFile, "utf8");
|
|
8914
9528
|
const present = new Set(existing.split("\n").map((line) => line.trim()));
|
|
8915
|
-
const additions = (0,
|
|
9529
|
+
const additions = (0, import_node_fs37.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
|
|
8916
9530
|
const trimmed = line.trim();
|
|
8917
9531
|
return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
|
|
8918
9532
|
});
|
|
8919
9533
|
if (additions.length === 0) return false;
|
|
8920
9534
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
8921
|
-
(0,
|
|
9535
|
+
(0, import_node_fs37.writeFileSync)(
|
|
8922
9536
|
targetFile,
|
|
8923
9537
|
`${existing}${separator}
|
|
8924
9538
|
# Added by mnci (Nx workspace)
|
|
@@ -8928,9 +9542,9 @@ ${additions.join("\n")}
|
|
|
8928
9542
|
return true;
|
|
8929
9543
|
}
|
|
8930
9544
|
function adoptGeneratedWorkspace(generatedRoot, target) {
|
|
8931
|
-
const entries = (0,
|
|
9545
|
+
const entries = (0, import_node_fs37.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
|
|
8932
9546
|
const collisions = entries.filter(
|
|
8933
|
-
(entry) => (0,
|
|
9547
|
+
(entry) => (0, import_node_fs37.existsSync)((0, import_node_path45.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
|
|
8934
9548
|
);
|
|
8935
9549
|
if (collisions.length > 0) {
|
|
8936
9550
|
throw new Error(
|
|
@@ -8939,28 +9553,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
|
|
|
8939
9553
|
}
|
|
8940
9554
|
const result = { copied: [], kept: [], mergedGitignore: false };
|
|
8941
9555
|
for (const entry of entries) {
|
|
8942
|
-
const from = (0,
|
|
8943
|
-
const to = (0,
|
|
8944
|
-
if (entry === ".gitignore" && (0,
|
|
9556
|
+
const from = (0, import_node_path45.join)(generatedRoot, entry);
|
|
9557
|
+
const to = (0, import_node_path45.join)(target, entry);
|
|
9558
|
+
if (entry === ".gitignore" && (0, import_node_fs37.existsSync)(to)) {
|
|
8945
9559
|
result.mergedGitignore = mergeGitignore(from, to);
|
|
8946
9560
|
result.kept.push(entry);
|
|
8947
9561
|
continue;
|
|
8948
9562
|
}
|
|
8949
|
-
if ((0,
|
|
9563
|
+
if ((0, import_node_fs37.existsSync)(to)) {
|
|
8950
9564
|
result.kept.push(entry);
|
|
8951
9565
|
continue;
|
|
8952
9566
|
}
|
|
8953
|
-
(0,
|
|
9567
|
+
(0, import_node_fs37.cpSync)(from, to, { recursive: true });
|
|
8954
9568
|
result.copied.push(entry);
|
|
8955
9569
|
}
|
|
8956
|
-
(0,
|
|
9570
|
+
(0, import_node_fs37.rmSync)(generatedRoot, { recursive: true, force: true });
|
|
8957
9571
|
return result;
|
|
8958
9572
|
}
|
|
8959
9573
|
|
|
8960
9574
|
// src/workspace-creation/create-workspace.use-case.ts
|
|
8961
|
-
var
|
|
9575
|
+
var import_node_fs38 = require("fs");
|
|
8962
9576
|
var import_node_os2 = require("os");
|
|
8963
|
-
var
|
|
9577
|
+
var import_node_path46 = require("path");
|
|
8964
9578
|
function nxCloudProviderValue(ci) {
|
|
8965
9579
|
return ci === "azure" ? "azure" : "github";
|
|
8966
9580
|
}
|
|
@@ -8985,7 +9599,7 @@ async function resolveCi(options) {
|
|
|
8985
9599
|
return await promptCi();
|
|
8986
9600
|
}
|
|
8987
9601
|
var REGISTRY_KINDS = /* @__PURE__ */ new Set(["azure-artifacts", "npm"]);
|
|
8988
|
-
async function
|
|
9602
|
+
async function resolveRegistry2(options) {
|
|
8989
9603
|
if (options.registry !== void 0 && !REGISTRY_KINDS.has(options.registry)) {
|
|
8990
9604
|
throw new Error(`Invalid --registry '${options.registry}'. Valid values: azure-artifacts, npm.`);
|
|
8991
9605
|
}
|
|
@@ -9003,12 +9617,12 @@ async function resolveRegistry(options) {
|
|
|
9003
9617
|
return await promptRegistry();
|
|
9004
9618
|
}
|
|
9005
9619
|
async function runNew(name, options) {
|
|
9006
|
-
const adoptTarget = options.into === void 0 ? void 0 : (0,
|
|
9620
|
+
const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path46.resolve)(process.cwd(), options.into);
|
|
9007
9621
|
if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
|
|
9008
|
-
const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0,
|
|
9622
|
+
const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path46.basename)(adoptTarget));
|
|
9009
9623
|
assertValidProjectName(workspaceName, "Workspace name");
|
|
9010
9624
|
const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
|
|
9011
|
-
const registry = await
|
|
9625
|
+
const registry = await resolveRegistry2(options);
|
|
9012
9626
|
const ci = await resolveCi(options);
|
|
9013
9627
|
const agent = options.agent ?? (options.yes ? "ubuntu-latest" : await promptText(
|
|
9014
9628
|
"CI build agent/runner (vmImage, GitHub Actions runner label, or self-hosted pool name)",
|
|
@@ -9018,8 +9632,8 @@ async function runNew(name, options) {
|
|
|
9018
9632
|
const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
|
|
9019
9633
|
const stack = await resolveStack(options);
|
|
9020
9634
|
const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
|
|
9021
|
-
const stagingParent = adoptTarget === void 0 ? process.cwd() : (0,
|
|
9022
|
-
let workspaceRoot = (0,
|
|
9635
|
+
const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs38.mkdtempSync)((0, import_node_path46.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
|
|
9636
|
+
let workspaceRoot = (0, import_node_path46.join)(stagingParent, workspaceName);
|
|
9023
9637
|
try {
|
|
9024
9638
|
logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
|
|
9025
9639
|
runNpx(
|
|
@@ -9042,7 +9656,7 @@ async function runNew(name, options) {
|
|
|
9042
9656
|
workspaceRoot = adoptTarget;
|
|
9043
9657
|
}
|
|
9044
9658
|
} finally {
|
|
9045
|
-
if (adoptTarget !== void 0) (0,
|
|
9659
|
+
if (adoptTarget !== void 0) (0, import_node_fs38.rmSync)(stagingParent, { recursive: true, force: true });
|
|
9046
9660
|
}
|
|
9047
9661
|
logger.step(
|
|
9048
9662
|
"Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
|
|
@@ -9052,8 +9666,8 @@ async function runNew(name, options) {
|
|
|
9052
9666
|
{ workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
|
|
9053
9667
|
logger.detail
|
|
9054
9668
|
);
|
|
9055
|
-
(0,
|
|
9056
|
-
(0,
|
|
9669
|
+
(0, import_node_fs38.rmSync)((0, import_node_path46.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
|
|
9670
|
+
(0, import_node_fs38.rmSync)((0, import_node_path46.join)(workspaceRoot, "package-lock.json"), { force: true });
|
|
9057
9671
|
logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
|
|
9058
9672
|
const installStatus = runShell(
|
|
9059
9673
|
"npm",
|
|
@@ -9091,185 +9705,10 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
|
|
|
9091
9705
|
}
|
|
9092
9706
|
|
|
9093
9707
|
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
9094
|
-
var
|
|
9708
|
+
var import_node_path47 = require("path");
|
|
9095
9709
|
var import_prompts4 = require("@inquirer/prompts");
|
|
9096
|
-
|
|
9097
|
-
// src/workspace-upgrade/upgrade-workspace.use-case.ts
|
|
9098
|
-
var import_node_fs35 = require("fs");
|
|
9099
|
-
var import_node_path42 = require("path");
|
|
9100
|
-
function resolveRegistry2(options, persisted) {
|
|
9101
|
-
if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
|
|
9102
|
-
const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
|
|
9103
|
-
const organization = options.organization ?? persistedAzure?.organization;
|
|
9104
|
-
const project = options.project ?? persistedAzure?.project;
|
|
9105
|
-
const artifactsFeed = options.artifactsFeed ?? persistedAzure?.artifactsFeed;
|
|
9106
|
-
if (!organization || !project || !artifactsFeed) {
|
|
9107
|
-
throw new Error(
|
|
9108
|
-
"Azure Artifacts registry needs --organization, --project and --artifacts-feed (none found in nx.json's persisted config either)."
|
|
9109
|
-
);
|
|
9110
|
-
}
|
|
9111
|
-
return { kind: "azure-artifacts", organization, project, artifactsFeed };
|
|
9112
|
-
}
|
|
9113
|
-
if (options.registry === "npm") {
|
|
9114
|
-
return { kind: "npm" };
|
|
9115
|
-
}
|
|
9116
|
-
if (persisted) {
|
|
9117
|
-
return persisted;
|
|
9118
|
-
}
|
|
9119
|
-
throw new Error(
|
|
9120
|
-
"No registry found in nx.json's persisted config. Pass --registry npm or --registry azure-artifacts (with --organization/--project/--artifacts-feed)."
|
|
9121
|
-
);
|
|
9122
|
-
}
|
|
9123
|
-
function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
9124
|
-
if (persisted.workspaceName) {
|
|
9125
|
-
return persisted.workspaceName;
|
|
9126
|
-
}
|
|
9127
|
-
try {
|
|
9128
|
-
const existing = (0, import_node_fs35.readdirSync)(workspaceRoot).find(
|
|
9129
|
-
(file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
|
|
9130
|
-
);
|
|
9131
|
-
if (existing) {
|
|
9132
|
-
return existing.replace(/\.code-workspace$/, "");
|
|
9133
|
-
}
|
|
9134
|
-
} catch {
|
|
9135
|
-
}
|
|
9136
|
-
return (0, import_node_path42.basename)(workspaceRoot);
|
|
9137
|
-
}
|
|
9138
|
-
function detectNpmAuth(workspaceRoot) {
|
|
9139
|
-
try {
|
|
9140
|
-
return (0, import_node_fs35.readFileSync)((0, import_node_path42.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
|
|
9141
|
-
} catch {
|
|
9142
|
-
return void 0;
|
|
9143
|
-
}
|
|
9144
|
-
}
|
|
9145
|
-
function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
9146
|
-
const scope = options.scope ?? persisted.scope;
|
|
9147
|
-
if (!scope) {
|
|
9148
|
-
throw new Error("No npm scope found in nx.json's persisted config. Pass --scope explicitly.");
|
|
9149
|
-
}
|
|
9150
|
-
const registry = resolveRegistry2(options, persisted.registry);
|
|
9151
|
-
const ci = options.ci ?? persisted.ci;
|
|
9152
|
-
if (!ci) {
|
|
9153
|
-
throw new Error(
|
|
9154
|
-
"No CI provider found in nx.json's persisted config. Pass --ci azure|github|both explicitly."
|
|
9155
|
-
);
|
|
9156
|
-
}
|
|
9157
|
-
const agent = options.agent ?? persisted.agent;
|
|
9158
|
-
if (!agent) {
|
|
9159
|
-
throw new Error(
|
|
9160
|
-
"No CI build agent found in nx.json's persisted config. Pass --agent explicitly."
|
|
9161
|
-
);
|
|
9162
|
-
}
|
|
9163
|
-
const variableGroup = options.variableGroup ?? persisted.variableGroup ?? "Build";
|
|
9164
|
-
const detected = ci === "azure" && persisted.npmAuth === void 0 && options.npmAuth === void 0 ? detectNpmAuth(workspaceRoot) : void 0;
|
|
9165
|
-
if (detected) {
|
|
9166
|
-
logger.detail("keeping build-identity npm auth: azure-pipelines.yml already runs npmAuthenticate@0");
|
|
9167
|
-
}
|
|
9168
|
-
const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci, persisted.npmAuth ?? detected);
|
|
9169
|
-
const testRunner = options.testRunner ?? persisted.stack?.testRunner;
|
|
9170
|
-
if (!testRunner) {
|
|
9171
|
-
throw new Error(
|
|
9172
|
-
"No testRunner found in nx.json's persisted config. Pass --test-runner explicitly."
|
|
9173
|
-
);
|
|
9174
|
-
}
|
|
9175
|
-
return {
|
|
9176
|
-
workspaceName: resolveWorkspaceName(workspaceRoot, persisted),
|
|
9177
|
-
scope,
|
|
9178
|
-
registry,
|
|
9179
|
-
agent,
|
|
9180
|
-
variableGroup,
|
|
9181
|
-
ci,
|
|
9182
|
-
stack: { testRunner },
|
|
9183
|
-
...npmAuth && { npmAuth }
|
|
9184
|
-
};
|
|
9185
|
-
}
|
|
9186
|
-
function runUpgrade(workspaceRoot, options) {
|
|
9187
|
-
if (!fileExists((0, import_node_path42.join)(workspaceRoot, "nx.json"))) {
|
|
9188
|
-
throw new Error(
|
|
9189
|
-
`No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
|
|
9190
|
-
);
|
|
9191
|
-
}
|
|
9192
|
-
const persisted = readMnciConfig(workspaceRoot);
|
|
9193
|
-
const resolved = resolveOverlayOptions(workspaceRoot, options, persisted);
|
|
9194
|
-
logger.step("Re-applying the MoNecromanCI overlay");
|
|
9195
|
-
applyOverlay(workspaceRoot, resolved, logger.detail);
|
|
9196
|
-
const repaired = repairRollupSourceMaps(workspaceRoot);
|
|
9197
|
-
if (repaired.length > 0) {
|
|
9198
|
-
logger.step("Enabling source maps in rollup configs (breakpoints in .ts files)");
|
|
9199
|
-
for (const path of repaired) {
|
|
9200
|
-
logger.detail(`updated ${path}`);
|
|
9201
|
-
}
|
|
9202
|
-
}
|
|
9203
|
-
const repairedManifests = repairPublishableManifests(workspaceRoot);
|
|
9204
|
-
if (repairedManifests.length > 0) {
|
|
9205
|
-
logger.step("Repointing `types` at the real declaration file");
|
|
9206
|
-
for (const path of repairedManifests) {
|
|
9207
|
-
logger.detail(`updated ${path}`);
|
|
9208
|
-
}
|
|
9209
|
-
}
|
|
9210
|
-
const lockfile = pruneStaleLocalRegistry(workspaceRoot);
|
|
9211
|
-
if (lockfile.stale) {
|
|
9212
|
-
logger.step("Dropping the unused local registry (verdaccio) from package-lock.json");
|
|
9213
|
-
if (lockfile.status !== 0) {
|
|
9214
|
-
logger.warn("npm could not re-resolve the lockfile; run `npm install --package-lock-only` once you are online.");
|
|
9215
|
-
}
|
|
9216
|
-
}
|
|
9217
|
-
const goApps = addGoPlatformTargets(workspaceRoot);
|
|
9218
|
-
if (goApps.length > 0) {
|
|
9219
|
-
logger.step("Adding the six-platform build to Go apps (build-all, package-all)");
|
|
9220
|
-
for (const path of goApps) {
|
|
9221
|
-
logger.detail(`updated ${path}`);
|
|
9222
|
-
}
|
|
9223
|
-
}
|
|
9224
|
-
const pinnedExtensions = pinVscodeExtensionProjectNames(workspaceRoot);
|
|
9225
|
-
if (pinnedExtensions.length > 0) {
|
|
9226
|
-
logger.step("Pinning the Nx project name of VS Code extensions (nx.name)");
|
|
9227
|
-
for (const path of pinnedExtensions) {
|
|
9228
|
-
logger.detail(`updated ${path}`);
|
|
9229
|
-
}
|
|
9230
|
-
}
|
|
9231
|
-
if (refreshVscodeExtensionScript(workspaceRoot)) {
|
|
9232
|
-
logger.step("Updating the VS Code extension packaging script");
|
|
9233
|
-
logger.detail(`updated ${VSCODE_EXTENSION_SCRIPT_PATH}`);
|
|
9234
|
-
}
|
|
9235
|
-
if (refreshGoReleaseScript(workspaceRoot)) {
|
|
9236
|
-
logger.step("Updating the releasable Go app script");
|
|
9237
|
-
logger.detail(`updated ${GO_RELEASE_SCRIPT_PATH}`);
|
|
9238
|
-
}
|
|
9239
|
-
if (hasGoProject(workspaceRoot) && registerNxGoPlugin(workspaceRoot)) {
|
|
9240
|
-
logger.step("Registering the Go plugin in nx.json, so Nx can see which Go project imports which");
|
|
9241
|
-
logger.detail("updated nx.json");
|
|
9242
|
-
}
|
|
9243
|
-
const addedDtsPlugins = addMissingDeclarationSpecifierPlugins(workspaceRoot);
|
|
9244
|
-
if (addedDtsPlugins.length > 0) {
|
|
9245
|
-
logger.step("Adding the declaration-specifier plugin to rollup configs that lacked it");
|
|
9246
|
-
for (const path of addedDtsPlugins) {
|
|
9247
|
-
logger.detail(`updated ${path}`);
|
|
9248
|
-
}
|
|
9249
|
-
}
|
|
9250
|
-
const upgradedDtsPlugins = upgradeDeclarationSpecifierPlugins(workspaceRoot);
|
|
9251
|
-
if (upgradedDtsPlugins.length > 0) {
|
|
9252
|
-
logger.step("Upgrading declaration specifiers to resolve under nodenext");
|
|
9253
|
-
for (const path of upgradedDtsPlugins) {
|
|
9254
|
-
logger.detail(`updated ${path}`);
|
|
9255
|
-
}
|
|
9256
|
-
}
|
|
9257
|
-
logger.step(
|
|
9258
|
-
"Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
|
|
9259
|
-
);
|
|
9260
|
-
runFormatter(workspaceRoot);
|
|
9261
|
-
const nxJson = readJson((0, import_node_path42.join)(workspaceRoot, "nx.json"));
|
|
9262
|
-
const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
|
|
9263
|
-
for (const entry of stranded) {
|
|
9264
|
-
logger.warn(`${entry.project} has release tags only under ${entry.oldTag}: nx release would restart it from its disk version. Run \`git tag ${entry.newTag} ${entry.oldTag}^{commit}\` before the next release (\`mnci doctor\` lists them all).`);
|
|
9265
|
-
}
|
|
9266
|
-
logger.success("Done. Review the changes with `git diff` before committing.");
|
|
9267
|
-
logger.info("Run `npm install` and commit package-lock.json too: the overlay may have added or moved a dependency, and CI installs with `npm ci`, which refuses a stale lockfile.");
|
|
9268
|
-
}
|
|
9269
|
-
|
|
9270
|
-
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
9271
9710
|
async function runInteractive() {
|
|
9272
|
-
const inWorkspace = fileExists((0,
|
|
9711
|
+
const inWorkspace = fileExists((0, import_node_path47.join)(process.cwd(), "nx.json"));
|
|
9273
9712
|
const choiceNew = { name: "Create a new monorepo", value: "new" };
|
|
9274
9713
|
const choiceAdd = { name: "Add a project to this workspace", value: "add" };
|
|
9275
9714
|
const choiceUpgrade = {
|
|
@@ -9321,7 +9760,7 @@ function buildProgram(cliVersion) {
|
|
|
9321
9760
|
).option("--json", "print the findings as one JSON document, each with its remedy").action((options) => {
|
|
9322
9761
|
runDoctor(process.cwd(), options);
|
|
9323
9762
|
});
|
|
9324
|
-
program.command("adopt").description("Read an existing repository and report what bringing it under mnci would involve: blockers, warnings and the step that clears each. Read-only unless a step flag is given; exits non-zero when something blocks").option("--json", "print the report as one JSON document").option("--tags", "create, locally, the baseline tag each project whose release tags are stranded under an old name needs; nothing is pushed").action((options) => {
|
|
9763
|
+
program.command("adopt").description("Read an existing repository and report what bringing it under mnci would involve: blockers, warnings and the step that clears each. Read-only unless a step flag is given; exits non-zero when something blocks").option("--json", "print the report as one JSON document").option("--tags", "create, locally, the baseline tag each project whose release tags are stranded under an old name needs; nothing is pushed").option("--toolchain", "retire old formatter and registry tooling, align the Nx family to one version and run npm audit fix until the audit gate passes; needs a clean git tree and leaves the changes uncommitted").option("--nx <version>", "the Nx version --toolchain aligns to (default: the newest published in the major already in use)").option("--kinds", "record each project's mnci kind as a type:<kind> tag (npm, Python, Go, Flutter and C# projects); a project where two kinds fit is listed with a guess and not tagged; needs a clean git tree").option("--kind <dir=kind>", "the kind you choose for one project, for --kinds (repeatable)", (value, previous = []) => [...previous, value]).option("--overlay", "apply the mnci overlay (release config, pipeline, npmrc, commitlint, scripts) with the flags mnci upgrade takes; the pipeline keeps the steps mnci does not recognise in its slots; needs a clean git tree and an nx.json").option("--scope <scope>", "npm scope for publishable packages (--overlay)").option("--registry <kind>", "azure-artifacts | npm (--overlay)").option("--organization <name>", "Azure DevOps organization (--overlay)").option("--project <name>", "Azure DevOps project (--overlay)").option("--artifacts-feed <name>", "Azure Artifacts feed (--overlay)").option("--agent <pool>", "CI build agent (--overlay)").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT (--overlay)").option("--npm-auth <mode>", "pat (default) | build-identity (--overlay, --ci azure only)").option("--ci <provider>", "azure | github | both (--overlay; default: what the repository already has)").option("--test-runner <runner>", "jest | vitest (--overlay; default: what the repository already declares)").action((options) => {
|
|
9325
9764
|
runAdopt(process.cwd(), options);
|
|
9326
9765
|
});
|
|
9327
9766
|
program.command("ci").addArgument(new import_commander.Argument("<phase>", "which phase of the pipeline to run").choices(CI_PHASES)).description(
|