@mnci/cli 4.3.3 → 4.5.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 +8 -3
- package/dist/cli.js +69 -19
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ plays (`.use-case`, `.client`, `.repository`, `.algorithm`, `.validator`,
|
|
|
34
34
|
|
|
35
35
|
```
|
|
36
36
|
src/
|
|
37
|
-
|
|
37
|
+
main.ts the CLI transport — decodes argv, calls one use case
|
|
38
38
|
workspace-overlay/ the config files mnci owns and rewrites
|
|
39
39
|
workspace-creation/ mnci new, and the interactive wizard
|
|
40
40
|
workspace-upgrade/ mnci upgrade
|
|
@@ -49,9 +49,14 @@ src/
|
|
|
49
49
|
cli-version/ the update check
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
The dependency graph is acyclic and flows one way: `
|
|
52
|
+
The dependency graph is acyclic and flows one way: `main` → the command
|
|
53
53
|
slices → the infrastructure slices → `file-system` as a leaf. That is checked,
|
|
54
|
-
not assumed.
|
|
54
|
+
not assumed — and now enforced: the root `eslint.config.mjs` turns on
|
|
55
|
+
`@mnci/eslint-config`'s `verticalSlices` rules for `packages/cli/src`, so a
|
|
56
|
+
deep sibling import, a file without a role suffix, a nested subfeature or a
|
|
57
|
+
cycle between slices fails `npm run lint` rather than needing someone to
|
|
58
|
+
re-run the checks by hand. It is scoped to this package deliberately; the
|
|
59
|
+
config file says which packages were measured and why they are excluded.
|
|
55
60
|
|
|
56
61
|
### Exceptions, and when they go away
|
|
57
62
|
|
package/dist/cli.js
CHANGED
|
@@ -28,13 +28,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
));
|
|
29
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
30
|
|
|
31
|
-
// src/
|
|
32
|
-
var
|
|
33
|
-
__export(
|
|
31
|
+
// src/main.ts
|
|
32
|
+
var main_exports = {};
|
|
33
|
+
__export(main_exports, {
|
|
34
34
|
buildProgram: () => buildProgram,
|
|
35
35
|
main: () => main
|
|
36
36
|
});
|
|
37
|
-
module.exports = __toCommonJS(
|
|
37
|
+
module.exports = __toCommonJS(main_exports);
|
|
38
38
|
var import_commander = require("commander");
|
|
39
39
|
|
|
40
40
|
// src/project-scaffolding/add-project.use-case.ts
|
|
@@ -415,6 +415,14 @@ function withSharedGlobals(nxJson) {
|
|
|
415
415
|
namedInputs: { ...namedInputs, sharedGlobals: [...existing, ...missing] }
|
|
416
416
|
};
|
|
417
417
|
}
|
|
418
|
+
var PYTHON_GRAPH_PLUGIN = "@mnci/nx-python-pip/graph";
|
|
419
|
+
function withPythonGraphPlugin(nxJson, pluginInstalled) {
|
|
420
|
+
const plugins = nxJson.plugins ?? [];
|
|
421
|
+
if (!pluginInstalled || plugins.some((entry) => pluginName(entry) === PYTHON_GRAPH_PLUGIN)) {
|
|
422
|
+
return nxJson.plugins === void 0 ? nxJson : { ...nxJson, plugins };
|
|
423
|
+
}
|
|
424
|
+
return { ...nxJson, plugins: [...plugins, PYTHON_GRAPH_PLUGIN] };
|
|
425
|
+
}
|
|
418
426
|
function withReleaseConfig(nxJson, ci) {
|
|
419
427
|
return { ...nxJson, defaultBase: "main", release: releaseConfig(ci) };
|
|
420
428
|
}
|
|
@@ -869,8 +877,19 @@ var SHALLOW_CLONE_GUARD = `node -e "const r=require('node:child_process').spawnS
|
|
|
869
877
|
function releaseGuard(pythonPublishEnv, nugetPublishEnv) {
|
|
870
878
|
return String.raw`node -e "const fs=require('node:fs'),cp=require('node:child_process');const npmCount=fs.globSync('packages/*/package.json').length;const csharpCount=fs.globSync('packages/*/*.csproj').length;const pythonCount=fs.globSync('python-packages/*/pyproject.toml').length;const dartCount=fs.globSync('packages/*/pubspec.yaml').length;const hasNpm=npmCount>0;const hasPython=pythonCount>0;const hasCsharp=csharpCount>0;const hasDart=dartCount>0;if(!hasNpm&&!hasPython&&!hasCsharp&&!hasDart){console.log('Nothing to release - skipping.');process.exit(0)}const specifier=process.env.RELEASE_SPECIFIER||'';let releaseCmd='npx nx release --yes';if(specifier){if(!/^(major|minor|patch|\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?)$/.test(specifier)){console.error('RELEASE_SPECIFIER value \''+specifier+'\' is invalid - use major, minor, patch, or an exact version like 1.2.3.');process.exit(1)}const releaseProjectCount=npmCount+csharpCount+pythonCount+dartCount;if(/^(major|minor|patch)$/.test(specifier)&&releaseProjectCount>1){console.error('RELEASE_SPECIFIER is a keyword (\''+specifier+'\') but this workspace has '+releaseProjectCount+' releasable packages - a keyword under-bumps interdependent packages, because nx computes the dependency-bump pass from a stale cached version. Set RELEASE_SPECIFIER to an exact version instead, or clear it.');process.exit(1)}releaseCmd='npx nx release '+specifier+' --yes'}const env={...process.env};${pythonPublishEnv}${nugetPublishEnv}process.exit(cp.spawnSync(releaseCmd,{stdio:'inherit',shell:true,env}).status ?? 1)"`;
|
|
871
879
|
}
|
|
872
|
-
|
|
873
|
-
|
|
880
|
+
var PYPI_TOKEN_VARIABLE = "PYPI_TOKEN";
|
|
881
|
+
function pypiTokenEnvLine(registryKind, variableReference, indent) {
|
|
882
|
+
return registryKind === "npm" ? `
|
|
883
|
+
${indent}${PYPI_TOKEN_VARIABLE}: ${variableReference(PYPI_TOKEN_VARIABLE)}` : "";
|
|
884
|
+
}
|
|
885
|
+
function pythonPublishEnvFragment(pythonPublishUrl2, registryKind) {
|
|
886
|
+
if (pythonPublishUrl2 !== void 0) {
|
|
887
|
+
return `if(hasPython){env.TWINE_REPOSITORY_URL='${pythonPublishUrl2}';env.TWINE_USERNAME='AzureArtifacts';env.TWINE_PASSWORD=Buffer.from(process.env.PAT,'base64').toString()}`;
|
|
888
|
+
}
|
|
889
|
+
if (registryKind !== "npm") {
|
|
890
|
+
return "";
|
|
891
|
+
}
|
|
892
|
+
return `if(hasPython){if(!process.env.${PYPI_TOKEN_VARIABLE}){console.error('This workspace has '+pythonCount+' Python package(s) to publish but ${PYPI_TOKEN_VARIABLE} is empty. Add a PyPI API token as a secret named ${PYPI_TOKEN_VARIABLE}, or remove the Python packages from release.projects.');process.exit(1)}env.TWINE_USERNAME='__token__';env.TWINE_PASSWORD=process.env.${PYPI_TOKEN_VARIABLE};env.TWINE_NON_INTERACTIVE='1'}`;
|
|
874
893
|
}
|
|
875
894
|
function nugetPublishEnvFragment(nugetFeedUrl2) {
|
|
876
895
|
return nugetFeedUrl2 ? "if(hasCsharp){env.NUGET_PAT=Buffer.from(process.env.PAT,'base64').toString()}" : "";
|
|
@@ -1148,11 +1167,11 @@ steps:
|
|
|
1148
1167
|
# it whenever more than one package is releasable. The guard below fails
|
|
1149
1168
|
# the run rather than under-bumping silently: clear the variable back to
|
|
1150
1169
|
# '' once the override is no longer needed.
|
|
1151
|
-
- script: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2), nugetPublishEnvFragment(nugetFeedUrl2))}
|
|
1170
|
+
- script: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2, registryKind), nugetPublishEnvFragment(nugetFeedUrl2))}
|
|
1152
1171
|
displayName: Release \u2014 version, tag and publish (npm + Python + C#)
|
|
1153
1172
|
condition: ${onMain}
|
|
1154
1173
|
env:
|
|
1155
|
-
${npmAuthName}: ${npmAuthValue}
|
|
1174
|
+
${npmAuthName}: ${npmAuthValue}${pypiTokenEnvLine(registryKind, (name) => `$(${name})`, " ".repeat(6))}
|
|
1156
1175
|
RELEASE_SPECIFIER: $(RELEASE_SPECIFIER)
|
|
1157
1176
|
|
|
1158
1177
|
# nx release's own git push (release.git.push) is deliberately left off: it
|
|
@@ -1381,11 +1400,11 @@ jobs:
|
|
|
1381
1400
|
# which is why 'nx release' pushes the tag itself here \u2014 see
|
|
1382
1401
|
# releaseConfig's remarks for why that is safe on this Nx version and
|
|
1383
1402
|
# why every other provider combination keeps the explicit push step below.` : ""}
|
|
1384
|
-
- run: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2), nugetPublishEnvFragment(nugetFeedUrl2))}
|
|
1403
|
+
- run: ${releaseGuard(pythonPublishEnvFragment(pythonPublishUrl2, registryKind), nugetPublishEnvFragment(nugetFeedUrl2))}
|
|
1385
1404
|
name: Release \u2014 version, tag${githubReleases ? ", publish and GitHub Release" : " and publish"} (npm + Python + C#)
|
|
1386
1405
|
if: \${{ ${onMain} }}
|
|
1387
1406
|
env:
|
|
1388
|
-
${npmAuthName}: ${npmAuthValue}
|
|
1407
|
+
${npmAuthName}: ${npmAuthValue}${pypiTokenEnvLine(registryKind, (name) => `\${{ secrets.${name} }}`, " ".repeat(10))}
|
|
1389
1408
|
RELEASE_SPECIFIER: \${{ vars.RELEASE_SPECIFIER }}${githubReleases ? `
|
|
1390
1409
|
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}` : ""}
|
|
1391
1410
|
${githubReleases ? "" : `
|
|
@@ -1498,7 +1517,13 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
|
|
|
1498
1517
|
};
|
|
1499
1518
|
const sync = { ...nxJson.sync, ...SYNC_CONFIG };
|
|
1500
1519
|
const mnci = { ...nxJson.mnci, ...mnciConfig(options) };
|
|
1501
|
-
const
|
|
1520
|
+
const rootManifest = readJson((0, import_node_path2.join)(workspaceRoot, "package.json"));
|
|
1521
|
+
const hasPythonPlugin = (rootManifest.devDependencies ?? {})["@mnci/nx-python-pip"] !== void 0 || (rootManifest.dependencies ?? {})["@mnci/nx-python-pip"] !== void 0;
|
|
1522
|
+
const withRelease = withReleaseConfig(nxJson, options.ci);
|
|
1523
|
+
const patched = withPythonGraphPlugin(
|
|
1524
|
+
withSharedGlobals(withEslintPlugin(withRelease)),
|
|
1525
|
+
hasPythonPlugin
|
|
1526
|
+
);
|
|
1502
1527
|
onProgress("nx.json \u2014 release, sync, generators, shared inputs, mnci block");
|
|
1503
1528
|
writeFileEnsured(nxJsonPath, toJson({ ...patched, generators, sync, mnci }));
|
|
1504
1529
|
onProgress("package.json \u2014 root scripts, TS compilers, ESLint toolchain, overrides");
|
|
@@ -1892,14 +1917,22 @@ function pascalScope(scope) {
|
|
|
1892
1917
|
var CSHARP_VERSION_ACTIONS_PATH = "tools/csharp-version-actions.cjs";
|
|
1893
1918
|
var CSHARP_VERSION_ACTIONS = `'use strict'
|
|
1894
1919
|
|
|
1895
|
-
const {
|
|
1920
|
+
const { posix } = require('node:path')
|
|
1896
1921
|
const { VersionActions } = require('nx/release')
|
|
1897
1922
|
|
|
1898
1923
|
const VERSION_TAG = /<Version>([^<]*)<\\/Version>/
|
|
1899
1924
|
|
|
1925
|
+
/*
|
|
1926
|
+
* posix.join, never plain join. An Nx Tree path is workspace-relative and
|
|
1927
|
+
* forward-slashed on EVERY platform, while join emits a backslashed path on
|
|
1928
|
+
* Windows. This value is handed back to nx release for changelog and manifest
|
|
1929
|
+
* bookkeeping, and interpolated into the user-facing error below, so it was
|
|
1930
|
+
* wrong on every Windows machine. The same bug was already fixed in the
|
|
1931
|
+
* Python and Flutter plugins' release actions; this third copy was missed.
|
|
1932
|
+
*/
|
|
1900
1933
|
function findCsproj (tree, root) {
|
|
1901
1934
|
const name = tree.children(root).find((entry) => entry.endsWith('.csproj'))
|
|
1902
|
-
return name ? join(root, name) : null
|
|
1935
|
+
return name ? posix.join(root, name) : null
|
|
1903
1936
|
}
|
|
1904
1937
|
|
|
1905
1938
|
/**
|
|
@@ -2836,18 +2869,35 @@ function pythonPipPluginSpec() {
|
|
|
2836
2869
|
return process.env.MNCI2_PYTHON_PIP_SPEC ?? "@mnci/nx-python-pip";
|
|
2837
2870
|
}
|
|
2838
2871
|
function ensurePythonPipPlugin(workspaceRoot) {
|
|
2839
|
-
if (hasPlugin(workspaceRoot, "@mnci/nx-python-pip")) {
|
|
2872
|
+
if (!hasPlugin(workspaceRoot, "@mnci/nx-python-pip")) {
|
|
2873
|
+
const spec = pythonPipPluginSpec();
|
|
2874
|
+
logger.step(`Installing the Python toolchain plugin (${spec})`);
|
|
2875
|
+
if (runShell("npm", ["install", "--save-dev", spec, "--no-audit", "--no-fund"], workspaceRoot) !== 0) {
|
|
2876
|
+
throw new Error("npm install of @mnci/nx-python-pip failed");
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
registerPythonGraphPlugin(workspaceRoot);
|
|
2880
|
+
}
|
|
2881
|
+
function registerPythonGraphPlugin(workspaceRoot) {
|
|
2882
|
+
const nxJsonPath = (0, import_node_path12.join)(workspaceRoot, "nx.json");
|
|
2883
|
+
if (!fileExists(nxJsonPath)) {
|
|
2840
2884
|
return;
|
|
2841
2885
|
}
|
|
2842
|
-
const
|
|
2843
|
-
|
|
2844
|
-
if (
|
|
2845
|
-
|
|
2886
|
+
const nxJson = readJson(nxJsonPath);
|
|
2887
|
+
const patched = withPythonGraphPlugin(nxJson, true);
|
|
2888
|
+
if (patched.plugins?.includes(PYTHON_GRAPH_PLUGIN) !== true) {
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
if (nxJson.plugins?.includes(PYTHON_GRAPH_PLUGIN) === true) {
|
|
2892
|
+
return;
|
|
2846
2893
|
}
|
|
2894
|
+
logger.step(`Registering ${PYTHON_GRAPH_PLUGIN} so nx affected sees Python dependencies`);
|
|
2895
|
+
writeFileEnsured(nxJsonPath, toJson(patched));
|
|
2847
2896
|
}
|
|
2848
2897
|
var PYTHON_REQUIREMENTS_DEV = `build
|
|
2849
2898
|
twine
|
|
2850
2899
|
ruff
|
|
2900
|
+
mypy
|
|
2851
2901
|
pytest
|
|
2852
2902
|
pip-audit
|
|
2853
2903
|
`;
|
|
@@ -4993,7 +5043,7 @@ function readCliVersion(packageDirectory) {
|
|
|
4993
5043
|
}
|
|
4994
5044
|
}
|
|
4995
5045
|
|
|
4996
|
-
// src/
|
|
5046
|
+
// src/main.ts
|
|
4997
5047
|
function buildProgram(cliVersion) {
|
|
4998
5048
|
const program = new import_commander.Command();
|
|
4999
5049
|
program.name("mnci").description("MoNecromanCI \u2014 a thin CLI over official Nx plugins").version(cliVersion, "-v, --version", "display the version");
|