vouchington-tooling 0.12.1 → 0.12.3

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.
@@ -1,13 +1,17 @@
1
1
  import { scheduler } from 'node:timers/promises';
2
2
  import { runPnpm } from './exec.mjs';
3
3
  import { nativeBinariesMatchRuntime, repairedNativeBinariesMatchRuntime } from './native-health.mjs';
4
- import { buildLedgersAllowNativeRepair, pendingBuilds } from './pending-builds.mjs';
4
+ import { buildLedgersAllowNativeRepair, deduplicatePendingBuilds, pendingBuilds, } from './pending-builds.mjs';
5
5
  import { INSTALL_TERMINATION_FAILED } from './process.mjs';
6
6
  import { formatReleaseAgeFailure, isReleaseAgeViolation } from './release-age.mjs';
7
7
  import { findWorkspaceLinkMismatches, forcedInstallArgs, logWorkspaceLinkMismatches, } from './support.mjs';
8
8
  function fail(message) {
9
9
  throw new Error(message);
10
10
  }
11
+ function failPendingBuildLedger(phase, state) {
12
+ const ids = state.kind === 'pending' ? `; remaining IDs: ${JSON.stringify(state.ids)}` : '';
13
+ fail(`${phase} completed without a clear pending build ledger${ids}`);
14
+ }
11
15
  export function withScriptPolicy(args, installScripts) {
12
16
  return installScripts ? args : [...args, '--ignore-scripts'];
13
17
  }
