@mnci/cli 4.40.9 → 4.42.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/dist/cli.js +144 -84
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7896,15 +7896,60 @@ function runKinds(options) {
|
|
|
7896
7896
|
|
|
7897
7897
|
// src/workspace-diagnostics/check-invariants.use-case.ts
|
|
7898
7898
|
var import_node_child_process = require("child_process");
|
|
7899
|
+
var import_node_fs30 = require("fs");
|
|
7900
|
+
var import_node_path35 = require("path");
|
|
7901
|
+
|
|
7902
|
+
// src/workspace-diagnostics/locate-stranded-release-tags.use-case.ts
|
|
7899
7903
|
var import_node_fs29 = require("fs");
|
|
7900
7904
|
var import_node_path34 = require("path");
|
|
7905
|
+
|
|
7906
|
+
// src/workspace-diagnostics/stranded-release-tags.algorithm.ts
|
|
7907
|
+
function compareVersions2(left, right) {
|
|
7908
|
+
const a = left.split(".").map(Number);
|
|
7909
|
+
const b = right.split(".").map(Number);
|
|
7910
|
+
return a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || 0;
|
|
7911
|
+
}
|
|
7912
|
+
function versionsOf(tags, name) {
|
|
7913
|
+
return tags.filter((tag) => tag.startsWith(`${name}@`)).map((tag) => tag.slice(name.length + 1)).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
|
|
7914
|
+
}
|
|
7915
|
+
function findStrandedReleaseTags(projects, tags) {
|
|
7916
|
+
const stranded = [];
|
|
7917
|
+
for (const project of projects) {
|
|
7918
|
+
const unscoped = /^@[^/]+\/(.+)$/.exec(project)?.[1];
|
|
7919
|
+
if (unscoped === void 0) {
|
|
7920
|
+
continue;
|
|
7921
|
+
}
|
|
7922
|
+
const current = versionsOf(tags, project).sort(compareVersions2).at(-1);
|
|
7923
|
+
const newest = versionsOf(tags, unscoped).sort(compareVersions2).at(-1);
|
|
7924
|
+
if (newest !== void 0 && (current === void 0 || compareVersions2(newest, current) > 0)) {
|
|
7925
|
+
stranded.push({ project, oldTag: `${unscoped}@${newest}`, newTag: `${project}@${newest}` });
|
|
7926
|
+
}
|
|
7927
|
+
}
|
|
7928
|
+
return stranded;
|
|
7929
|
+
}
|
|
7930
|
+
|
|
7931
|
+
// src/workspace-diagnostics/locate-stranded-release-tags.use-case.ts
|
|
7932
|
+
var MNCI_TAG_PATTERN = "{projectName}@{version}";
|
|
7933
|
+
function locateStrandedReleaseTags(workspaceRoot, tagPattern) {
|
|
7934
|
+
if (tagPattern !== void 0 && tagPattern !== MNCI_TAG_PATTERN) {
|
|
7935
|
+
return [];
|
|
7936
|
+
}
|
|
7937
|
+
const listed = runCapture("git", ["tag", "--list"], workspaceRoot);
|
|
7938
|
+
if (listed.status !== 0) {
|
|
7939
|
+
return [];
|
|
7940
|
+
}
|
|
7941
|
+
const projects = (0, import_node_fs29.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot }).map((path) => readJson((0, import_node_path34.join)(workspaceRoot, path))).filter((manifest) => manifest.private !== true && manifest.name !== void 0).map((manifest) => manifest.name);
|
|
7942
|
+
return findStrandedReleaseTags(projects, listed.stdout.split(/\r?\n/).filter(Boolean));
|
|
7943
|
+
}
|
|
7944
|
+
|
|
7945
|
+
// src/workspace-diagnostics/check-invariants.use-case.ts
|
|
7901
7946
|
var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
|
|
7902
7947
|
function toPosix2(path) {
|
|
7903
7948
|
return path.replaceAll("\\", "/");
|
|
7904
7949
|
}
|
|
7905
7950
|
function checkEslintConfigs(workspaceRoot) {
|
|
7906
|
-
const rootConfigs = (0,
|
|
7907
|
-
const projectConfigs = (0,
|
|
7951
|
+
const rootConfigs = (0, import_node_fs30.globSync)("eslint.config.{js,mjs,cjs,ts,mts,cts}", { cwd: workspaceRoot });
|
|
7952
|
+
const projectConfigs = (0, import_node_fs30.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
|
|
7908
7953
|
cwd: workspaceRoot
|
|
7909
7954
|
}).map((config) => toPosix2(config));
|
|
7910
7955
|
return [
|
|
@@ -7924,10 +7969,10 @@ function checkEslintConfigs(workspaceRoot) {
|
|
|
7924
7969
|
];
|
|
7925
7970
|
}
|
|
7926
7971
|
function checkEslintEntryPointReachesTheRules(workspaceRoot) {
|
|
7927
|
-
const rules = (0,
|
|
7928
|
-
if (!(0,
|
|
7929
|
-
const entryPoint = (0,
|
|
7930
|
-
const source = (0,
|
|
7972
|
+
const rules = (0, import_node_path35.join)(workspaceRoot, ESLINT_MNCI_FILENAME);
|
|
7973
|
+
if (!(0, import_node_fs30.existsSync)(rules)) return [];
|
|
7974
|
+
const entryPoint = (0, import_node_path35.join)(workspaceRoot, ESLINT_USER_FILENAME);
|
|
7975
|
+
const source = (0, import_node_fs30.existsSync)(entryPoint) ? (0, import_node_fs30.readFileSync)(entryPoint, "utf8") : "";
|
|
7931
7976
|
return [
|
|
7932
7977
|
{
|
|
7933
7978
|
check: `${ESLINT_USER_FILENAME} imports the mnci rules`,
|
|
@@ -7940,7 +7985,7 @@ function checkEslintEntryPointReachesTheRules(workspaceRoot) {
|
|
|
7940
7985
|
function declaredDevDependencies(workspaceRoot) {
|
|
7941
7986
|
try {
|
|
7942
7987
|
const manifest = readJson(
|
|
7943
|
-
(0,
|
|
7988
|
+
(0, import_node_path35.join)(workspaceRoot, "package.json")
|
|
7944
7989
|
);
|
|
7945
7990
|
return manifest.devDependencies ?? {};
|
|
7946
7991
|
} catch {
|
|
@@ -7948,7 +7993,7 @@ function declaredDevDependencies(workspaceRoot) {
|
|
|
7948
7993
|
}
|
|
7949
7994
|
}
|
|
7950
7995
|
function checkNoRetiredFormatter(workspaceRoot) {
|
|
7951
|
-
const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0,
|
|
7996
|
+
const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path35.join)(workspaceRoot, file)));
|
|
7952
7997
|
const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
|
|
7953
7998
|
const stale = [...files, ...declared];
|
|
7954
7999
|
if (stale.length === 0) {
|
|
@@ -7974,7 +8019,7 @@ function checkEslintPlugin(nxJson) {
|
|
|
7974
8019
|
};
|
|
7975
8020
|
}
|
|
7976
8021
|
function checkResolvedEslint(workspaceRoot) {
|
|
7977
|
-
const manifestPath = (0,
|
|
8022
|
+
const manifestPath = (0, import_node_path35.join)(workspaceRoot, "node_modules/eslint/package.json");
|
|
7978
8023
|
if (!fileExists(manifestPath)) {
|
|
7979
8024
|
return void 0;
|
|
7980
8025
|
}
|
|
@@ -7992,11 +8037,11 @@ function checkResolvedEslint(workspaceRoot) {
|
|
|
7992
8037
|
}
|
|
7993
8038
|
}
|
|
7994
8039
|
function checkNpmrc(workspaceRoot, registry, scope) {
|
|
7995
|
-
const npmrcPath = (0,
|
|
8040
|
+
const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
|
|
7996
8041
|
if (!registry || !fileExists(npmrcPath)) {
|
|
7997
8042
|
return void 0;
|
|
7998
8043
|
}
|
|
7999
|
-
const npmrc = (0,
|
|
8044
|
+
const npmrc = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8");
|
|
8000
8045
|
if (registry.kind === "npm") {
|
|
8001
8046
|
return {
|
|
8002
8047
|
check: ".npmrc authenticates the public registry",
|
|
@@ -8013,11 +8058,11 @@ function checkNpmrc(workspaceRoot, registry, scope) {
|
|
|
8013
8058
|
};
|
|
8014
8059
|
}
|
|
8015
8060
|
function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
|
|
8016
|
-
const npmrcPath = (0,
|
|
8061
|
+
const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
|
|
8017
8062
|
if (!fileExists(npmrcPath)) {
|
|
8018
8063
|
return void 0;
|
|
8019
8064
|
}
|
|
8020
|
-
const npmrc = (0,
|
|
8065
|
+
const npmrc = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8");
|
|
8021
8066
|
const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
|
|
8022
8067
|
const referenced = [
|
|
8023
8068
|
...new Set(
|
|
@@ -8041,13 +8086,13 @@ function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env)
|
|
|
8041
8086
|
};
|
|
8042
8087
|
}
|
|
8043
8088
|
function checkNpmAuthMatchesPipeline(workspaceRoot, registry) {
|
|
8044
|
-
const npmrcPath = (0,
|
|
8045
|
-
const pipelinePath = (0,
|
|
8089
|
+
const npmrcPath = (0, import_node_path35.join)(workspaceRoot, ".npmrc");
|
|
8090
|
+
const pipelinePath = (0, import_node_path35.join)(workspaceRoot, "azure-pipelines.yml");
|
|
8046
8091
|
if (registry?.kind !== "azure-artifacts" || !fileExists(npmrcPath) || !fileExists(pipelinePath)) {
|
|
8047
8092
|
return void 0;
|
|
8048
8093
|
}
|
|
8049
|
-
const holdsCredentials = (0,
|
|
8050
|
-
const runsTask = (0,
|
|
8094
|
+
const holdsCredentials = (0, import_node_fs30.readFileSync)(npmrcPath, "utf8").split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).some((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
|
|
8095
|
+
const runsTask = (0, import_node_fs30.readFileSync)(pipelinePath, "utf8").includes("npmAuthenticate@0");
|
|
8051
8096
|
if (!holdsCredentials && !runsTask) {
|
|
8052
8097
|
return {
|
|
8053
8098
|
check: "npm auth: .npmrc and azure-pipelines.yml agree",
|
|
@@ -8092,13 +8137,13 @@ function npmjsCredentialShape(credentials, environment) {
|
|
|
8092
8137
|
}
|
|
8093
8138
|
function checkVersionActions(workspaceRoot) {
|
|
8094
8139
|
const candidates = [
|
|
8095
|
-
...(0,
|
|
8096
|
-
...(0,
|
|
8097
|
-
...(0,
|
|
8140
|
+
...(0, import_node_fs30.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
|
|
8141
|
+
...(0, import_node_fs30.globSync)("packages/*/*.csproj", { cwd: workspaceRoot }),
|
|
8142
|
+
...(0, import_node_fs30.globSync)("python-packages/*/pyproject.toml", { cwd: workspaceRoot })
|
|
8098
8143
|
].map((manifest) => toPosix2(manifest));
|
|
8099
8144
|
return candidates.flatMap((manifest) => {
|
|
8100
8145
|
const projectRoot = manifest.slice(0, manifest.lastIndexOf("/"));
|
|
8101
|
-
const projectJsonPath = (0,
|
|
8146
|
+
const projectJsonPath = (0, import_node_path35.join)(workspaceRoot, projectRoot, "project.json");
|
|
8102
8147
|
let hasOverride = false;
|
|
8103
8148
|
try {
|
|
8104
8149
|
const projectJson = readJson(projectJsonPath);
|
|
@@ -8127,7 +8172,7 @@ function declaredTargets(workspaceRoot, projectRoot) {
|
|
|
8127
8172
|
]) {
|
|
8128
8173
|
try {
|
|
8129
8174
|
const targets = extract(
|
|
8130
|
-
readJson((0,
|
|
8175
|
+
readJson((0, import_node_path35.join)(workspaceRoot, projectRoot, file))
|
|
8131
8176
|
);
|
|
8132
8177
|
if (targets && typeof targets === "object") {
|
|
8133
8178
|
sources.push({
|
|
@@ -8143,8 +8188,8 @@ function declaredTargets(workspaceRoot, projectRoot) {
|
|
|
8143
8188
|
function checkTargetFilesExist(workspaceRoot) {
|
|
8144
8189
|
const projectRoots = new Set(
|
|
8145
8190
|
[
|
|
8146
|
-
...(0,
|
|
8147
|
-
...(0,
|
|
8191
|
+
...(0, import_node_fs30.globSync)("{apps,libs,packages}/*/project.json", { cwd: workspaceRoot }),
|
|
8192
|
+
...(0, import_node_fs30.globSync)("{apps,libs,packages}/*/package.json", { cwd: workspaceRoot })
|
|
8148
8193
|
].map((manifest) => toPosix2(manifest).split("/").slice(0, 2).join("/"))
|
|
8149
8194
|
);
|
|
8150
8195
|
return [...projectRoots].flatMap(
|
|
@@ -8159,7 +8204,7 @@ function checkOneTargetsFiles(workspaceRoot, source, targetName, target) {
|
|
|
8159
8204
|
return TARGET_FILE_OPTIONS.flatMap((option) => {
|
|
8160
8205
|
const value = target?.options?.[option];
|
|
8161
8206
|
const checkable = typeof value === "string" && !value.includes("{");
|
|
8162
|
-
if (!checkable || fileExists((0,
|
|
8207
|
+
if (!checkable || fileExists((0, import_node_path35.join)(workspaceRoot, value))) {
|
|
8163
8208
|
return [];
|
|
8164
8209
|
}
|
|
8165
8210
|
return [
|
|
@@ -8198,15 +8243,15 @@ function checkGoPluginRegistered(workspaceRoot) {
|
|
|
8198
8243
|
};
|
|
8199
8244
|
}
|
|
8200
8245
|
function checkGoWorkInSync(workspaceRoot) {
|
|
8201
|
-
const goWorkPath = (0,
|
|
8246
|
+
const goWorkPath = (0, import_node_path35.join)(workspaceRoot, "go.work");
|
|
8202
8247
|
if (!fileExists(goWorkPath)) {
|
|
8203
8248
|
return void 0;
|
|
8204
8249
|
}
|
|
8205
|
-
const contents = (0,
|
|
8250
|
+
const contents = (0, import_node_fs30.existsSync)(goWorkPath) ? (0, import_node_fs30.readFileSync)(goWorkPath, "utf8") : "";
|
|
8206
8251
|
const blockEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+\(([^)]*)\)/g), (match) => match[1].split("\n")).flat();
|
|
8207
8252
|
const singleEntries = Array.from(contents.matchAll(/(?:^|\n)\s*use\s+(\.\S+)/g), (match) => match[1]);
|
|
8208
8253
|
const uses = [...blockEntries, ...singleEntries].map((entry) => entry.trim()).filter(Boolean);
|
|
8209
|
-
const stale = uses.filter((entry) => !(0,
|
|
8254
|
+
const stale = uses.filter((entry) => !(0, import_node_fs30.existsSync)((0, import_node_path35.join)(workspaceRoot, entry, "go.mod")));
|
|
8210
8255
|
return {
|
|
8211
8256
|
check: "every go.work `use` entry points to a module that still exists",
|
|
8212
8257
|
ok: stale.length === 0,
|
|
@@ -8222,9 +8267,9 @@ function checkNativeApps(workspaceRoot) {
|
|
|
8222
8267
|
{ file: ".github/workflows/ci.yml", marker: "native (${{ matrix.os }})" },
|
|
8223
8268
|
{ file: "azure-pipelines.yml", marker: "- job: native" }
|
|
8224
8269
|
];
|
|
8225
|
-
const findings = pipelines.filter(({ file }) => fileExists((0,
|
|
8270
|
+
const findings = pipelines.filter(({ file }) => fileExists((0, import_node_path35.join)(workspaceRoot, file))).map(({ file, marker }) => ({
|
|
8226
8271
|
check: `${file} builds the native apps on every OS`,
|
|
8227
|
-
ok: (0,
|
|
8272
|
+
ok: (0, import_node_fs30.readFileSync)((0, import_node_path35.join)(workspaceRoot, file), "utf8").includes(marker),
|
|
8228
8273
|
detail: `${file} has no native job: CI would verify a cgo app on the one agent that cannot build it`,
|
|
8229
8274
|
remedy: "run `mnci upgrade`"
|
|
8230
8275
|
}));
|
|
@@ -8237,7 +8282,7 @@ function checkNativeApps(workspaceRoot) {
|
|
|
8237
8282
|
return findings;
|
|
8238
8283
|
}
|
|
8239
8284
|
function checkNoRootRuntimeDependencies(workspaceRoot) {
|
|
8240
|
-
const manifestPath = (0,
|
|
8285
|
+
const manifestPath = (0, import_node_path35.join)(workspaceRoot, "package.json");
|
|
8241
8286
|
if (!fileExists(manifestPath)) {
|
|
8242
8287
|
return void 0;
|
|
8243
8288
|
}
|
|
@@ -8257,14 +8302,14 @@ function checkNoRootRuntimeDependencies(workspaceRoot) {
|
|
|
8257
8302
|
};
|
|
8258
8303
|
}
|
|
8259
8304
|
function checkRollupSourceMaps(workspaceRoot) {
|
|
8260
|
-
const configs = (0,
|
|
8305
|
+
const configs = (0, import_node_fs30.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
|
|
8261
8306
|
cwd: workspaceRoot
|
|
8262
8307
|
}).map((config) => toPosix2(config));
|
|
8263
8308
|
return configs.flatMap((relativePath) => {
|
|
8264
|
-
const configPath = (0,
|
|
8309
|
+
const configPath = (0, import_node_path35.join)(workspaceRoot, relativePath);
|
|
8265
8310
|
let config;
|
|
8266
8311
|
try {
|
|
8267
|
-
config = (0,
|
|
8312
|
+
config = (0, import_node_fs30.readFileSync)(configPath, "utf8");
|
|
8268
8313
|
} catch {
|
|
8269
8314
|
return [];
|
|
8270
8315
|
}
|
|
@@ -8279,11 +8324,11 @@ function checkRollupSourceMaps(workspaceRoot) {
|
|
|
8279
8324
|
});
|
|
8280
8325
|
}
|
|
8281
8326
|
function checkDeclarationSpecifiers(workspaceRoot) {
|
|
8282
|
-
const configs = (0,
|
|
8327
|
+
const configs = (0, import_node_fs30.globSync)(["packages/*/rollup.config.cjs", "libs/*/rollup.config.cjs"], {
|
|
8283
8328
|
cwd: workspaceRoot
|
|
8284
8329
|
}).map((config) => toPosix2(config));
|
|
8285
8330
|
return configs.flatMap((relativePath) => {
|
|
8286
|
-
const configPath = (0,
|
|
8331
|
+
const configPath = (0, import_node_path35.join)(workspaceRoot, relativePath);
|
|
8287
8332
|
if (!fileExists(configPath)) {
|
|
8288
8333
|
return [];
|
|
8289
8334
|
}
|
|
@@ -8298,7 +8343,7 @@ function checkDeclarationSpecifiers(workspaceRoot) {
|
|
|
8298
8343
|
// `plugins` array (what @nx/react:library writes). For any other shape it would no-op, and
|
|
8299
8344
|
// naming a command that silently does nothing is the failure mode the source-map check
|
|
8300
8345
|
// above goes out of its way to avoid, so the remedy depends on the shape.
|
|
8301
|
-
remedy: canAddDeclarationSpecifierPlugin((0,
|
|
8346
|
+
remedy: canAddDeclarationSpecifierPlugin((0, import_node_fs30.readFileSync)(configPath, "utf8")) ? "run `mnci upgrade`, which adds the plugin to the plugins array of withNx's second argument" : "add the plugin to withNx's second argument by hand (copy it from a freshly `mnci add npm-lib`'d project) \u2014 mnci does not recognise the shape of this config, so `mnci upgrade` cannot add it"
|
|
8302
8347
|
}
|
|
8303
8348
|
];
|
|
8304
8349
|
}
|
|
@@ -8314,8 +8359,8 @@ function checkDeclarationSpecifiers(workspaceRoot) {
|
|
|
8314
8359
|
}
|
|
8315
8360
|
function checkPipelinePhases(workspaceRoot) {
|
|
8316
8361
|
const files = ["azure-pipelines.yml", ".github/workflows/ci.yml"];
|
|
8317
|
-
return files.filter((file) => fileExists((0,
|
|
8318
|
-
const { verifyActive, switchedOff } = inspectPipeline((0,
|
|
8362
|
+
return files.filter((file) => fileExists((0, import_node_path35.join)(workspaceRoot, file))).flatMap((file) => {
|
|
8363
|
+
const { verifyActive, switchedOff } = inspectPipeline((0, import_node_fs30.readFileSync)((0, import_node_path35.join)(workspaceRoot, file), "utf8"));
|
|
8319
8364
|
const verify = {
|
|
8320
8365
|
check: `${file} runs the enforced verify phase`,
|
|
8321
8366
|
ok: verifyActive,
|
|
@@ -8356,7 +8401,7 @@ function checkDependencyRangesNotPreserved(nxJson) {
|
|
|
8356
8401
|
};
|
|
8357
8402
|
}
|
|
8358
8403
|
function checkLockfileHasNoLocalRegistry(workspaceRoot) {
|
|
8359
|
-
if (!fileExists((0,
|
|
8404
|
+
if (!fileExists((0, import_node_path35.join)(workspaceRoot, "package-lock.json"))) {
|
|
8360
8405
|
return void 0;
|
|
8361
8406
|
}
|
|
8362
8407
|
return {
|
|
@@ -8366,8 +8411,17 @@ function checkLockfileHasNoLocalRegistry(workspaceRoot) {
|
|
|
8366
8411
|
remedy: "run `mnci upgrade`, which removes it, then commit package-lock.json"
|
|
8367
8412
|
};
|
|
8368
8413
|
}
|
|
8414
|
+
function checkReleaseTagsResolve(workspaceRoot, nxJson) {
|
|
8415
|
+
const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
|
|
8416
|
+
return {
|
|
8417
|
+
check: "release tags resolve under each project's current name",
|
|
8418
|
+
ok: stranded.length === 0,
|
|
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: `on the commit of each old tag run: ${stranded.map((entry) => `git tag ${entry.newTag} ${entry.oldTag}^{commit}`).join(" ; ")} - then push the tags`
|
|
8421
|
+
};
|
|
8422
|
+
}
|
|
8369
8423
|
function collectFindings(workspaceRoot) {
|
|
8370
|
-
const nxJsonPath = (0,
|
|
8424
|
+
const nxJsonPath = (0, import_node_path35.join)(workspaceRoot, "nx.json");
|
|
8371
8425
|
if (!fileExists(nxJsonPath)) {
|
|
8372
8426
|
throw new Error(
|
|
8373
8427
|
`No nx.json found in ${workspaceRoot} \u2014 run 'mnci doctor' from the workspace root.`
|
|
@@ -8394,7 +8448,8 @@ function collectFindings(workspaceRoot) {
|
|
|
8394
8448
|
...checkPipelinePhases(workspaceRoot),
|
|
8395
8449
|
...checkNativeBuildConfig(workspaceRoot),
|
|
8396
8450
|
checkDependencyRangesNotPreserved(nxJson),
|
|
8397
|
-
checkLockfileHasNoLocalRegistry(workspaceRoot)
|
|
8451
|
+
checkLockfileHasNoLocalRegistry(workspaceRoot),
|
|
8452
|
+
checkReleaseTagsResolve(workspaceRoot, nxJson)
|
|
8398
8453
|
].filter((finding) => finding !== void 0);
|
|
8399
8454
|
}
|
|
8400
8455
|
function runDoctor(workspaceRoot, options = {}) {
|
|
@@ -8500,11 +8555,11 @@ function runCommands(program, options) {
|
|
|
8500
8555
|
}
|
|
8501
8556
|
|
|
8502
8557
|
// src/workspace-info/list-projects.use-case.ts
|
|
8503
|
-
var
|
|
8558
|
+
var import_node_path36 = require("path");
|
|
8504
8559
|
var TYPE_TAG_PREFIX = "type:";
|
|
8505
8560
|
function listProjects(workspaceRoot) {
|
|
8506
8561
|
return locateProjects(workspaceRoot).map((location) => {
|
|
8507
|
-
const projectJsonPath = (0,
|
|
8562
|
+
const projectJsonPath = (0, import_node_path36.join)(workspaceRoot, location.dir, "project.json");
|
|
8508
8563
|
const project = fileExists(projectJsonPath) ? readJson(projectJsonPath) : {};
|
|
8509
8564
|
const typeTag = (project.tags ?? []).find((tag) => tag.startsWith(TYPE_TAG_PREFIX));
|
|
8510
8565
|
return {
|
|
@@ -8517,7 +8572,7 @@ function listProjects(workspaceRoot) {
|
|
|
8517
8572
|
}).toSorted((a, b) => a.dir.localeCompare(b.dir));
|
|
8518
8573
|
}
|
|
8519
8574
|
function runProjects(workspaceRoot, options) {
|
|
8520
|
-
if (!fileExists((0,
|
|
8575
|
+
if (!fileExists((0, import_node_path36.join)(workspaceRoot, "nx.json"))) {
|
|
8521
8576
|
throw new Error("No nx.json found here. Run `projects` from the workspace root.");
|
|
8522
8577
|
}
|
|
8523
8578
|
const projects = listProjects(workspaceRoot);
|
|
@@ -8531,11 +8586,11 @@ function runProjects(workspaceRoot, options) {
|
|
|
8531
8586
|
}
|
|
8532
8587
|
|
|
8533
8588
|
// src/workspace-info/read-workspace-info.use-case.ts
|
|
8534
|
-
var
|
|
8589
|
+
var import_node_path38 = require("path");
|
|
8535
8590
|
|
|
8536
8591
|
// src/cli-version/check-for-update.use-case.ts
|
|
8537
|
-
var
|
|
8538
|
-
var
|
|
8592
|
+
var import_node_fs31 = require("fs");
|
|
8593
|
+
var import_node_path37 = require("path");
|
|
8539
8594
|
var import_cross_spawn3 = __toESM(require("cross-spawn"));
|
|
8540
8595
|
var PACKAGE_NAME2 = "@mnci/cli";
|
|
8541
8596
|
var REGISTRY_TIMEOUT_MS = 2e3;
|
|
@@ -8594,8 +8649,8 @@ function releaseTriple(version) {
|
|
|
8594
8649
|
}
|
|
8595
8650
|
function readCliVersion(packageDirectory) {
|
|
8596
8651
|
try {
|
|
8597
|
-
const manifestPath = (0,
|
|
8598
|
-
const manifest = JSON.parse((0,
|
|
8652
|
+
const manifestPath = (0, import_node_path37.join)(packageDirectory, "..", "package.json");
|
|
8653
|
+
const manifest = JSON.parse((0, import_node_fs31.readFileSync)(manifestPath, "utf8"));
|
|
8599
8654
|
return manifest.version ?? "0.0.0";
|
|
8600
8655
|
} catch {
|
|
8601
8656
|
return "0.0.0";
|
|
@@ -8605,7 +8660,7 @@ function readCliVersion(packageDirectory) {
|
|
|
8605
8660
|
// src/workspace-info/read-workspace-info.use-case.ts
|
|
8606
8661
|
function readWorkspaceInfo(workspaceRoot, cliVersion) {
|
|
8607
8662
|
const latest = fetchLatestVersion() ?? null;
|
|
8608
|
-
const isWorkspace = fileExists((0,
|
|
8663
|
+
const isWorkspace = fileExists((0, import_node_path38.join)(workspaceRoot, "nx.json"));
|
|
8609
8664
|
return {
|
|
8610
8665
|
cli: {
|
|
8611
8666
|
version: cliVersion,
|
|
@@ -8626,8 +8681,8 @@ function runInfo(workspaceRoot, cliVersion, options) {
|
|
|
8626
8681
|
}
|
|
8627
8682
|
|
|
8628
8683
|
// src/workspace-creation/adopt-directory.use-case.ts
|
|
8629
|
-
var
|
|
8630
|
-
var
|
|
8684
|
+
var import_node_fs32 = require("fs");
|
|
8685
|
+
var import_node_path39 = require("path");
|
|
8631
8686
|
var NEVER_COPIED = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
8632
8687
|
var AGENT_AND_CI_ENTRIES = [
|
|
8633
8688
|
"AGENTS.md",
|
|
@@ -8658,13 +8713,13 @@ var PREFLIGHT_BLOCKERS = [
|
|
|
8658
8713
|
"packages"
|
|
8659
8714
|
];
|
|
8660
8715
|
function assertAdoptableDirectory(target) {
|
|
8661
|
-
if (!(0,
|
|
8716
|
+
if (!(0, import_node_fs32.existsSync)(target)) {
|
|
8662
8717
|
throw new Error(`--into '${target}' does not exist. Create or clone it first.`);
|
|
8663
8718
|
}
|
|
8664
|
-
if (!(0,
|
|
8719
|
+
if (!(0, import_node_fs32.statSync)(target).isDirectory()) {
|
|
8665
8720
|
throw new Error(`--into '${target}' is not a directory.`);
|
|
8666
8721
|
}
|
|
8667
|
-
const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0,
|
|
8722
|
+
const blockers = PREFLIGHT_BLOCKERS.filter((entry) => (0, import_node_fs32.existsSync)((0, import_node_path39.join)(target, entry)));
|
|
8668
8723
|
if (blockers.length > 0) {
|
|
8669
8724
|
throw new Error(
|
|
8670
8725
|
`--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.`
|
|
@@ -8672,15 +8727,15 @@ function assertAdoptableDirectory(target) {
|
|
|
8672
8727
|
}
|
|
8673
8728
|
}
|
|
8674
8729
|
function mergeGitignore(generatedFile, targetFile) {
|
|
8675
|
-
const existing = (0,
|
|
8730
|
+
const existing = (0, import_node_fs32.readFileSync)(targetFile, "utf8");
|
|
8676
8731
|
const present = new Set(existing.split("\n").map((line) => line.trim()));
|
|
8677
|
-
const additions = (0,
|
|
8732
|
+
const additions = (0, import_node_fs32.readFileSync)(generatedFile, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => {
|
|
8678
8733
|
const trimmed = line.trim();
|
|
8679
8734
|
return trimmed !== "" && !trimmed.startsWith("#") && !present.has(trimmed);
|
|
8680
8735
|
});
|
|
8681
8736
|
if (additions.length === 0) return false;
|
|
8682
8737
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
8683
|
-
(0,
|
|
8738
|
+
(0, import_node_fs32.writeFileSync)(
|
|
8684
8739
|
targetFile,
|
|
8685
8740
|
`${existing}${separator}
|
|
8686
8741
|
# Added by mnci (Nx workspace)
|
|
@@ -8690,9 +8745,9 @@ ${additions.join("\n")}
|
|
|
8690
8745
|
return true;
|
|
8691
8746
|
}
|
|
8692
8747
|
function adoptGeneratedWorkspace(generatedRoot, target) {
|
|
8693
|
-
const entries = (0,
|
|
8748
|
+
const entries = (0, import_node_fs32.readdirSync)(generatedRoot).filter((entry) => !NEVER_COPIED.has(entry));
|
|
8694
8749
|
const collisions = entries.filter(
|
|
8695
|
-
(entry) => (0,
|
|
8750
|
+
(entry) => (0, import_node_fs32.existsSync)((0, import_node_path39.join)(target, entry)) && !EXISTING_WINS.has(entry) && entry !== ".gitignore"
|
|
8696
8751
|
);
|
|
8697
8752
|
if (collisions.length > 0) {
|
|
8698
8753
|
throw new Error(
|
|
@@ -8701,28 +8756,28 @@ function adoptGeneratedWorkspace(generatedRoot, target) {
|
|
|
8701
8756
|
}
|
|
8702
8757
|
const result = { copied: [], kept: [], mergedGitignore: false };
|
|
8703
8758
|
for (const entry of entries) {
|
|
8704
|
-
const from = (0,
|
|
8705
|
-
const to = (0,
|
|
8706
|
-
if (entry === ".gitignore" && (0,
|
|
8759
|
+
const from = (0, import_node_path39.join)(generatedRoot, entry);
|
|
8760
|
+
const to = (0, import_node_path39.join)(target, entry);
|
|
8761
|
+
if (entry === ".gitignore" && (0, import_node_fs32.existsSync)(to)) {
|
|
8707
8762
|
result.mergedGitignore = mergeGitignore(from, to);
|
|
8708
8763
|
result.kept.push(entry);
|
|
8709
8764
|
continue;
|
|
8710
8765
|
}
|
|
8711
|
-
if ((0,
|
|
8766
|
+
if ((0, import_node_fs32.existsSync)(to)) {
|
|
8712
8767
|
result.kept.push(entry);
|
|
8713
8768
|
continue;
|
|
8714
8769
|
}
|
|
8715
|
-
(0,
|
|
8770
|
+
(0, import_node_fs32.cpSync)(from, to, { recursive: true });
|
|
8716
8771
|
result.copied.push(entry);
|
|
8717
8772
|
}
|
|
8718
|
-
(0,
|
|
8773
|
+
(0, import_node_fs32.rmSync)(generatedRoot, { recursive: true, force: true });
|
|
8719
8774
|
return result;
|
|
8720
8775
|
}
|
|
8721
8776
|
|
|
8722
8777
|
// src/workspace-creation/create-workspace.use-case.ts
|
|
8723
|
-
var
|
|
8778
|
+
var import_node_fs33 = require("fs");
|
|
8724
8779
|
var import_node_os2 = require("os");
|
|
8725
|
-
var
|
|
8780
|
+
var import_node_path40 = require("path");
|
|
8726
8781
|
function nxCloudProviderValue(ci) {
|
|
8727
8782
|
return ci === "azure" ? "azure" : "github";
|
|
8728
8783
|
}
|
|
@@ -8765,9 +8820,9 @@ async function resolveRegistry(options) {
|
|
|
8765
8820
|
return await promptRegistry();
|
|
8766
8821
|
}
|
|
8767
8822
|
async function runNew(name, options) {
|
|
8768
|
-
const adoptTarget = options.into === void 0 ? void 0 : (0,
|
|
8823
|
+
const adoptTarget = options.into === void 0 ? void 0 : (0, import_node_path40.resolve)(process.cwd(), options.into);
|
|
8769
8824
|
if (adoptTarget !== void 0) assertAdoptableDirectory(adoptTarget);
|
|
8770
|
-
const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0,
|
|
8825
|
+
const workspaceName = name ?? (adoptTarget === void 0 ? await promptText("Workspace name") : (0, import_node_path40.basename)(adoptTarget));
|
|
8771
8826
|
assertValidProjectName(workspaceName, "Workspace name");
|
|
8772
8827
|
const scope = options.scope ?? (options.yes ? `@${workspaceName}` : await promptText("npm scope for publishable packages", `@${workspaceName}`));
|
|
8773
8828
|
const registry = await resolveRegistry(options);
|
|
@@ -8780,8 +8835,8 @@ async function runNew(name, options) {
|
|
|
8780
8835
|
const npmAuth = resolveNpmAuth(options.npmAuth, registry, ci);
|
|
8781
8836
|
const stack = await resolveStack(options);
|
|
8782
8837
|
const nxCloud = options.nxCloud ?? (options.yes ? false : await promptNxCloud());
|
|
8783
|
-
const stagingParent = adoptTarget === void 0 ? process.cwd() : (0,
|
|
8784
|
-
let workspaceRoot = (0,
|
|
8838
|
+
const stagingParent = adoptTarget === void 0 ? process.cwd() : (0, import_node_fs33.mkdtempSync)((0, import_node_path40.join)((0, import_node_os2.tmpdir)(), "mnci-new-"));
|
|
8839
|
+
let workspaceRoot = (0, import_node_path40.join)(stagingParent, workspaceName);
|
|
8785
8840
|
try {
|
|
8786
8841
|
logger.step(`Creating Nx workspace '${workspaceName}' (preset: ts)`);
|
|
8787
8842
|
runNpx(
|
|
@@ -8804,7 +8859,7 @@ async function runNew(name, options) {
|
|
|
8804
8859
|
workspaceRoot = adoptTarget;
|
|
8805
8860
|
}
|
|
8806
8861
|
} finally {
|
|
8807
|
-
if (adoptTarget !== void 0) (0,
|
|
8862
|
+
if (adoptTarget !== void 0) (0, import_node_fs33.rmSync)(stagingParent, { recursive: true, force: true });
|
|
8808
8863
|
}
|
|
8809
8864
|
logger.step(
|
|
8810
8865
|
"Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
|
|
@@ -8814,8 +8869,8 @@ async function runNew(name, options) {
|
|
|
8814
8869
|
{ workspaceName, scope, registry, agent, variableGroup, ci, stack, ...npmAuth && { npmAuth } },
|
|
8815
8870
|
logger.detail
|
|
8816
8871
|
);
|
|
8817
|
-
(0,
|
|
8818
|
-
(0,
|
|
8872
|
+
(0, import_node_fs33.rmSync)((0, import_node_path40.join)(workspaceRoot, "node_modules"), { recursive: true, force: true });
|
|
8873
|
+
(0, import_node_fs33.rmSync)((0, import_node_path40.join)(workspaceRoot, "package-lock.json"), { force: true });
|
|
8819
8874
|
logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
|
|
8820
8875
|
const installStatus = runShell(
|
|
8821
8876
|
"npm",
|
|
@@ -8853,12 +8908,12 @@ function projectKindHintLines(kinds = PROJECT_KINDS) {
|
|
|
8853
8908
|
}
|
|
8854
8909
|
|
|
8855
8910
|
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
8856
|
-
var
|
|
8911
|
+
var import_node_path42 = require("path");
|
|
8857
8912
|
var import_prompts4 = require("@inquirer/prompts");
|
|
8858
8913
|
|
|
8859
8914
|
// src/workspace-upgrade/upgrade-workspace.use-case.ts
|
|
8860
|
-
var
|
|
8861
|
-
var
|
|
8915
|
+
var import_node_fs34 = require("fs");
|
|
8916
|
+
var import_node_path41 = require("path");
|
|
8862
8917
|
function resolveRegistry2(options, persisted) {
|
|
8863
8918
|
if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
|
|
8864
8919
|
const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
|
|
@@ -8887,7 +8942,7 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
|
8887
8942
|
return persisted.workspaceName;
|
|
8888
8943
|
}
|
|
8889
8944
|
try {
|
|
8890
|
-
const existing = (0,
|
|
8945
|
+
const existing = (0, import_node_fs34.readdirSync)(workspaceRoot).find(
|
|
8891
8946
|
(file) => file.endsWith(".code-workspace") && file !== "undefined.code-workspace"
|
|
8892
8947
|
);
|
|
8893
8948
|
if (existing) {
|
|
@@ -8895,11 +8950,11 @@ function resolveWorkspaceName(workspaceRoot, persisted) {
|
|
|
8895
8950
|
}
|
|
8896
8951
|
} catch {
|
|
8897
8952
|
}
|
|
8898
|
-
return (0,
|
|
8953
|
+
return (0, import_node_path41.basename)(workspaceRoot);
|
|
8899
8954
|
}
|
|
8900
8955
|
function detectNpmAuth(workspaceRoot) {
|
|
8901
8956
|
try {
|
|
8902
|
-
return (0,
|
|
8957
|
+
return (0, import_node_fs34.readFileSync)((0, import_node_path41.join)(workspaceRoot, "azure-pipelines.yml"), "utf8").includes("npmAuthenticate@0") ? "build-identity" : void 0;
|
|
8903
8958
|
} catch {
|
|
8904
8959
|
return void 0;
|
|
8905
8960
|
}
|
|
@@ -8946,7 +9001,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
|
8946
9001
|
};
|
|
8947
9002
|
}
|
|
8948
9003
|
function runUpgrade(workspaceRoot, options) {
|
|
8949
|
-
if (!fileExists((0,
|
|
9004
|
+
if (!fileExists((0, import_node_path41.join)(workspaceRoot, "nx.json"))) {
|
|
8950
9005
|
throw new Error(
|
|
8951
9006
|
`No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
|
|
8952
9007
|
);
|
|
@@ -9020,13 +9075,18 @@ function runUpgrade(workspaceRoot, options) {
|
|
|
9020
9075
|
"Formatting the workspace (eslint --fix) \u2014 the slowest step, minutes on a large workspace"
|
|
9021
9076
|
);
|
|
9022
9077
|
runFormatter(workspaceRoot);
|
|
9078
|
+
const nxJson = readJson((0, import_node_path41.join)(workspaceRoot, "nx.json"));
|
|
9079
|
+
const stranded = locateStrandedReleaseTags(workspaceRoot, nxJson.release?.releaseTag?.pattern);
|
|
9080
|
+
for (const entry of stranded) {
|
|
9081
|
+
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).`);
|
|
9082
|
+
}
|
|
9023
9083
|
logger.success("Done. Review the changes with `git diff` before committing.");
|
|
9024
9084
|
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.");
|
|
9025
9085
|
}
|
|
9026
9086
|
|
|
9027
9087
|
// src/workspace-creation/interactive-wizard.use-case.ts
|
|
9028
9088
|
async function runInteractive() {
|
|
9029
|
-
const inWorkspace = fileExists((0,
|
|
9089
|
+
const inWorkspace = fileExists((0, import_node_path42.join)(process.cwd(), "nx.json"));
|
|
9030
9090
|
const choiceNew = { name: "Create a new monorepo", value: "new" };
|
|
9031
9091
|
const choiceAdd = { name: "Add a project to this workspace", value: "add" };
|
|
9032
9092
|
const choiceUpgrade = {
|