@mnci/cli 4.7.1 → 4.8.1
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 +55 -3
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -944,13 +944,17 @@ function releaseGuard(pythonPublishEnv, nugetPublishEnv) {
|
|
|
944
944
|
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)"`;
|
|
945
945
|
}
|
|
946
946
|
var PYPI_TOKEN_VARIABLE = "PYPI_TOKEN";
|
|
947
|
+
var AZURE_PAT_VARIABLE = "PAT";
|
|
948
|
+
function azurePatPreflight(countExpression, subject) {
|
|
949
|
+
return `if(!process.env.${AZURE_PAT_VARIABLE}){console.error('This workspace has '+${countExpression}+' ${subject} package(s) to publish to Azure Artifacts but ${AZURE_PAT_VARIABLE} is empty. Add your base64-encoded Azure DevOps PAT as a secret named ${AZURE_PAT_VARIABLE}, or remove the ${subject} packages from release.projects.');process.exit(1)}`;
|
|
950
|
+
}
|
|
947
951
|
function pypiTokenEnvLine(registryKind, variableReference, indent) {
|
|
948
952
|
return registryKind === "npm" ? `
|
|
949
953
|
${indent}${PYPI_TOKEN_VARIABLE}: ${variableReference(PYPI_TOKEN_VARIABLE)}` : "";
|
|
950
954
|
}
|
|
951
955
|
function pythonPublishEnvFragment(pythonPublishUrl2, registryKind) {
|
|
952
956
|
if (pythonPublishUrl2 !== void 0) {
|
|
953
|
-
return `if(hasPython){env.TWINE_REPOSITORY_URL='${pythonPublishUrl2}';env.TWINE_USERNAME='AzureArtifacts';env.TWINE_PASSWORD=Buffer.from(process.env
|
|
957
|
+
return `if(hasPython){${azurePatPreflight("pythonCount", "Python")}env.TWINE_REPOSITORY_URL='${pythonPublishUrl2}';env.TWINE_USERNAME='AzureArtifacts';env.TWINE_PASSWORD=Buffer.from(process.env.${AZURE_PAT_VARIABLE},'base64').toString()}`;
|
|
954
958
|
}
|
|
955
959
|
if (registryKind !== "npm") {
|
|
956
960
|
return "";
|
|
@@ -958,10 +962,10 @@ function pythonPublishEnvFragment(pythonPublishUrl2, registryKind) {
|
|
|
958
962
|
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'}`;
|
|
959
963
|
}
|
|
960
964
|
function nugetPublishEnvFragment(nugetFeedUrl2) {
|
|
961
|
-
return nugetFeedUrl2 ?
|
|
965
|
+
return nugetFeedUrl2 ? `if(hasCsharp){${azurePatPreflight("csharpCount", "C#")}env.NUGET_PAT=Buffer.from(process.env.${AZURE_PAT_VARIABLE},'base64').toString()}` : "";
|
|
962
966
|
}
|
|
963
967
|
function npmAuthEnvVariable(registryKind, variableReference) {
|
|
964
|
-
return registryKind === "npm" ? ["NODE_AUTH_TOKEN", variableReference("NPM_TOKEN")] : [
|
|
968
|
+
return registryKind === "npm" ? ["NODE_AUTH_TOKEN", variableReference("NPM_TOKEN")] : [AZURE_PAT_VARIABLE, variableReference(AZURE_PAT_VARIABLE)];
|
|
965
969
|
}
|
|
966
970
|
function poolBlock(agent) {
|
|
967
971
|
return /^(?:ubuntu|windows|macos)-/i.test(agent) ? ` vmImage: ${agent}` : ` name: ${agent}`;
|
|
@@ -4718,6 +4722,53 @@ function checkNpmrc(workspaceRoot, registry, scope) {
|
|
|
4718
4722
|
remedy: "run `mnci upgrade`"
|
|
4719
4723
|
};
|
|
4720
4724
|
}
|
|
4725
|
+
function checkNpmrcCredentialResolves(workspaceRoot, environment = process.env) {
|
|
4726
|
+
const npmrcPath = (0, import_node_path19.join)(workspaceRoot, ".npmrc");
|
|
4727
|
+
if (!fileExists(npmrcPath)) {
|
|
4728
|
+
return void 0;
|
|
4729
|
+
}
|
|
4730
|
+
const npmrc = (0, import_node_fs12.readFileSync)(npmrcPath, "utf8");
|
|
4731
|
+
const credentials = npmrc.split("\n").filter((line) => !line.trimStart().startsWith(";") && !line.trimStart().startsWith("#")).filter((line) => /(?:_authToken|_password|_auth)\s*=/u.test(line));
|
|
4732
|
+
const referenced = [
|
|
4733
|
+
...new Set(
|
|
4734
|
+
credentials.flatMap(
|
|
4735
|
+
(line) => Array.from(line.matchAll(/\$\{(\w+)\}/gu), (match) => match[1])
|
|
4736
|
+
)
|
|
4737
|
+
)
|
|
4738
|
+
];
|
|
4739
|
+
if (referenced.length === 0) {
|
|
4740
|
+
return void 0;
|
|
4741
|
+
}
|
|
4742
|
+
const unset = referenced.filter((name) => (environment[name] ?? "") === "");
|
|
4743
|
+
if (unset.length === 0) {
|
|
4744
|
+
return npmjsCredentialShape(credentials, environment);
|
|
4745
|
+
}
|
|
4746
|
+
return {
|
|
4747
|
+
check: "npm credentials in this workspace resolve to something",
|
|
4748
|
+
ok: false,
|
|
4749
|
+
detail: `.npmrc authenticates with \${${unset.join("}, ${")}}, which ${unset.length > 1 ? "are" : "is"} unset here \u2014 and a project .npmrc beats your user one, so npm will send an EMPTY token from this directory rather than the one \`npm login\` wrote. Writes are then refused as a 404 on the PUT, which reads like a missing package`,
|
|
4750
|
+
remedy: "nothing, for installing or building \u2014 this only affects authenticated commands. To publish or deprecate by hand, run it from outside this workspace, or export a real token first. If it still fails there, `npm whoami` \u2014 an expired token gives the same 404"
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
var NPM_TOKEN_PREFIX = "npm_";
|
|
4754
|
+
var LEGACY_NPM_TOKEN = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu;
|
|
4755
|
+
function npmjsCredentialShape(credentials, environment) {
|
|
4756
|
+
const line = credentials.find((entry) => entry.includes("//registry.npmjs.org/:_authToken="));
|
|
4757
|
+
const variable = line === void 0 ? void 0 : /\$\{(\w+)\}/u.exec(line)?.[1];
|
|
4758
|
+
if (variable === void 0) {
|
|
4759
|
+
return void 0;
|
|
4760
|
+
}
|
|
4761
|
+
const value = environment[variable] ?? "";
|
|
4762
|
+
if (value.startsWith(NPM_TOKEN_PREFIX) || LEGACY_NPM_TOKEN.test(value)) {
|
|
4763
|
+
return void 0;
|
|
4764
|
+
}
|
|
4765
|
+
return {
|
|
4766
|
+
check: "the credential bound for npmjs.org looks like an npm token",
|
|
4767
|
+
ok: false,
|
|
4768
|
+
detail: `\${${variable}} is set (${value.length} characters) but does not start with '${NPM_TOKEN_PREFIX}' and is not a legacy UUID token, so it is probably a credential for somewhere else \u2014 '${variable}' is a generic name that other tooling also sets, and inside this workspace it is sent to the PUBLIC registry. A write then fails as a 404 on the PUT, which reads like a missing package`,
|
|
4769
|
+
remedy: `\`npm whoami\` to confirm \u2014 it is the only thing that separates a wrong token from an expired one. Then unset \`${variable}\` for local work, or set it to a real npm token`
|
|
4770
|
+
};
|
|
4771
|
+
}
|
|
4721
4772
|
function checkVersionActions(workspaceRoot) {
|
|
4722
4773
|
const candidates = [
|
|
4723
4774
|
...(0, import_node_fs12.globSync)("packages/*/pubspec.yaml", { cwd: workspaceRoot }),
|
|
@@ -4902,6 +4953,7 @@ function collectFindings(workspaceRoot) {
|
|
|
4902
4953
|
checkEslintPlugin(nxJson),
|
|
4903
4954
|
checkResolvedEslint(workspaceRoot),
|
|
4904
4955
|
checkNpmrc(workspaceRoot, nxJson.mnci?.registry, nxJson.mnci?.scope),
|
|
4956
|
+
checkNpmrcCredentialResolves(workspaceRoot),
|
|
4905
4957
|
checkNoRootRuntimeDependencies(workspaceRoot),
|
|
4906
4958
|
...checkRollupSourceMaps(workspaceRoot),
|
|
4907
4959
|
...checkDeclarationSpecifiers(workspaceRoot),
|