@@ -49,16 +53,15 @@ async function verifyInstallHealth(runCapture, phase, repairedNativePaths = [])
49
53
  export async function finalizePendingBuilds(options, runCapture, phase) {
50
54
  const before = await pendingBuilds();
51
55
  if (options.installScripts && before.kind === 'unknown')
52
- fail(`${phase} completed without a clear pending build ledger`);
56
+ failPendingBuildLedger(phase, before);
53
57
  if (options.installScripts && before.kind === 'pending') {
58
+ const deduplicated = await deduplicatePendingBuilds();
59
+ if (deduplicated.kind !== 'pending')
60
+ failPendingBuildLedger(phase, deduplicated);
54
61
  await install(['rebuild', '--pending', '--recursive'], options, 'pending scripts rebuild');
55
- let after = await pendingBuilds();
56
- if (after.kind === 'pending' && after.ids.length === 1 && after.ids[0] === '.') {
57
- await install(['rebuild', '--pending', '--workspace-root'], options, 'pending workspace root rebuild');
58
- after = await pendingBuilds();
59
- }
62
+ const after = await pendingBuilds();
60
63
  if (after.kind !== 'clear')
61
- fail(`${phase} completed without a clear pending build ledger`);
64
+ failPendingBuildLedger(phase, after);
62
65
  }
63
66
  await verifyInstallHealth(runCapture, phase);
64
67
  return options.installScripts ? { kind: 'clear' } : before;
@@ -7,4 +7,5 @@ export type PendingBuildState = {
7
7
  kind: 'unknown';
8
8
  };
9
9
  export declare function pendingBuilds(): Promise<PendingBuildState>;
10
+ export declare function deduplicatePendingBuilds(): Promise<PendingBuildState>;
10
11
  export declare function buildLedgersAllowNativeRepair(): Promise<boolean>;
@@ -1,9 +1,10 @@
1
- import { readFile } from 'node:fs/promises';
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { parse } from 'yaml';
3
+ import { parse, stringify } from 'yaml';
4
+ const modulesPath = () => path.join(process.cwd(), 'node_modules', '.modules.yaml');
4
5
  async function buildLedgers() {
5
6
  try {
6
- const value = parse(await readFile(path.join(process.cwd(), 'node_modules', '.modules.yaml'), 'utf8'));
7
+ const value = parse(await readFile(modulesPath(), 'utf8'));
7
8
  if (typeof value !== 'object' || value === null || Array.isArray(value))
8
9
  return undefined;
9
10
  // oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- validate the parsed YAML object before reading its fields
@@ -18,6 +19,7 @@ async function buildLedgers() {
18
19
  return {
19
20
  ignoredBuilds: ignored,
20
21
  pendingBuilds: pending.length === 0 ? { kind: 'clear' } : { ids: pending.toSorted(), kind: 'pending' },
22
+ record,
21
23
  };
22
24
  }
23
25
  catch {
@@ -27,6 +29,22 @@ async function buildLedgers() {
27
29
  export async function pendingBuilds() {
28
30
  return (await buildLedgers())?.pendingBuilds ?? { kind: 'unknown' };
29
31
  }
32
+ export async function deduplicatePendingBuilds() {
33
+ const ledgers = await buildLedgers();
34
+ if (ledgers === undefined || ledgers.pendingBuilds.kind !== 'pending')
35
+ return ledgers?.pendingBuilds ?? { kind: 'unknown' };
36
+ // `buildLedgers` has already verified every pending entry is a string.
37
+ const unique = [...new Set(ledgers.record.pendingBuilds)];
38
+ if (unique.length === ledgers.pendingBuilds.ids.length)
39
+ return ledgers.pendingBuilds;
40
+ try {
41
+ await writeFile(modulesPath(), stringify({ ...ledgers.record, pendingBuilds: unique }));
42
+ }
43
+ catch {
44
+ return { kind: 'unknown' };
45
+ }
46
+ return pendingBuilds();
47
+ }
30
48
  export async function buildLedgersAllowNativeRepair() {
31
49
  const ledgers = await buildLedgers();
32
50
  return (ledgers !== undefined &&
@@ -29,10 +29,10 @@ if [ "\${PNPM_FAIL_RELEASE_AGE_CALL:-0}" = "$calls" ]; then
29
29
  exit 1
30
30
  fi
31
31
  if [ -n "\${PNPM_SLEEP_SECONDS:-}" ]; then sleep "$PNPM_SLEEP_SECONDS"; fi
32
- if [ "\${PNPM_INVALID_PENDING_BUILDS:-0}" = 1 ]; then
32
+ if [ "\${1:-}" != rebuild ] && [ "\${PNPM_INVALID_PENDING_BUILDS:-0}" = 1 ]; then
33
33
  mkdir -p "$PNPM_NODE_MODULES"
34
34
  printf 'pendingBuilds: invalid\n' > "$PNPM_NODE_MODULES/.modules.yaml"
35
- elif [ -n "\${PNPM_PENDING_BUILDS:-}" ]; then
35
+ elif [ "\${1:-}" != rebuild ] && [ -n "\${PNPM_PENDING_BUILDS:-}" ]; then
36
36
  mkdir -p "$PNPM_NODE_MODULES"
37
37
  printf 'pendingBuilds: [%s]\\n' "$PNPM_PENDING_BUILDS" > "$PNPM_NODE_MODULES/.modules.yaml"
38
38
  elif [ ! -f "$PNPM_NODE_MODULES/.modules.yaml" ]; then
@@ -49,6 +49,8 @@ case " $* " in
49
49
  fi
50
50
  if [ "\${PNPM_REBUILD_INVALID_LEDGER:-0}" = 1 ]; then
51
51
  printf 'pendingBuilds: invalid\n' > "$PNPM_NODE_MODULES/.modules.yaml"
52
+ elif [ "\${PNPM_REBUILD_REQUIRES_DEDUPED:-0}" = 1 ] && sed -n 's/.*\\[\\(.*\\)\\].*/\\1/p' "$PNPM_NODE_MODULES/.modules.yaml" | tr ',' '\\n' | sed 's/^ *//; s/ *$//' | sort | uniq -d | grep -q .; then
53
+ cp "$PNPM_NODE_MODULES/.modules.yaml" "$PNPM_NODE_MODULES/.modules.yaml.rebuild-left-pending"
52
54
  elif [ -n "\${PNPM_REBUILD_PENDING_BUILDS:-}" ]; then
53
55
  printf 'pendingBuilds: [%s]\n' "$PNPM_REBUILD_PENDING_BUILDS" > "$PNPM_NODE_MODULES/.modules.yaml"
54
56
  else
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "Vouchington CLI and extractable tooling libraries.",
5
5
  "homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
6
6
  "bugs": {