@mnci/cli 4.6.2 → 4.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 +59 -0
- package/dist/cli.js +181 -30
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,7 @@ consumers point at it.
|
|
|
81
81
|
mnci new my-repo # create a monorepo (prompts scope + registry)
|
|
82
82
|
mnci new my-repo --yes --registry npm --scope @my
|
|
83
83
|
mnci new my-repo --yes --registry npm --scope @my --nx-cloud # opt in to Nx Cloud
|
|
84
|
+
mnci new --into . # ...or bootstrap into a clone that already exists
|
|
84
85
|
|
|
85
86
|
cd my-repo
|
|
86
87
|
mnci add react-app web # @nx/react (Vite + Jest)
|
|
@@ -613,6 +614,23 @@ the editor. It also makes `space-before-function-paren` enforceable for the
|
|
|
613
614
|
first time: every Prettier-compatible formatter, oxfmt included, rewrites
|
|
614
615
|
`function f (a)` back to `function f(a)`.
|
|
615
616
|
|
|
617
|
+
**`npm run lint` checks one thing `npm run format` does not.** `lint` is
|
|
618
|
+
`nx run-many -t lint`; `format` is a bare `eslint . --fix --cache`. The
|
|
619
|
+
`@nx/dependency-checks` rule needs the Nx project graph, and outside a target it
|
|
620
|
+
prints `No cached ProjectGraph is available. The rule will be skipped.` So a
|
|
621
|
+
dependency problem shows up in `lint` and never in `format`, your editor, or a
|
|
622
|
+
pre-commit hook.
|
|
623
|
+
|
|
624
|
+
That asymmetry is now a safety property rather than a hazard. The rule is
|
|
625
|
+
**fixable**, and `format` passes `--fix`; when the graph was warm — which it is
|
|
626
|
+
after any `nx` command in the same workspace — a `format` run could and did
|
|
627
|
+
rewrite `package.json`. `@mnci/eslint-config` turns off the two checks whose
|
|
628
|
+
fixers do that (`checkObsoleteDependencies`, `checkVersionMismatches`), so
|
|
629
|
+
neither path is destructive, and the skip means `format` cannot reach a manifest
|
|
630
|
+
at all. Warm the graph deliberately (`npx nx show projects`) if you want the
|
|
631
|
+
rule evaluated in `format` too; mnci does not, because it would make every
|
|
632
|
+
format run pay for a graph computation to enforce what `lint` already gates.
|
|
633
|
+
|
|
616
634
|
**Upgrading an older workspace.** `mnci upgrade` deletes every config a previous
|
|
617
635
|
version could have written for a second tool — `.prettierrc`, `.prettierrc.json`,
|
|
618
636
|
`.prettierrc.mjs`, `.prettierignore`, `.oxfmtrc.json`, `oxlint.config.ts` — and
|
|
@@ -623,6 +641,47 @@ formatter from the **project's** dependencies, so a stale declaration is enough
|
|
|
623
641
|
to reformat on save against an opinion nothing checks. `mnci doctor` reports a
|
|
624
642
|
workspace that has not been upgraded yet.
|
|
625
643
|
|
|
644
|
+
## `--into`: bootstrapping into a repository that already exists
|
|
645
|
+
|
|
646
|
+
`create-nx-workspace <name>` creates the directory itself and exits with
|
|
647
|
+
`DIRECTORY_EXISTS` when one is already there. That rules out the most common
|
|
648
|
+
way a repository actually starts: the host creates it, you clone it, and the
|
|
649
|
+
clone holds a `.git` directory, a README and a licence. Doing it by hand means
|
|
650
|
+
generating into a temp parent, copying everything except `.git` and
|
|
651
|
+
`node_modules` across, and reinstalling — four steps, each of which can quietly
|
|
652
|
+
lose a file.
|
|
653
|
+
|
|
654
|
+
`mnci new --into <dir>` is that, done once and tested:
|
|
655
|
+
|
|
656
|
+
```sh
|
|
657
|
+
git clone git@github.com:me/my-repo.git
|
|
658
|
+
cd my-repo
|
|
659
|
+
mnci new --into .
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
The workspace name defaults to the directory's name, because the directory is
|
|
663
|
+
already named and retyping it is a way to get the two out of step; pass a name
|
|
664
|
+
argument to override it.
|
|
665
|
+
|
|
666
|
+
What it does with the files that are already there is the whole of the risk, so
|
|
667
|
+
every case is decided in advance:
|
|
668
|
+
|
|
669
|
+
| Already in the directory | What happens |
|
|
670
|
+
| --- | --- |
|
|
671
|
+
| `.git` | Never touched. Keeping it is the point. |
|
|
672
|
+
| `README.md`, `LICENSE*` | **Kept.** The generator's README is boilerplate; yours is usually the only hand-written file in the repository. |
|
|
673
|
+
| `.gitignore` | **Merged.** Your lines stay, and the generated ones (`.nx/cache`, `dist`, `out-tsc`, …) are appended under a labelled heading. Lines already present are not repeated, so it is idempotent. |
|
|
674
|
+
| Anything else the new workspace also writes | **Refused**, naming every collision, before a single file is written. |
|
|
675
|
+
| Anything the new workspace does not write | Left alone. |
|
|
676
|
+
|
|
677
|
+
Two checks, not one. A directory holding `package.json`, `nx.json`,
|
|
678
|
+
`tsconfig.base.json`, `node_modules`, `apps/`, `libs/` or `packages/` is
|
|
679
|
+
rejected **before** anything is generated — it is a project already, and the
|
|
680
|
+
answer there is `mnci upgrade`, not `mnci new`. The full collision check needs
|
|
681
|
+
the generated tree, so it runs afterwards, but still before the first write:
|
|
682
|
+
a refusal leaves the target byte-identical to how it was found, and the staging
|
|
683
|
+
copy is discarded.
|
|
684
|
+
|
|
626
685
|
## Layout convention = release scoping
|
|
627
686
|
|
|
628
687
|
| Directory | Contents | Released? |
|
package/dist/cli.js
CHANGED
|
@@ -147,7 +147,7 @@ function runCapture(command, arguments_, cwd) {
|
|
|
147
147
|
return { status: result.status ?? 1, stdout: result.stdout ?? "" };
|
|
148
148
|
}
|
|
149
149
|
async function runCaptureAsync(command, arguments_, cwd) {
|
|
150
|
-
return await new Promise((
|
|
150
|
+
return await new Promise((resolve2) => {
|
|
151
151
|
const child = (0, import_cross_spawn.default)(command, arguments_, {
|
|
152
152
|
cwd,
|
|
153
153
|
timeout: CAPTURE_TIMEOUT_MS,
|
|
@@ -159,10 +159,10 @@ async function runCaptureAsync(command, arguments_, cwd) {
|
|
|
159
159
|
stdout += chunk;
|
|
160
160
|
});
|
|
161
161
|
child.on("error", () => {
|
|
162
|
-
|
|
162
|
+
resolve2({ status: 1, stdout: "" });
|
|
163
163
|
});
|
|
164
164
|
child.on("close", (code) => {
|
|
165
|
-
|
|
165
|
+
resolve2({ status: code ?? 1, stdout });
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
168
|
}
|
|
@@ -1558,7 +1558,58 @@ updates:
|
|
|
1558
1558
|
}
|
|
1559
1559
|
return config;
|
|
1560
1560
|
}
|
|
1561
|
-
var NX_SCAFFOLDING_TO_REMOVE = [
|
|
1561
|
+
var NX_SCAFFOLDING_TO_REMOVE = [
|
|
1562
|
+
".prettierrc",
|
|
1563
|
+
".prettierrc.json",
|
|
1564
|
+
".vscode",
|
|
1565
|
+
// See LOCAL_REGISTRY_SCAFFOLDING: the config half of a publishing mechanism
|
|
1566
|
+
// this workspace does not use.
|
|
1567
|
+
".verdaccio",
|
|
1568
|
+
// The AI-agent set, in full. See the remarks above: a partial delete leaves
|
|
1569
|
+
// every `nx` command printing an "outdated configuration" nag.
|
|
1570
|
+
".agents",
|
|
1571
|
+
".claude",
|
|
1572
|
+
".codex",
|
|
1573
|
+
".cursor",
|
|
1574
|
+
".gemini",
|
|
1575
|
+
".opencode",
|
|
1576
|
+
".github/agents",
|
|
1577
|
+
".github/prompts",
|
|
1578
|
+
".github/skills",
|
|
1579
|
+
"AGENTS.md",
|
|
1580
|
+
"CLAUDE.md",
|
|
1581
|
+
"opencode.json"
|
|
1582
|
+
];
|
|
1583
|
+
function withoutKey(record, key) {
|
|
1584
|
+
return Object.fromEntries(Object.entries(record).filter(([name]) => name !== key));
|
|
1585
|
+
}
|
|
1586
|
+
var LOCAL_REGISTRY_SCAFFOLDING = {
|
|
1587
|
+
/** The config directory, removed with the rest of {@link NX_SCAFFOLDING_TO_REMOVE}. */
|
|
1588
|
+
directory: ".verdaccio",
|
|
1589
|
+
/** The root devDependency the target runs. */
|
|
1590
|
+
devDependency: "verdaccio",
|
|
1591
|
+
/** The root Nx target wired to both of the above. */
|
|
1592
|
+
rootTarget: "local-registry"
|
|
1593
|
+
};
|
|
1594
|
+
function removeLocalRegistryScaffolding(workspaceRoot) {
|
|
1595
|
+
(0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, LOCAL_REGISTRY_SCAFFOLDING.directory), {
|
|
1596
|
+
recursive: true,
|
|
1597
|
+
force: true
|
|
1598
|
+
});
|
|
1599
|
+
const manifestPath = (0, import_node_path2.join)(workspaceRoot, "package.json");
|
|
1600
|
+
if (!fileExists(manifestPath)) return;
|
|
1601
|
+
const manifest = readJson(manifestPath);
|
|
1602
|
+
if (manifest.devDependencies?.[LOCAL_REGISTRY_SCAFFOLDING.devDependency] !== void 0) {
|
|
1603
|
+
delete manifest.devDependencies[LOCAL_REGISTRY_SCAFFOLDING.devDependency];
|
|
1604
|
+
if (Object.keys(manifest.devDependencies).length === 0) delete manifest.devDependencies;
|
|
1605
|
+
}
|
|
1606
|
+
if (manifest.nx?.targets?.[LOCAL_REGISTRY_SCAFFOLDING.rootTarget] !== void 0) {
|
|
1607
|
+
delete manifest.nx.targets[LOCAL_REGISTRY_SCAFFOLDING.rootTarget];
|
|
1608
|
+
if (Object.keys(manifest.nx.targets).length === 0) delete manifest.nx.targets;
|
|
1609
|
+
if (Object.keys(manifest.nx).length === 0) delete manifest.nx;
|
|
1610
|
+
}
|
|
1611
|
+
writeFileEnsured(manifestPath, toJson(manifest));
|
|
1612
|
+
}
|
|
1562
1613
|
function removeNxScaffolding(workspaceRoot) {
|
|
1563
1614
|
for (const entry of NX_SCAFFOLDING_TO_REMOVE) {
|
|
1564
1615
|
(0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, entry), { recursive: true, force: true });
|
|
@@ -1621,12 +1672,15 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
|
|
|
1621
1672
|
...rootScripts()
|
|
1622
1673
|
};
|
|
1623
1674
|
const existingDevDeps = manifest.devDependencies;
|
|
1624
|
-
const devDeps =
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1675
|
+
const devDeps = withoutKey(
|
|
1676
|
+
withoutRetiredFormatterDependencies({
|
|
1677
|
+
...existingDevDeps,
|
|
1678
|
+
...TS_COMPILER_DEPENDENCIES,
|
|
1679
|
+
// The preset pins `nx` itself; the ESLint plugins must match it exactly.
|
|
1680
|
+
...eslintToolchainDependencies(existingDevDeps?.nx ?? "latest")
|
|
1681
|
+
}),
|
|
1682
|
+
LOCAL_REGISTRY_SCAFFOLDING.devDependency
|
|
1683
|
+
);
|
|
1630
1684
|
const overrides = {
|
|
1631
1685
|
...manifest.overrides,
|
|
1632
1686
|
...ESLINT_PEER_OVERRIDES,
|
|
@@ -1638,11 +1692,15 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
|
|
|
1638
1692
|
...reactExpressPeerOverride(manifest)
|
|
1639
1693
|
};
|
|
1640
1694
|
const existingNx = manifest.nx;
|
|
1695
|
+
const existingTargets = withoutKey(
|
|
1696
|
+
existingNx?.targets ?? {},
|
|
1697
|
+
LOCAL_REGISTRY_SCAFFOLDING.rootTarget
|
|
1698
|
+
);
|
|
1641
1699
|
const nx = {
|
|
1642
1700
|
...existingNx,
|
|
1643
1701
|
includedScripts: existingNx?.includedScripts ?? [],
|
|
1644
1702
|
targets: {
|
|
1645
|
-
...
|
|
1703
|
+
...existingTargets,
|
|
1646
1704
|
lint: ROOT_LINT_TARGET
|
|
1647
1705
|
}
|
|
1648
1706
|
};
|
|
@@ -2937,6 +2995,7 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
|
|
|
2937
2995
|
repairDeclarationSpecifiers(projectRoot);
|
|
2938
2996
|
writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
|
|
2939
2997
|
removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
|
|
2998
|
+
removeLocalRegistryScaffolding(workspaceRoot);
|
|
2940
2999
|
registerProjectCommands(workspaceRoot, name, { build: true });
|
|
2941
3000
|
}
|
|
2942
3001
|
);
|
|
@@ -3283,6 +3342,7 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
|
|
|
3283
3342
|
repairDeclarationSpecifiers(projectRoot);
|
|
3284
3343
|
writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
|
|
3285
3344
|
removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
|
|
3345
|
+
removeLocalRegistryScaffolding(workspaceRoot);
|
|
3286
3346
|
registerProjectCommands(workspaceRoot, name, { build: true });
|
|
3287
3347
|
}
|
|
3288
3348
|
);
|
|
@@ -4838,9 +4898,86 @@ function runDoctor(workspaceRoot) {
|
|
|
4838
4898
|
process.exitCode = 1;
|
|
4839
4899
|
}
|
|
4840
4900
|
|
|
4841
|
-
// src/workspace-creation/
|
|
4901
|
+
// src/workspace-creation/adopt-directory.use-case.ts
|
|
4842
4902
|
var import_node_fs13 = require("fs");
|
|
4843
4903
|
var import_node_path20 = require("path");
|
|
4904
|
+
var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
4905
|
+
var EXISTING_WINS = /* @__PURE__ */ new Set(["README.md", "LICENSE", "LICENSE.md", "LICENSE.txt"]);
|
|
4906
|
+
var PREFLIGHT_BLOCKERS = [
|
|
4907
|
+
"package.json",
|
|
4908
|
+
"nx.json",
|
|
4909
|
+
"tsconfig.base.json",
|
|
4910
|
+
"node_modules",
|
|
4911
|
+
"apps",
|
|
4912
|
+
"libs",
|
|
4913
|
+
"packages"
|
|
4914
|
+
];
|
|
4915
|
+
function assertAdoptableDirectory(target) {
|
|
4916
|
+
if (!(0, import_node_fs13.existsSync)(target)) {
|
|
4917
|
+
throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
|
|
4918
|
+
}
|
|
4919
|
+
if (!(0, import_node_fs13.statSync)(target).isDirectory()) {
|
|
4920
|
+
throw new Error(`--into '${target}' is not a directory.`);
|
|
4921
|
+
}
|
|
4922
|
+
const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)));
|
|
4923
|
+
if (blockers.length > 0) {
|
|
4924
|
+
throw new Error(
|
|
4925
|
+
`--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.`
|
|
4926
|
+
);
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
function mergeGitignore(generatedFile, targetFile) {
|
|
4930
|
+
const existing = (0, import_node_fs13.readFileSync)(targetFile, "utf8");
|
|
4931
|
+
const present = new Set(existing.split("\n").map((line) => line.trim()));
|
|
4932
|
+
const additions = (0, import_node_fs13.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
|
|
4933
|
+
const trimmed = line.trim();
|
|
4934
|
+
return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
|
|
4935
|
+
});
|
|
4936
|
+
if (additions.length === 0) return false;
|
|
4937
|
+
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
4938
|
+
(0, import_node_fs13.writeFileSync)(
|
|
4939
|
+
targetFile,
|
|
4940
|
+
`${existing}${separator}
|
|
4941
|
+
# Added by mnci (Nx workspace)
|
|
4942
|
+
${additions.join("\n")}
|
|
4943
|
+
`
|
|
4944
|
+
);
|
|
4945
|
+
return true;
|
|
4946
|
+
}
|
|
4947
|
+
function adoptGeneratedWorkspace(generatedRoot, target) {
|
|
4948
|
+
const entries = (0, import_node_fs13.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
|
|
4949
|
+
const collisions = entries.filter(
|
|
4950
|
+
(entry) => (0, import_node_fs13.existsSync)((0, import_node_path20.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
|
|
4951
|
+
);
|
|
4952
|
+
if (collisions.length > 0) {
|
|
4953
|
+
throw new Error(
|
|
4954
|
+
`--into '${target}' already contains ${collisions.join(", ")}, which the new workspace also writes. Move those aside and run it again; nothing has been changed.`
|
|
4955
|
+
);
|
|
4956
|
+
}
|
|
4957
|
+
const result = { copied: [], kept: [], mergedGitignore: false };
|
|
4958
|
+
for (const entry of entries) {
|
|
4959
|
+
const from = (0, import_node_path20.join)(generatedRoot, entry);
|
|
4960
|
+
const to = (0, import_node_path20.join)(target, entry);
|
|
4961
|
+
if (entry === ".gitignore" && (0, import_node_fs13.existsSync)(to)) {
|
|
4962
|
+
result.mergedGitignore = mergeGitignore(from, to);
|
|
4963
|
+
result.kept.push(entry);
|
|
4964
|
+
continue;
|
|
4965
|
+
}
|
|
4966
|
+
if ((0, import_node_fs13.existsSync)(to)) {
|
|
4967
|
+
result.kept.push(entry);
|
|
4968
|
+
continue;
|
|
4969
|
+
}
|
|
4970
|
+
(0, import_node_fs13.cpSync)(from, to, { recursive: true });
|
|
4971
|
+
result.copied.push(entry);
|
|
4972
|
+
}
|
|
4973
|
+
(0, import_node_fs13.rmSync)(generatedRoot, { recursive: true, force: true });
|
|
4974
|
+
return result;
|
|
4975
|
+
}
|
|
4976
|
+
|
|
4977
|
+
// src/workspace-creation/create-workspace.use-case.ts
|
|
4978
|
+
var import_node_fs14 = require("fs");
|
|
4979
|
+
var import_node_os = require("os");
|
|
4980
|
+
var import_node_path21 = require("path");
|
|
4844
4981
|
function nxCloudProviderValue(ci) {
|
|
4845
4982
|
return ci === "azure" ? "azure" : "github";
|
|
4846
4983
|
}
|
|
@@ -4876,7 +5013,9 @@ async function resolveRegistry(options) {
|
|
|
4876
5013
|
return await promptRegistry();
|
|
4877
5014
|
}
|
|
4878
5015
|
async function runNew(name, options) {
|
|
4879
|
-
const
|
|
5016
|
+
const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path21.resolve)(process.cwd(), options.into);
|
|
5017
|
+
if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
|
|
5018
|
+
const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path21.basename)(adoptTarget));
|
|
4880
5019
|
assertValidProjectName(workspaceName, "Workspace name");
|
|
4881
5020
|
const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
|
|
4882
5021
|
const registry = await resolveRegistry(options);
|
|
@@ -4888,6 +5027,7 @@ async function runNew(name, options) {
|
|
|
4888
5027
|
const variableGroup = ci === "github" ? options.variableGroup ?? "Build" : options.variableGroup ?? (options.yes ? "Build" : await promptText("Azure DevOps variable group holding the npm PAT", "Build"));
|
|
4889
5028
|
const stack = await resolveStack(options);
|
|
4890
5029
|
const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
|
|
5030
|
+
const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs14.mkdtempSync)((0, import_node_path21.join)((0, import_node_os.tmpdir)(), "mnci-new-"));
|
|
4891
5031
|
logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
|
|
4892
5032
|
runNpx(
|
|
4893
5033
|
[
|
|
@@ -4899,9 +5039,17 @@ async function runNew(name, options) {
|
|
|
4899
5039
|
nxCloud ? `--nxCloud=${nxCloudProviderValue(ci)}` : "--nxCloud=skip",
|
|
4900
5040
|
"--no-interactive"
|
|
4901
5041
|
],
|
|
4902
|
-
|
|
5042
|
+
stagingParent
|
|
4903
5043
|
);
|
|
4904
|
-
|
|
5044
|
+
let workspaceRoot = (0, import_node_path21.join)(stagingParent, workspaceName);
|
|
5045
|
+
if (adoptTarget !== void 0) {
|
|
5046
|
+
logger.step(`Adopting ${adoptTarget} (keeping its .git)`);
|
|
5047
|
+
const adoption = adoptGeneratedWorkspace(workspaceRoot, adoptTarget);
|
|
5048
|
+
for (const kept of adoption.kept) logger.detail(`kept the existing ${kept}`);
|
|
5049
|
+
if (adoption.mergedGitignore) logger.detail("merged the generated .gitignore into the existing one");
|
|
5050
|
+
(0, import_node_fs14.rmSync)(stagingParent, { recursive: true, force: true });
|
|
5051
|
+
workspaceRoot = adoptTarget;
|
|
5052
|
+
}
|
|
4905
5053
|
logger.step(
|
|
4906
5054
|
"Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
|
|
4907
5055
|
);
|
|
@@ -4910,8 +5058,8 @@ async function runNew(name, options) {
|
|
|
4910
5058
|
{ workspaceName, scope, registry, agent, variableGroup, ci, stack },
|
|
4911
5059
|
logger.detail
|
|
4912
5060
|
);
|
|
4913
|
-
(0,
|
|
4914
|
-
(0,
|
|
5061
|
+
(0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
|
|
5062
|
+
(0, import_node_fs14.rmSync)((0, import_node_path21.join)(workspaceRoot, "package-lock.json"), { force: true });
|
|
4915
5063
|
logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
|
|
4916
5064
|
const installStatus = runShell(
|
|
4917
5065
|
"npm",
|
|
@@ -4925,7 +5073,7 @@ async function runNew(name, options) {
|
|
|
4925
5073
|
logger.step("Formatting the workspace (eslint --fix, JavaScript Standard Style)");
|
|
4926
5074
|
runFormatter(workspaceRoot);
|
|
4927
5075
|
logger.success("Done. Next steps:");
|
|
4928
|
-
logger.info(` cd ${workspaceName}`);
|
|
5076
|
+
if (adoptTarget === void 0) logger.info(` cd ${workspaceName}`);
|
|
4929
5077
|
logger.info(" mnci add react-app web # or: react-lib, react-internal-lib, node-app,");
|
|
4930
5078
|
logger.info(" # node-function-app, npm-lib, internal-lib,");
|
|
4931
5079
|
logger.info(
|
|
@@ -4941,12 +5089,12 @@ async function runNew(name, options) {
|
|
|
4941
5089
|
}
|
|
4942
5090
|
|
|
4943
5091
|
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
4944
|
-
var
|
|
5092
|
+
var import_node_path23 = require("path");
|
|
4945
5093
|
var import_prompts4 = require("@inquirer/prompts");
|
|
4946
5094
|
|
|
4947
5095
|
// src/workspace-upgrade/upgrade-workspace.use-case.ts
|
|
4948
|
-
var
|
|
4949
|
-
var
|
|
5096
|
+
var import_node_fs15 = require("fs");
|
|
5097
|
+
var import_node_path22 = require("path");
|
|
4950
5098
|
function resolveRegistry2(options, persisted) {
|
|
4951
5099
|
if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
|
|
4952
5100
|
const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
|
|
@@ -4975,7 +5123,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
|
4975
5123
|
return persisted.workspaceName;
|
|
4976
5124
|
}
|
|
4977
5125
|
try {
|
|
4978
|
-
const existing = (0,
|
|
5126
|
+
const existing = (0, import_node_fs15.readdirSync)(workspaceRoot).find(
|
|
4979
5127
|
(file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
|
|
4980
5128
|
);
|
|
4981
5129
|
if (existing) {
|
|
@@ -4983,7 +5131,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
|
4983
5131
|
}
|
|
4984
5132
|
} catch {
|
|
4985
5133
|
}
|
|
4986
|
-
return (0,
|
|
5134
|
+
return (0, import_node_path22.basename)(workspaceRoot);
|
|
4987
5135
|
}
|
|
4988
5136
|
function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
4989
5137
|
const scope = options.scope ?? persisted.scope;
|
|
@@ -5021,7 +5169,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
|
5021
5169
|
};
|
|
5022
5170
|
}
|
|
5023
5171
|
function runUpgrade(workspaceRoot, options) {
|
|
5024
|
-
if (!fileExists((0,
|
|
5172
|
+
if (!fileExists((0, import_node_path22.join)(workspaceRoot, "nx.json"))) {
|
|
5025
5173
|
throw new Error(
|
|
5026
5174
|
`No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
|
|
5027
5175
|
);
|
|
@@ -5060,7 +5208,7 @@ function runUpgrade(workspaceRoot, options) {
|
|
|
5060
5208
|
|
|
5061
5209
|
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
5062
5210
|
async function runInteractive() {
|
|
5063
|
-
const inWorkspace = fileExists((0,
|
|
5211
|
+
const inWorkspace = fileExists((0, import_node_path23.join)(process.cwd(), "nx.json"));
|
|
5064
5212
|
const choiceNew = { name: "Create a new monorepo", value: "new" };
|
|
5065
5213
|
const choiceAdd = { name: "Add a project to this workspace", value: "add" };
|
|
5066
5214
|
const choiceUpgrade = {
|
|
@@ -5081,8 +5229,8 @@ async function runInteractive() {
|
|
|
5081
5229
|
}
|
|
5082
5230
|
|
|
5083
5231
|
// src/cli-version/check-for-update.use-case.ts
|
|
5084
|
-
var
|
|
5085
|
-
var
|
|
5232
|
+
var import_node_fs16 = require("fs");
|
|
5233
|
+
var import_node_path24 = require("path");
|
|
5086
5234
|
var import_cross_spawn2 = __toESM(require("cross-spawn"));
|
|
5087
5235
|
var PACKAGE_NAME = "@mnci/cli";
|
|
5088
5236
|
var REGISTRY_TIMEOUT_MS = 2e3;
|
|
@@ -5138,8 +5286,8 @@ function releaseTriple(version) {
|
|
|
5138
5286
|
}
|
|
5139
5287
|
function readCliVersion(packageDirectory) {
|
|
5140
5288
|
try {
|
|
5141
|
-
const manifestPath = (0,
|
|
5142
|
-
const manifest = JSON.parse((0,
|
|
5289
|
+
const manifestPath = (0, import_node_path24.join)(packageDirectory, "..", "package.json");
|
|
5290
|
+
const manifest = JSON.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf8"));
|
|
5143
5291
|
return manifest.version ?? "0.0.0";
|
|
5144
5292
|
} catch {
|
|
5145
5293
|
return "0.0.0";
|
|
@@ -5153,7 +5301,10 @@ function buildProgram(cliVersion) {
|
|
|
5153
5301
|
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(
|
|
5154
5302
|
"--agent <pool>",
|
|
5155
5303
|
"CI build agent: a vmImage (e.g. ubuntu-latest) or self-hosted pool name"
|
|
5156
|
-
).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").
|
|
5304
|
+
).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").option(
|
|
5305
|
+
"--into <dir>",
|
|
5306
|
+
"bootstrap into an existing directory (a fresh clone holding only .git); the directory name is the workspace name unless one is given"
|
|
5307
|
+
).action(async (name, options) => {
|
|
5157
5308
|
await runNew(name, options);
|
|
5158
5309
|
});
|
|
5159
5310
|
program.command("upgrade").description(
|