@mnci/cli 4.40.8 → 4.41.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 CHANGED
@@ -299,27 +299,35 @@ function planIsEmpty(stdout) {
299
299
  return false;
300
300
  }
301
301
  }
302
- function auditNpm(result, dryRun, log) {
302
+ function auditNpm(result, production, dryRun, log) {
303
303
  let report;
304
+ let shipped;
304
305
  try {
305
306
  report = JSON.parse(result.stdout);
307
+ shipped = JSON.parse(production.stdout);
306
308
  } catch {
307
309
  log(`npm audit produced no JSON (exit ${result.status}) - not blocking on a broken audit.`);
308
310
  return 0;
309
311
  }
310
- const { blocking, total, notes } = classifyNpmAudit(report);
312
+ const { notes } = classifyNpmAudit(report);
313
+ const { blocking, total } = classifyNpmAudit(shipped);
314
+ const productionNames = new Set(Object.keys(shipped.vulnerabilities ?? {}));
315
+ const developmentOnly = classifyNpmAudit(report).blocking.filter((advisory) => !productionNames.has(advisory.name));
311
316
  for (const note of notes) {
312
317
  log(note);
313
318
  }
319
+ for (const advisory of developmentOnly) {
320
+ log(` note [${advisory.severity}] ${advisory.name} - reaches only dev dependencies, which no consumer receives, so it does not block`);
321
+ }
314
322
  if (blocking.length === 0) {
315
- log(`npm audit - ${total} advisory(ies), none actionable at moderate or above.`);
323
+ log(`npm audit - ${Object.keys(report.vulnerabilities ?? {}).length} advisory(ies), none actionable at moderate or above in production dependencies.`);
316
324
  return 0;
317
325
  }
318
326
  if (planIsEmpty(dryRun().stdout)) {
319
327
  for (const advisory of blocking) {
320
328
  log(` note [${advisory.severity}] ${advisory.name} - npm reports a fix, but npm audit fix has nothing to apply`);
321
329
  }
322
- log(`npm audit - ${total} advisory(ies); ${blocking.length} reported as fixable, but no patched release is reachable, so there is nothing to do here.`);
330
+ log(`npm audit - ${total} production advisory(ies); ${blocking.length} reported as fixable, but no patched release is reachable, so there is nothing to do here.`);
323
331
  return 0;
324
332
  }
325
333
  for (const advisory of blocking) {
@@ -348,7 +356,12 @@ function runAudit(workspaceRoot, dependencies = {}) {
348
356
  }
349
357
  };
350
358
  log(groupStart(host, "npm audit"));
351
- const npm = auditNpm(processes.capture("npm", ["audit", "--json"]), () => processes.capture("npm", ["audit", "fix", "--dry-run", "--json"]), log);
359
+ const npm = auditNpm(
360
+ processes.capture("npm", ["audit", "--json"]),
361
+ processes.capture("npm", ["audit", "--omit=dev", "--json"]),
362
+ () => processes.capture("npm", ["audit", "fix", "--omit=dev", "--dry-run", "--json"]),
363
+ log
364
+ );
352
365
  closeGroup();
353
366
  if (npm !== 0) {
354
367
  return npm;
@@ -7885,6 +7898,33 @@ function runKinds(options) {
7885
7898
  var import_node_child_process = require("child_process");
7886
7899
  var import_node_fs29 = require("fs");
7887
7900
  var import_node_path34 = require("path");
7901
+
7902
+ // src/workspace-diagnostics/stranded-release-tags.algorithm.ts
7903
+ function compareVersions2(left, right) {
7904
+ const a = left.split(".").map(Number);
7905
+ const b = right.split(".").map(Number);
7906
+ return a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || 0;
7907
+ }
7908
+ function versionsOf(tags, name) {
7909
+ return tags.filter((tag) => tag.startsWith(`${name}@`)).map((tag) => tag.slice(name.length + 1)).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
7910
+ }
7911
+ function findStrandedReleaseTags(projects, tags) {
7912
+ const stranded = [];
7913
+ for (const project of projects) {
7914
+ const unscoped = /^@[^/]+\/(.+)$/.exec(project)?.[1];
7915
+ if (unscoped === void 0) {
7916
+ continue;
7917
+ }
7918
+ const current = versionsOf(tags, project).sort(compareVersions2).at(-1);
7919
+ const newest = versionsOf(tags, unscoped).sort(compareVersions2).at(-1);
7920
+ if (newest !== void 0 && (current === void 0 || compareVersions2(newest, current) > 0)) {
7921
+ stranded.push({ project, oldTag: `${unscoped}@${newest}`, newTag: `${project}@${newest}` });
7922
+ }
7923
+ }
7924
+ return stranded;
7925
+ }
7926
+
7927
+ // src/workspace-diagnostics/check-invariants.use-case.ts
7888
7928
  var SUPPORTED_ESLINT_MAJOR = ESLINT_VERSION.replace(/^\D*/, "").split(".", 1)[0];
7889
7929
  function toPosix2(path) {
7890
7930
  return path.replaceAll("\\", "/");
@@ -8353,6 +8393,24 @@ function checkLockfileHasNoLocalRegistry(workspaceRoot) {
8353
8393
  remedy: "run `mnci upgrade`, which removes it, then commit package-lock.json"
8354
8394
  };
8355
8395
  }
8396
+ function checkReleaseTagsResolve(workspaceRoot, nxJson) {
8397
+ const pattern = nxJson.release?.releaseTag?.pattern;
8398
+ if (pattern !== void 0 && pattern !== "{projectName}@{version}") {
8399
+ return void 0;
8400
+ }
8401
+ const listed = runCapture("git", ["tag", "--list"], workspaceRoot);
8402
+ if (listed.status !== 0) {
8403
+ return void 0;
8404
+ }
8405
+ 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);
8406
+ const stranded = findStrandedReleaseTags(projects, listed.stdout.split(/\r?\n/).filter(Boolean));
8407
+ return {
8408
+ check: "release tags resolve under each project's current name",
8409
+ ok: stranded.length === 0,
8410
+ 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`,
8411
+ remedy: `on the commit of each old tag run: ${stranded.map((entry) => `git tag ${entry.newTag} ${entry.oldTag}^{commit}`).join(" ; ")} - then push the tags`
8412
+ };
8413
+ }
8356
8414
  function collectFindings(workspaceRoot) {
8357
8415
  const nxJsonPath = (0, import_node_path34.join)(workspaceRoot, "nx.json");
8358
8416
  if (!fileExists(nxJsonPath)) {
@@ -8381,7 +8439,8 @@ function collectFindings(workspaceRoot) {
8381
8439
  ...checkPipelinePhases(workspaceRoot),
8382
8440
  ...checkNativeBuildConfig(workspaceRoot),
8383
8441
  checkDependencyRangesNotPreserved(nxJson),
8384
- checkLockfileHasNoLocalRegistry(workspaceRoot)
8442
+ checkLockfileHasNoLocalRegistry(workspaceRoot),
8443
+ checkReleaseTagsResolve(workspaceRoot, nxJson)
8385
8444
  ].filter((finding) => finding !== void 0);
8386
8445
  }
8387
8446
  function runDoctor(workspaceRoot, options = {}) {