@rightkit/release 0.6.10 → 0.6.11
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 +7 -5
- package/admission-files.mjs +3 -0
- package/admission.mjs +2 -2
- package/advisory-exceptions.mjs +41 -5
- package/android-play-upload.mjs +16 -15
- package/app-check.mjs +13 -9
- package/bin/rightkit-gate.mjs +762 -345
- package/broker-pins.mjs +152 -0
- package/build-release.mjs +80 -27
- package/cargo-ledger.mjs +62 -0
- package/cargo-target-shim.mjs +98 -26
- package/cli/right-release.mjs +28 -4
- package/clippy-equivalence.mjs +202 -0
- package/clippy-route.mjs +543 -0
- package/committed-source.mjs +39 -5
- package/crate-workspaces.mjs +87 -0
- package/create-mac-updater.mjs +14 -2
- package/deterministic-scans.mjs +196 -21
- package/development.mjs +13 -4
- package/direct-receipt.mjs +135 -0
- package/door-policy.mjs +10 -0
- package/door.mjs +6 -6
- package/freshness-census.mjs +257 -0
- package/gate-stages.mjs +76 -10
- package/hook-retirement.mjs +65 -0
- package/init-command.mjs +1 -1
- package/inventory-check.mjs +11 -8
- package/ios-upload.mjs +20 -15
- package/local-publish.mjs +77 -41
- package/local-qualify.mjs +5 -3
- package/local-runtime.mjs +5 -4
- package/mac-package-recipe.mjs +4 -1
- package/mirror-root-artifact.mjs +18 -5
- package/ownership-class-rules.mjs +1 -1
- package/ownership-evidence.mjs +37 -13
- package/ownership-hooks.mjs +20 -59
- package/ownership-lockfiles.mjs +14 -1
- package/ownership-policy-bundle.mjs +3 -2
- package/ownership-staged.mjs +2 -1
- package/ownership.mjs +24 -0
- package/package-recipe-targets.mjs +35 -6
- package/package.json +1 -1
- package/pipeline-admission.mjs +4 -4
- package/preflight.mjs +27 -4
- package/publish-cargo.mjs +4 -3
- package/recipe-build.mjs +38 -14
- package/release-artifact-path.mjs +341 -0
- package/release-invocation.mjs +8 -1
- package/release-qa-command.mjs +25 -9
- package/release-source-brand.mjs +17 -0
- package/release-source-identity.mjs +171 -0
- package/release.mjs +44 -17
- package/rightkit-versions.json +62 -42
- package/runtime-budgets.mjs +6 -2
- package/scan-digest.mjs +71 -5
- package/sign-updater.mjs +6 -3
- package/snapshot-broker.mjs +172 -0
- package/snapshot-check.mjs +12 -6
- package/snapshot-request.mjs +207 -5
- package/snapshot.mjs +123 -10
- package/source-split.mjs +73 -0
- package/stage-commands.mjs +2 -2
- package/stage-ledger.mjs +204 -0
- package/stage-sidecar-command.mjs +5 -1
- package/stage-sidecar.mjs +100 -20
- package/swap-helper-bundle.mjs +5 -2
- package/unit-gate.mjs +45 -3
- package/web-build.mjs +6 -4
- package/win-package-recipe.mjs +20 -7
package/release.mjs
CHANGED
|
@@ -14,6 +14,8 @@ import { assertQaAdoption, assertQaBackdoorContract } from "./qa-contract.mjs";
|
|
|
14
14
|
import { assertLegalReleaseContract } from "./legal-contract.mjs";
|
|
15
15
|
import { DECLARED_UNRELATED_POLICY, declaredUnrelatedRefusal, releaseArtifactPaths } from "./hosted-workflow-policy.mjs";
|
|
16
16
|
import { assertNativeIosPrepareHasManifest, assertPrimaryReleaseCheckout, dirtyBuildInputs, resolveReleaseBuildInputs } from "./release-invocation.mjs";
|
|
17
|
+
import { resolveReleaseSource, sourceRootOf } from "./release-source-identity.mjs";
|
|
18
|
+
import { ArtifactPathError, assertSplitCommandPaths, releaseCommandSteps, resolveArtifactPath, splitArtifactContext } from "./release-artifact-path.mjs";
|
|
17
19
|
import { declaredCargoManifest, hasDefaultTauriManifest, resolveNativeCargoLayout } from "./native-cargo-layout.mjs";
|
|
18
20
|
import {
|
|
19
21
|
canonicalPackageIdentity,
|
|
@@ -275,10 +277,17 @@ const nativeFinalizer = resolveNativeFinalizerConfig(nativeAssembly);
|
|
|
275
277
|
// state root and admission record; a snapshot from anywhere else is refused. The standalone doctor resolves live.
|
|
276
278
|
const rightKitSnapshotFile = process.env[SNAPSHOT_ENV] || null;
|
|
277
279
|
let rightKitResolution = null; // null when the registry resolution failed (recorded as the `rightkit-registry` finding)
|
|
280
|
+
// The worker of a door split (row 7.04): its cwd is the snapshot, which has no git directory. Its commit and source root are the selected
|
|
281
|
+
// commit's and the snapshot's (release-source-identity.mjs); the checkout route reads them from git as before.
|
|
282
|
+
let workerSource = null;
|
|
283
|
+
let artifactPathContext = null; // the declared-artifact resolver's context (artifactContext, row 7.04c)
|
|
284
|
+
if (!opts.doctor && process.env.RK_GATE_CHECKOUT) {
|
|
285
|
+
try { workerSource = resolveReleaseSource({ cwd: process.cwd() }); } catch (error) { fail(`${error.code ?? "RK_SOURCE_IDENTITY"}: ${error.message}`); }
|
|
286
|
+
}
|
|
278
287
|
try {
|
|
279
288
|
const lockInventory = () => {
|
|
280
289
|
try {
|
|
281
|
-
const repoRoot = git(root, ["rev-parse", "--show-toplevel"]);
|
|
290
|
+
const repoRoot = workerSource ? sourceRootOf(workerSource) : git(root, ["rev-parse", "--show-toplevel"]);
|
|
282
291
|
let canonicalTarget = config.targets?.[opts.platform];
|
|
283
292
|
try { canonicalTarget = expandPackageRecipeTarget(canonicalTarget, { platform: opts.platform, appRoot: root, config }); } catch { /* reported later */ }
|
|
284
293
|
const inputs = resolveReleaseBuildInputs({ repoRoot, appRoot: root, configPath, config, target: canonicalTarget });
|
|
@@ -292,7 +301,7 @@ try {
|
|
|
292
301
|
if (!rightKitSnapshotFile) throw new RightKitRegistryError("no-admission", "no admitted RightKit registry snapshot was handed to the release worker; run it through `right-release build`, which admits the release");
|
|
293
302
|
const stateRoot = process.env.RIGHT_RELEASE_STATE_ROOT;
|
|
294
303
|
if (!stateRoot) throw new RightKitRegistryError("no-admission", "RIGHT_RELEASE_STATE_ROOT is not set; the admitted RightKit registry snapshot cannot be located");
|
|
295
|
-
const commit = git(root, ["rev-parse", "HEAD"]);
|
|
304
|
+
const commit = workerSource ? workerSource.commit : git(root, ["rev-parse", "HEAD"]);
|
|
296
305
|
boundSnapshot = loadAdmittedSnapshot(stateRoot, { releaseId: `${config.app}-${config.version}-${commit.slice(0, 8)}`, commit, platform: opts.platform, snapshotFile: rightKitSnapshotFile });
|
|
297
306
|
}
|
|
298
307
|
rightKitResolution = await prepareRightKitResolution({
|
|
@@ -348,6 +357,12 @@ await check("target", [], () => {
|
|
|
348
357
|
if (!expanded) throw new Error(`${config.app ?? "app"} has no ${opts.platform} release target`);
|
|
349
358
|
target = expanded;
|
|
350
359
|
});
|
|
360
|
+
// Row 7.04c (R-T1, R-T4): in a door split each Cargo manifest's target is bound now, once, before any step runs, and no step the app owns may name
|
|
361
|
+
// a target-relative path (the snapshot has no target directory). Checkout mode checks nothing here.
|
|
362
|
+
await check("split-artifact-paths", ["target"], () => {
|
|
363
|
+
if (!workerSource) return;
|
|
364
|
+
assertSplitCommandPaths(releaseCommandSteps({ target, config, root }), artifactContext());
|
|
365
|
+
});
|
|
351
366
|
const legalCheck = await check("legal-contract", [], () => (config.legal
|
|
352
367
|
? assertLegalReleaseContract(root, config.legal, config.app ?? path.basename(root), opts.platform)
|
|
353
368
|
: null));
|
|
@@ -636,7 +651,7 @@ if (opts.platform === "win" && target.signingContract === MSIX_SIGNING_CONTRACT)
|
|
|
636
651
|
// writes the App Installer route and the seal record. Never a second signer.
|
|
637
652
|
await runCommand(target.prePackage, root);
|
|
638
653
|
// Raw payload scan BEFORE the package is packed (a packed MSIX is only readable through its ZIP directory).
|
|
639
|
-
assertNoQaControlBinaries("msix staged payload", [
|
|
654
|
+
assertNoQaControlBinaries("msix staged payload", [resolveDeclaredPath(root, target.msix.stageDir)], { requireBinary: true, prePack: true });
|
|
640
655
|
const options = msixBuildOptions({ root, target, app: config.app, dryRun: opts.dryRun, receipts: {
|
|
641
656
|
pe: windowsReceiptPath(root, "raw-exe"), msix: windowsReceiptPath(root, "installer"),
|
|
642
657
|
dir: path.dirname(windowsReceiptPath(root, "raw-exe")) } });
|
|
@@ -645,7 +660,7 @@ if (opts.platform === "win" && target.signingContract === MSIX_SIGNING_CONTRACT)
|
|
|
645
660
|
// Second layer: read the finished package through its ZIP central directory (stored and deflate entries).
|
|
646
661
|
if (!built.dryRun) assertNoQaControlBinaries("msix package", [options.out], { requireBinary: true });
|
|
647
662
|
} else if (opts.platform === "win") {
|
|
648
|
-
const rawFiles = target.sign.prePackageFiles.map((p) =>
|
|
663
|
+
const rawFiles = target.sign.prePackageFiles.map((p) => resolveDeclaredPath(root, p));
|
|
649
664
|
const sidecarPlan = await prepareMediaSidecar(root);
|
|
650
665
|
const externalPlan = await prepareExternalBin(root);
|
|
651
666
|
await runCommand(target.prePackage, root);
|
|
@@ -894,15 +909,25 @@ function assertNoWebBundleMocksInFrontend(phase, { required }) {
|
|
|
894
909
|
} catch (error) { fail(error.message); }
|
|
895
910
|
}
|
|
896
911
|
|
|
912
|
+
// Row 7.04c (R-T2): one resolver for every declared artifact path. Checkout mode is the historical rule, byte for byte (the app root, then
|
|
913
|
+
// RIGHT_RELEASE_ARTIFACT_DIR); a door split maps a target-prefixed path to its bound Cargo target and never reads the checkout.
|
|
914
|
+
function artifactContext() {
|
|
915
|
+
artifactPathContext ??= splitArtifactContext({
|
|
916
|
+
cwd: root, env: process.env, nativeLayout, config, target: config.targets?.[opts.platform],
|
|
917
|
+
...(workerSource?.mode === "snapshot" ? { snapshotRoot: workerSource.snapshot } : {}),
|
|
918
|
+
});
|
|
919
|
+
return artifactPathContext;
|
|
920
|
+
}
|
|
921
|
+
|
|
897
922
|
function resolveReleaseArtifactPath(root, declared) {
|
|
898
|
-
|
|
899
|
-
if (
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
return
|
|
923
|
+
try { return resolveArtifactPath(declared, artifactContext()); }
|
|
924
|
+
catch (error) { if (error instanceof ArtifactPathError) fail(error.message); throw error; }
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/** A declared path that never fell back to the managed artifact directory (a staged payload, a raw EXE): the app root, or in a split the same resolver. */
|
|
928
|
+
function resolveDeclaredPath(root, declared) {
|
|
929
|
+
const context = artifactContext();
|
|
930
|
+
return context.mode === "split" ? resolveReleaseArtifactPath(root, declared) : path.resolve(root, declared);
|
|
906
931
|
}
|
|
907
932
|
|
|
908
933
|
function fail(message) {
|
|
@@ -1042,11 +1067,13 @@ function nativeSignedArtifacts(files, root) {
|
|
|
1042
1067
|
return values.map((value) => {
|
|
1043
1068
|
const declared = typeof value === "string" ? value : value?.path ?? value?.file;
|
|
1044
1069
|
if (!declared) fail("native finalizer signed artifact path is missing");
|
|
1045
|
-
const absolute =
|
|
1046
|
-
|
|
1070
|
+
const absolute = resolveDeclaredPath(root, declared);
|
|
1071
|
+
// A split's bound target lies outside the app: its absolute path is the evidence there.
|
|
1072
|
+
const evidencePath = () => { const relative = path.relative(root, absolute).replaceAll("\\", "/"); return relative.startsWith("..") ? absolute.replaceAll("\\", "/") : relative; };
|
|
1073
|
+
if (opts.dryRun) return { path: evidencePath() };
|
|
1047
1074
|
if (!existsSync(absolute)) fail(`native finalizer signed artifact missing: ${absolute}`);
|
|
1048
1075
|
return {
|
|
1049
|
-
path:
|
|
1076
|
+
path: evidencePath(),
|
|
1050
1077
|
sha256: createHash("sha256").update(readFileSync(absolute)).digest("hex"),
|
|
1051
1078
|
sizeBytes: readFileSync(absolute).length,
|
|
1052
1079
|
};
|
|
@@ -1080,7 +1107,7 @@ function nativeArchiveCandidates({ root, target, nativeAssembly }) {
|
|
|
1080
1107
|
...(target.installer?.artifacts ?? []).map((artifact) => artifact.file),
|
|
1081
1108
|
...(target.updater?.artifacts ?? []).map((artifact) => artifact.file),
|
|
1082
1109
|
].filter((value) => typeof value === "string" && value.trim());
|
|
1083
|
-
return [...new Set(declared.map((value) =>
|
|
1110
|
+
return [...new Set(declared.map((value) => resolveDeclaredPath(root, value)))];
|
|
1084
1111
|
}
|
|
1085
1112
|
|
|
1086
1113
|
function nativeFinalizerOutputPath({ finalizer, target, root }) {
|
|
@@ -1906,7 +1933,7 @@ async function verifyWindowsEmbedding({ root, target, files, markers }) {
|
|
|
1906
1933
|
console.log("dry-run: verify installer embeds the signed raw EXE");
|
|
1907
1934
|
return;
|
|
1908
1935
|
}
|
|
1909
|
-
const rawFile =
|
|
1936
|
+
const rawFile = resolveDeclaredPath(root, target.sign.prePackageFiles[0]);
|
|
1910
1937
|
const rawReceiptPath = windowsReceiptPath(root, "raw-exe");
|
|
1911
1938
|
let rawReceipt;
|
|
1912
1939
|
try { rawReceipt = JSON.parse(readFileSync(rawReceiptPath, "utf8")); } catch { fail(`missing raw EXE signing receipt: ${rawReceiptPath}`); }
|
package/rightkit-versions.json
CHANGED
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"@rightkit/outdated": "0.3.0",
|
|
30
30
|
"@rightkit/pdf-ui": "0.2.0",
|
|
31
31
|
"@rightkit/platform-ui": "0.4.0",
|
|
32
|
-
"@rightkit/qa": "0.6.
|
|
32
|
+
"@rightkit/qa": "0.6.2",
|
|
33
33
|
"@rightkit/qa-chrome": "0.1.12",
|
|
34
34
|
"@rightkit/react-shell": "0.7.2",
|
|
35
|
-
"@rightkit/release": "0.6.
|
|
35
|
+
"@rightkit/release": "0.6.11",
|
|
36
36
|
"@rightkit/settings-ui": "0.7.0",
|
|
37
37
|
"@rightkit/tauri": "0.3.0",
|
|
38
38
|
"@rightkit/tauri-shell": "0.1.3",
|
|
@@ -236,7 +236,8 @@
|
|
|
236
236
|
"0.4.9",
|
|
237
237
|
"0.5.0",
|
|
238
238
|
"0.5.1",
|
|
239
|
-
"0.5.2"
|
|
239
|
+
"0.5.2",
|
|
240
|
+
"0.6.1"
|
|
240
241
|
],
|
|
241
242
|
"@rightkit/qa-chrome": [
|
|
242
243
|
"0.1.0",
|
|
@@ -376,7 +377,8 @@
|
|
|
376
377
|
"0.6.5",
|
|
377
378
|
"0.6.6",
|
|
378
379
|
"0.6.7",
|
|
379
|
-
"0.6.8"
|
|
380
|
+
"0.6.8",
|
|
381
|
+
"0.6.10"
|
|
380
382
|
],
|
|
381
383
|
"@rightkit/settings-ui": [
|
|
382
384
|
"0.1.0",
|
|
@@ -457,56 +459,57 @@
|
|
|
457
459
|
"rightkit-asr": "0.3.1",
|
|
458
460
|
"rightkit-audio": "0.3.1",
|
|
459
461
|
"rightkit-automation": "0.6.1",
|
|
460
|
-
"rightkit-browser": "0.3.
|
|
462
|
+
"rightkit-browser": "0.3.7",
|
|
461
463
|
"rightkit-cache": "0.2.3",
|
|
462
|
-
"rightkit-channel-memory": "0.2.
|
|
464
|
+
"rightkit-channel-memory": "0.2.2",
|
|
463
465
|
"rightkit-child-process": "0.5.7",
|
|
464
466
|
"rightkit-compose": "0.2.0",
|
|
465
|
-
"rightkit-contracts": "0.1.
|
|
467
|
+
"rightkit-contracts": "0.1.8",
|
|
466
468
|
"rightkit-crash": "0.3.6",
|
|
467
469
|
"rightkit-credentials": "0.4.2",
|
|
468
470
|
"rightkit-crypto": "0.1.0",
|
|
469
471
|
"rightkit-daemon": "0.4.0",
|
|
470
|
-
"rightkit-db": "0.5.
|
|
472
|
+
"rightkit-db": "0.5.3",
|
|
471
473
|
"rightkit-device": "0.4.0",
|
|
472
|
-
"rightkit-docs": "0.1.
|
|
473
|
-
"rightkit-embed": "0.6.
|
|
474
|
+
"rightkit-docs": "0.1.3",
|
|
475
|
+
"rightkit-embed": "0.6.2",
|
|
474
476
|
"rightkit-ffmpeg": "0.2.11",
|
|
475
|
-
"rightkit-file-watch": "0.4.
|
|
477
|
+
"rightkit-file-watch": "0.4.2",
|
|
476
478
|
"rightkit-fs": "0.4.7",
|
|
477
|
-
"rightkit-fsindex": "0.
|
|
479
|
+
"rightkit-fsindex": "0.6.0",
|
|
478
480
|
"rightkit-google-identity": "0.2.0",
|
|
479
481
|
"rightkit-hooks": "0.2.0",
|
|
480
482
|
"rightkit-hotkeys": "0.1.2",
|
|
481
|
-
"rightkit-http": "0.3.
|
|
483
|
+
"rightkit-http": "0.3.9",
|
|
482
484
|
"rightkit-identity": "0.1.0",
|
|
483
485
|
"rightkit-job-queue": "0.5.1",
|
|
484
486
|
"rightkit-license": "0.2.5",
|
|
485
487
|
"rightkit-llm": "0.3.1",
|
|
486
|
-
"rightkit-logs": "0.3.
|
|
487
|
-
"rightkit-mcp": "0.7.
|
|
488
|
-
"rightkit-models": "0.5.
|
|
488
|
+
"rightkit-logs": "0.3.6",
|
|
489
|
+
"rightkit-mcp": "0.7.1",
|
|
490
|
+
"rightkit-models": "0.5.2",
|
|
489
491
|
"rightkit-motion": "0.2.0",
|
|
490
492
|
"rightkit-oauth": "0.10.0",
|
|
491
493
|
"rightkit-ocr": "0.2.3",
|
|
492
494
|
"rightkit-onnx": "0.2.8",
|
|
493
495
|
"rightkit-overlay": "0.2.0",
|
|
494
496
|
"rightkit-overlay-win": "0.1.0",
|
|
495
|
-
"rightkit-ownership": "0.4.
|
|
496
|
-
"rightkit-pdf": "0.3.
|
|
497
|
+
"rightkit-ownership": "0.4.3",
|
|
498
|
+
"rightkit-pdf": "0.3.4",
|
|
497
499
|
"rightkit-platform-rules": "0.1.0",
|
|
498
500
|
"rightkit-playback": "0.3.0",
|
|
501
|
+
"rightkit-qa": "0.9.2",
|
|
499
502
|
"rightkit-qa-driver": "0.7.0",
|
|
500
503
|
"rightkit-record": "0.3.3",
|
|
501
504
|
"rightkit-review": "0.4.0",
|
|
502
505
|
"rightkit-sandbox": "0.6.1",
|
|
503
|
-
"rightkit-search": "0.4.
|
|
504
|
-
"rightkit-send": "0.
|
|
506
|
+
"rightkit-search": "0.4.1",
|
|
507
|
+
"rightkit-send": "0.3.0",
|
|
505
508
|
"rightkit-sidecar": "0.3.0",
|
|
506
509
|
"rightkit-speech-client": "0.4.0",
|
|
507
510
|
"rightkit-spend": "0.2.0",
|
|
508
511
|
"rightkit-sync": "0.2.2",
|
|
509
|
-
"rightkit-tauri-shell": "0.
|
|
512
|
+
"rightkit-tauri-shell": "0.7.0",
|
|
510
513
|
"rightkit-time": "0.1.0",
|
|
511
514
|
"rightkit-transcript": "0.4.0",
|
|
512
515
|
"rightkit-tts": "0.2.3",
|
|
@@ -542,7 +545,7 @@
|
|
|
542
545
|
"rightkit-browser": "0.3.6",
|
|
543
546
|
"rightkit-cache": "0.2.3",
|
|
544
547
|
"rightkit-channel-memory": "0.2.1",
|
|
545
|
-
"rightkit-child-process": "0.5.
|
|
548
|
+
"rightkit-child-process": "0.5.7",
|
|
546
549
|
"rightkit-compose": "0.2.0",
|
|
547
550
|
"rightkit-contracts": "0.1.7",
|
|
548
551
|
"rightkit-control": "0.3.0",
|
|
@@ -631,13 +634,13 @@
|
|
|
631
634
|
"@rightkit/logs": "0.1.6",
|
|
632
635
|
"@rightkit/media-ui": "0.3.4",
|
|
633
636
|
"@rightkit/onboarding": "0.6.3",
|
|
634
|
-
"@rightkit/outdated": "0.
|
|
637
|
+
"@rightkit/outdated": "0.3.0",
|
|
635
638
|
"@rightkit/pdf-ui": "0.2.0",
|
|
636
639
|
"@rightkit/platform-ui": "0.4.0",
|
|
637
640
|
"@rightkit/qa": "0.6.1",
|
|
638
|
-
"@rightkit/qa-chrome": "0.1.
|
|
641
|
+
"@rightkit/qa-chrome": "0.1.12",
|
|
639
642
|
"@rightkit/react-shell": "0.7.2",
|
|
640
|
-
"@rightkit/release": "0.6.
|
|
643
|
+
"@rightkit/release": "0.6.10",
|
|
641
644
|
"@rightkit/settings-ui": "0.7.0",
|
|
642
645
|
"@rightkit/shell": "0.1.1",
|
|
643
646
|
"@rightkit/tauri": "0.3.0",
|
|
@@ -652,7 +655,8 @@
|
|
|
652
655
|
"0.2.1",
|
|
653
656
|
"0.3.1",
|
|
654
657
|
"0.4.0",
|
|
655
|
-
"0.4.1"
|
|
658
|
+
"0.4.1",
|
|
659
|
+
"0.4.2"
|
|
656
660
|
],
|
|
657
661
|
"rightkit-browser": [
|
|
658
662
|
"0.2.0",
|
|
@@ -661,7 +665,8 @@
|
|
|
661
665
|
"0.3.0",
|
|
662
666
|
"0.3.1",
|
|
663
667
|
"0.3.4",
|
|
664
|
-
"0.3.5"
|
|
668
|
+
"0.3.5",
|
|
669
|
+
"0.3.6"
|
|
665
670
|
],
|
|
666
671
|
"rightkit-models": [
|
|
667
672
|
"0.2.1",
|
|
@@ -674,7 +679,8 @@
|
|
|
674
679
|
"0.3.0",
|
|
675
680
|
"0.3.1",
|
|
676
681
|
"0.3.2",
|
|
677
|
-
"0.4.4"
|
|
682
|
+
"0.4.4",
|
|
683
|
+
"0.5.1"
|
|
678
684
|
],
|
|
679
685
|
"rightkit-audio": [
|
|
680
686
|
"0.1.0",
|
|
@@ -690,7 +696,8 @@
|
|
|
690
696
|
"0.3.1",
|
|
691
697
|
"0.4.0",
|
|
692
698
|
"0.4.3",
|
|
693
|
-
"0.5.1"
|
|
699
|
+
"0.5.1",
|
|
700
|
+
"0.5.2"
|
|
694
701
|
],
|
|
695
702
|
"rightkit-embed": [
|
|
696
703
|
"0.2.1",
|
|
@@ -700,7 +707,8 @@
|
|
|
700
707
|
"0.3.2",
|
|
701
708
|
"0.4.0",
|
|
702
709
|
"0.5.0",
|
|
703
|
-
"0.6.0"
|
|
710
|
+
"0.6.0",
|
|
711
|
+
"0.6.1"
|
|
704
712
|
],
|
|
705
713
|
"rightkit-jobs": [
|
|
706
714
|
"0.2.1",
|
|
@@ -720,7 +728,8 @@
|
|
|
720
728
|
"0.5.1",
|
|
721
729
|
"0.5.2",
|
|
722
730
|
"0.5.3",
|
|
723
|
-
"0.6.0"
|
|
731
|
+
"0.6.0",
|
|
732
|
+
"0.7.0"
|
|
724
733
|
],
|
|
725
734
|
"rightkit-media": [
|
|
726
735
|
"0.2.2",
|
|
@@ -772,7 +781,8 @@
|
|
|
772
781
|
"0.7.0",
|
|
773
782
|
"0.7.1",
|
|
774
783
|
"0.8.0",
|
|
775
|
-
"0.9.0"
|
|
784
|
+
"0.9.0",
|
|
785
|
+
"0.9.1"
|
|
776
786
|
],
|
|
777
787
|
"rightkit-sandbox": [
|
|
778
788
|
"0.1.0",
|
|
@@ -833,7 +843,8 @@
|
|
|
833
843
|
"0.3.0",
|
|
834
844
|
"0.3.5",
|
|
835
845
|
"0.3.6",
|
|
836
|
-
"0.3.7"
|
|
846
|
+
"0.3.7",
|
|
847
|
+
"0.3.8"
|
|
837
848
|
],
|
|
838
849
|
"rightkit-fs": [
|
|
839
850
|
"0.1.0",
|
|
@@ -869,7 +880,8 @@
|
|
|
869
880
|
"rightkit-pdf": [
|
|
870
881
|
"0.1.0",
|
|
871
882
|
"0.3.0",
|
|
872
|
-
"0.3.2"
|
|
883
|
+
"0.3.2",
|
|
884
|
+
"0.3.3"
|
|
873
885
|
],
|
|
874
886
|
"rightkit-speech-client": [
|
|
875
887
|
"0.3.0",
|
|
@@ -898,7 +910,8 @@
|
|
|
898
910
|
"0.2.0",
|
|
899
911
|
"0.2.1",
|
|
900
912
|
"0.3.0",
|
|
901
|
-
"0.4.1"
|
|
913
|
+
"0.4.1",
|
|
914
|
+
"0.5.0"
|
|
902
915
|
],
|
|
903
916
|
"rightkit-asr": [
|
|
904
917
|
"0.0.2",
|
|
@@ -912,7 +925,8 @@
|
|
|
912
925
|
"0.2.2",
|
|
913
926
|
"0.3.0",
|
|
914
927
|
"0.3.2",
|
|
915
|
-
"0.3.3"
|
|
928
|
+
"0.3.3",
|
|
929
|
+
"0.3.5"
|
|
916
930
|
],
|
|
917
931
|
"rightkit-ocr": [
|
|
918
932
|
"0.1.2",
|
|
@@ -998,13 +1012,15 @@
|
|
|
998
1012
|
"0.1.1"
|
|
999
1013
|
],
|
|
1000
1014
|
"rightkit-channel-memory": [
|
|
1001
|
-
"0.1.0"
|
|
1015
|
+
"0.1.0",
|
|
1016
|
+
"0.2.1"
|
|
1002
1017
|
],
|
|
1003
1018
|
"rightkit-compose": [
|
|
1004
1019
|
"0.1.0"
|
|
1005
1020
|
],
|
|
1006
1021
|
"rightkit-contracts": [
|
|
1007
|
-
"0.1.5"
|
|
1022
|
+
"0.1.5",
|
|
1023
|
+
"0.1.7"
|
|
1008
1024
|
],
|
|
1009
1025
|
"rightkit-hooks": [
|
|
1010
1026
|
"0.1.0",
|
|
@@ -1068,7 +1084,8 @@
|
|
|
1068
1084
|
],
|
|
1069
1085
|
"rightkit-docs": [
|
|
1070
1086
|
"0.1.0",
|
|
1071
|
-
"0.1.1"
|
|
1087
|
+
"0.1.1",
|
|
1088
|
+
"0.1.2"
|
|
1072
1089
|
],
|
|
1073
1090
|
"rightkit-tts-qwen": [
|
|
1074
1091
|
"0.2.6"
|
|
@@ -1078,10 +1095,12 @@
|
|
|
1078
1095
|
"0.2.2"
|
|
1079
1096
|
],
|
|
1080
1097
|
"rightkit-send": [
|
|
1081
|
-
"0.1.0"
|
|
1098
|
+
"0.1.0",
|
|
1099
|
+
"0.2.0"
|
|
1082
1100
|
],
|
|
1083
1101
|
"rightkit-file-watch": [
|
|
1084
|
-
"0.4.0"
|
|
1102
|
+
"0.4.0",
|
|
1103
|
+
"0.4.1"
|
|
1085
1104
|
],
|
|
1086
1105
|
"rightkit-sync": [
|
|
1087
1106
|
"0.1.1"
|
|
@@ -1092,7 +1111,8 @@
|
|
|
1092
1111
|
"0.3.3",
|
|
1093
1112
|
"0.4.0",
|
|
1094
1113
|
"0.5.0",
|
|
1095
|
-
"0.5.1"
|
|
1114
|
+
"0.5.1",
|
|
1115
|
+
"0.6.0"
|
|
1096
1116
|
],
|
|
1097
1117
|
"rightkit-android": [
|
|
1098
1118
|
"0.2.0"
|
package/runtime-budgets.mjs
CHANGED
|
@@ -251,10 +251,13 @@ const posix = (p) => p.split(path.sep).join("/");
|
|
|
251
251
|
* The git pathspecs (relative to the workspace root) whose change makes a measurement stale: the
|
|
252
252
|
* crate's src, benches, Cargo.toml (features) and build.rs, plus src, Cargo.toml and build.rs of every
|
|
253
253
|
* workspace crate it reaches through `path` dependencies (transitively). Returns { root, specs, problems }.
|
|
254
|
+
* Every crate is its own Cargo workspace (rightkit#1285), so `root` is the crate directory (its own Cargo.toml and Cargo.lock)
|
|
255
|
+
* and a sibling crate's paths are `../<x>/...`. `deps.base` names the directory the specs are relative to (default: the
|
|
256
|
+
* workspace root); a caller that runs git at the repository root passes it so the specs read crates/<x>/....
|
|
254
257
|
* Callers must refuse incomplete metadata rather than using a partial dependency scope.
|
|
255
258
|
*/
|
|
256
259
|
export function measuredPathspecs(crateDir, deps = {}) {
|
|
257
|
-
const { exists = existsSync, readFile = readFileSync } = deps;
|
|
260
|
+
const { exists = existsSync, readFile = readFileSync, base } = deps;
|
|
258
261
|
const problems = [];
|
|
259
262
|
// Workspace discovery deliberately tolerates bad ancestor manifests elsewhere. Freshness cannot:
|
|
260
263
|
// a swallowed read/parse failure could hide inherited dependencies and shrink the measured graph.
|
|
@@ -271,7 +274,7 @@ export function measuredPathspecs(crateDir, deps = {}) {
|
|
|
271
274
|
const checked = { exists, readFile: checkedRead };
|
|
272
275
|
let root = path.resolve(crateDir);
|
|
273
276
|
const specs = [];
|
|
274
|
-
const add = (dir, names) => { for (const name of names) specs.push(posix(path.relative(root, path.join(dir, name)))); };
|
|
277
|
+
const add = (dir, names) => { for (const name of names) specs.push(posix(path.relative(base ? path.resolve(base) : root, path.join(dir, name)))); };
|
|
275
278
|
try {
|
|
276
279
|
root = findWorkspaceRoot(crateDir, checked) ?? root;
|
|
277
280
|
add(path.resolve(crateDir), CRATE_PATHS);
|
|
@@ -365,6 +368,7 @@ export function measurementStaleness(commit, crateDir, git = defaultGit, deps =
|
|
|
365
368
|
}
|
|
366
369
|
} catch (error) { return `cannot resolve Cargo.lock package identity: ${error.message}`; }
|
|
367
370
|
if (name) {
|
|
371
|
+
// The crate's own workspace lock: root is the crate directory when the crate is its own workspace (#1285).
|
|
368
372
|
const lockPath = path.join(root, "Cargo.lock");
|
|
369
373
|
let now;
|
|
370
374
|
try { now = exists(lockPath) ? readFile(lockPath, "utf8") : null; }
|
package/scan-digest.mjs
CHANGED
|
@@ -54,6 +54,60 @@ export function rustCratePlan(own = {}) {
|
|
|
54
54
|
return { lintSets, defaultCheck, checkSets };
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// ---- Clippy batching (GATE-CONTRACT §1 "Clippy route & batching"; item 8 rows 8.6, 8.8, 8.15) -----------------------------------------
|
|
58
|
+
// Lives here, beside the scan ids, so the credentialed verifiers (requiredScanIds) and the planner (planScans) spell a batch's id from
|
|
59
|
+
// one function. Pure: no file reads.
|
|
60
|
+
|
|
61
|
+
/** The feature flags that mean the same thing on every package they are applied to: any other set names features of one crate. */
|
|
62
|
+
export const CLIPPY_UNIVERSAL_FEATURE_FLAGS = Object.freeze(["--all-features", "--no-default-features"]);
|
|
63
|
+
const optionValue = (set, names) => {
|
|
64
|
+
for (let i = 0; i < set.length; i += 1) for (const n of names) { if (set[i] === n) return set[i + 1] ?? null; if (set[i].startsWith(`${n}=`)) return set[i].slice(n.length + 1); }
|
|
65
|
+
return null;
|
|
66
|
+
};
|
|
67
|
+
/** The target and profile a feature-set argv selects (null: the toolchain's host target and the dev profile). */
|
|
68
|
+
export const clippySelectionOf = (set) => ({ target: optionValue(set, ["--target"]), profile: set.includes("--release") || set.includes("-r") ? "release" : optionValue(set, ["--profile"]) });
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Groups the Clippy configurations of a plan into invocations. `entries`: `[{ name, crate, ws, set, count, env }]`, one per crate
|
|
72
|
+
* and lint feature set (`count` is how many sets the crate declares). Entries are batched when workspace, feature set, target,
|
|
73
|
+
* profile, lint policy, toolchain and environment are all equal (they share one `-p` list); an entry is its own invocation, with
|
|
74
|
+
* the reason recorded, when:
|
|
75
|
+
* - its crate is in `solo` (ci/shards.json `solo`: a crate that always gets a job of its own);
|
|
76
|
+
* - it is in `separate` (a name to a reason): batching changed what compiles for it (feature unification, item 8 row 8.7);
|
|
77
|
+
* - its feature set names crate-specific features (anything but --all-features / --no-default-features): such a set is
|
|
78
|
+
* per-configuration by construction, for example rightkit-db's SQLCipher variants or rightkit-qa-driver's wv2 generations
|
|
79
|
+
* (ci/gate.config.json featureSets);
|
|
80
|
+
* - its crate is sidecar-bound: it is scheduled after every independent batch and never joins one.
|
|
81
|
+
* A batch never widens a package set: it names exactly its members with `-p`. A batch's id is `clippy:batch:[<ws>:]<8 hex>` over its
|
|
82
|
+
* workspace, feature set, target, profile, lint policy and member list (never the toolchain or the output directory, which a
|
|
83
|
+
* verifier does not know), so the planner and requiredScanIds agree and the id names exactly the crates it covers. Returns
|
|
84
|
+
* `{ batches, notes }`; batches are ordered independent first, then sidecar-bound, each group by workspace then key.
|
|
85
|
+
*/
|
|
86
|
+
export function clippyBatchPlan(entries, { solo = [], separate = new Map(), sidecarBound = new Set(), toolchain = null, lint = ["-D", "warnings"] } = {}) {
|
|
87
|
+
const soloSet = new Set(solo);
|
|
88
|
+
const groups = new Map();
|
|
89
|
+
for (const e of entries) {
|
|
90
|
+
const set = [...e.set];
|
|
91
|
+
const crate = e.crate ?? e.name;
|
|
92
|
+
const sel = clippySelectionOf(set);
|
|
93
|
+
let reason = null;
|
|
94
|
+
if (soloSet.has(e.name) || soloSet.has(crate)) reason = "ci/shards.json solo: the crate always gets an invocation of its own";
|
|
95
|
+
else if (separate instanceof Map && separate.has(e.name)) reason = separate.get(e.name);
|
|
96
|
+
else if (set.some((w) => !CLIPPY_UNIVERSAL_FEATURE_FLAGS.includes(w))) reason = `ci/gate.config.json featureSets names crate-specific features (${set.join(" ")})${e.count > 1 ? `; ${crate} declares ${e.count} feature configurations that are separate invocations by construction` : ""}`;
|
|
97
|
+
const bound = sidecarBound.has(e.name) || sidecarBound.has(crate);
|
|
98
|
+
const identity = { ws: e.ws, set, target: sel.target, profile: sel.profile, lint, ...(reason || bound ? { only: e.name, sidecar: bound } : {}) };
|
|
99
|
+
const key = canonicalJson({ ...identity, toolchain, env: e.env ?? null });
|
|
100
|
+
if (!groups.has(key)) groups.set(key, { key, identity: canonicalJson(identity), ws: e.ws, set, target: sel.target, profile: sel.profile, units: [], crates: [], reason: reason ?? (bound ? "sidecar-bound: scheduled after its sidecar prerequisite, never batched with independent crates" : null), order: bound ? "sidecar" : "independent" });
|
|
101
|
+
const g = groups.get(key);
|
|
102
|
+
g.units.push(e.name); if (!g.crates.includes(crate)) g.crates.push(crate);
|
|
103
|
+
}
|
|
104
|
+
const batches = [...groups.values()].map((g) => ({ ...g, units: g.units.sort(), crates: g.crates.sort() })).map((g) => ({ ...g, id: `clippy:batch:${g.ws === "." ? "" : `${g.ws}:`}${sha256(`${g.identity}\0${g.units.join("\0")}`).slice(0, 8)}` }));
|
|
105
|
+
batches.sort((a, b) => (a.order === b.order ? (a.ws === b.ws ? (a.key < b.key ? -1 : 1) : a.ws < b.ws ? -1 : 1) : a.order === "independent" ? -1 : 1));
|
|
106
|
+
const notes = batches.filter((b) => b.reason).map((b) => `clippy batching: ${b.units.join(", ")} (${b.set.join(" ") || "default features"}) stays its own invocation: ${b.reason}`);
|
|
107
|
+
notes.push(`clippy batching: ${entries.length} crate configuration(s) in ${batches.length} invocation(s), each \`-p\` list exactly its members, \`--locked\` and \`--no-deps\` on every one; no batch is \`--workspace\``);
|
|
108
|
+
return { batches, notes };
|
|
109
|
+
}
|
|
110
|
+
|
|
57
111
|
/** Scan ids every scan of the whole repository always has when it holds Rust units (cargo.toml, workflows, YAML, JSON and licences). */
|
|
58
112
|
export const WORKSPACE_SCAN_IDS = Object.freeze(["cargo-metadata", "cargo-deny", "cargo-audit", "actionlint", "yaml-parse", "toml-parse", "json-parse", "license", "secret-scan"]);
|
|
59
113
|
/** Prefixes at least one scan id must carry (rustfmt groups by edition, so its exact ids depend on the files). */
|
|
@@ -62,25 +116,35 @@ export const REQUIRED_SCAN_PREFIXES = Object.freeze(["rustfmt:"]);
|
|
|
62
116
|
/**
|
|
63
117
|
* The scan ids a LOCAL scan record must contain, each with status pass, for these publishable Rust `units` ([names], crates/<name>).
|
|
64
118
|
* `exists(repoPath)` answers from the AUTHENTICATED source (never from the record): src/lib.rs decides `doc`, CHANGELOG.md decides
|
|
65
|
-
* `changelog-version`, and the repository's own ci/advisory-exceptions.json, ownership catalog and docs generator decide theirs.
|
|
119
|
+
* `changelog-version`, and the repository's own ci/advisory-exceptions.json (or, per crate, crates/<name>/.rightkit/advisory-exceptions.json), ownership catalog and docs generator decide theirs.
|
|
66
120
|
* `crateFeatures` is ci/gate.config.json `rust`. `includeTests` adds the per-feature-set test scans. Extra scans in a record are
|
|
67
121
|
* allowed; a missing one is not. planScans builds its ids from the same helpers, and a test holds the two in agreement.
|
|
68
122
|
*/
|
|
69
|
-
export function requiredScanIds({ units, crateFeatures = {}, exists, includeTests = false }) {
|
|
123
|
+
export function requiredScanIds({ units, crateFeatures = {}, exists, includeTests = false, perCrateWorkspaces = undefined, clippyBatching = false, shardSolo = [], clippySeparate = new Map(), sidecarBound = new Set() }) {
|
|
70
124
|
if (!Array.isArray(units) || units.length === 0 || !units.every((n) => typeof n === "string" && n)) throw new TypeError("requiredScanIds: units must be a non-empty array of names");
|
|
71
125
|
if (typeof exists !== "function") throw new TypeError("requiredScanIds: exists(repoPath) is required");
|
|
72
|
-
|
|
73
|
-
|
|
126
|
+
// One Cargo workspace and lock per crate (rightkit#1285): every unit has its own crates/<name>/Cargo.lock, so the per-workspace scans
|
|
127
|
+
// (metadata, deny, audit and the advisory ledger where the crate has one) are required per unit and carry the crate name; there is no
|
|
128
|
+
// repository-level ledger. A repository with one root workspace has no per-crate lock and keeps the unsuffixed ids.
|
|
129
|
+
const perCrate = perCrateWorkspaces ?? units.every((n) => exists(`crates/${n}/Cargo.lock`));
|
|
130
|
+
const ids = new Set(WORKSPACE_SCAN_IDS.filter((id) => !(perCrate && /^cargo-(metadata|deny|audit)$/.test(id))));
|
|
131
|
+
if (!perCrate && exists("ci/advisory-exceptions.json")) ids.add("advisory-exceptions");
|
|
74
132
|
if (exists("packages/release/rightkit-ownership.json") && exists("crates/rightkit-ownership/catalog/ownership-catalog.json")) ids.add("ownership-catalog");
|
|
75
133
|
if (exists("scripts/generate-index.mjs")) ids.add("generated-docs");
|
|
134
|
+
const clippyEntries = [];
|
|
76
135
|
for (const name of units) {
|
|
77
136
|
const own = crateFeatures?.[name] ?? {};
|
|
78
137
|
const { lintSets, defaultCheck, checkSets } = rustCratePlan(own);
|
|
138
|
+
if (perCrate) {
|
|
139
|
+
for (const id of ["cargo-metadata", "cargo-deny", "cargo-audit"]) ids.add(`${id}:${name}`);
|
|
140
|
+
if (exists(`crates/${name}/.rightkit/advisory-exceptions.json`)) ids.add(`advisory-exceptions:${name}`);
|
|
141
|
+
}
|
|
79
142
|
ids.add(rustScanId.packageList(name));
|
|
80
143
|
if (exists(`crates/${name}/CHANGELOG.md`)) ids.add(rustScanId.changelog(name));
|
|
81
144
|
if (defaultCheck) ids.add(rustScanId.check(name));
|
|
82
145
|
checkSets.forEach((_set, i) => ids.add(rustScanId.checkFeatures(name, i)));
|
|
83
|
-
lintSets.forEach((
|
|
146
|
+
if (clippyBatching) lintSets.forEach((set) => clippyEntries.push({ name, crate: name, ws: ".", set, count: lintSets.length, env: null }));
|
|
147
|
+
else lintSets.forEach((_set, i) => ids.add(rustScanId.clippy(name, lintSets.length, i)));
|
|
84
148
|
if (exists(`crates/${name}/src/lib.rs`)) ids.add(rustScanId.doc(name));
|
|
85
149
|
if (includeTests) {
|
|
86
150
|
lintSets.forEach((_set, i) => {
|
|
@@ -89,6 +153,8 @@ export function requiredScanIds({ units, crateFeatures = {}, exists, includeTest
|
|
|
89
153
|
});
|
|
90
154
|
}
|
|
91
155
|
}
|
|
156
|
+
// With batching on, the Clippy ids are the batches' (the same function the planner calls), never the per-crate ones.
|
|
157
|
+
if (clippyBatching) for (const b of clippyBatchPlan(clippyEntries, { solo: shardSolo, separate: clippySeparate, sidecarBound }).batches) ids.add(b.id);
|
|
92
158
|
return [...ids].sort();
|
|
93
159
|
}
|
|
94
160
|
|
package/sign-updater.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { refuseManagedEnvSecrets } from "./managed-host-secrets.mjs";
|
|
|
7
7
|
import { execWithUpdaterCredential } from "./protected-credentials.mjs";
|
|
8
8
|
import { resolvePnpmCli } from "./development.mjs";
|
|
9
9
|
import { UPDATER_KEY_ID_RE, updaterSignatureKeyId } from "./github-updater-release.mjs";
|
|
10
|
+
import { ArtifactPathError, loadSplitArtifactContext, resolveArtifactPath } from "./release-artifact-path.mjs";
|
|
10
11
|
|
|
11
12
|
export const UPDATER_SIGNING_SECRET = "updater-signing-key";
|
|
12
13
|
|
|
@@ -14,6 +15,8 @@ export function runSignUpdater(args, {
|
|
|
14
15
|
env = process.env, platform = process.platform, cwd = process.cwd(),
|
|
15
16
|
execCredential = execWithUpdaterCredential, resolvePnpm = resolvePnpmCli,
|
|
16
17
|
signMac = signMacUpdaterFiles, exists = existsSync, remove = rmSync, read = (file) => readFileSync(file, "utf8"), log = console.log,
|
|
18
|
+
// The artifact-path context of a door split (release-artifact-path.mjs, row 7.04c): `--file` is then the bound Cargo target's, never the checkout's.
|
|
19
|
+
artifactPaths = null,
|
|
17
20
|
} = {}) {
|
|
18
21
|
const files = [];
|
|
19
22
|
let dryRun = false;
|
|
@@ -21,7 +24,7 @@ export function runSignUpdater(args, {
|
|
|
21
24
|
for (let i = 0; i < args.length; i++) {
|
|
22
25
|
if (args[i] === "--file") {
|
|
23
26
|
if (!args[i + 1] || args[i + 1].startsWith("--")) throw new Error("--file requires an artifact path");
|
|
24
|
-
files.push(path.resolve(cwd, args[++i]));
|
|
27
|
+
files.push(artifactPaths?.mode === "split" ? resolveArtifactPath(args[++i], artifactPaths) : path.resolve(cwd, args[++i]));
|
|
25
28
|
} else if (args[i] === "--key-id") {
|
|
26
29
|
if (keyId !== undefined) throw new Error("--key-id may be given only once");
|
|
27
30
|
if (!UPDATER_KEY_ID_RE.test(args[i + 1] ?? "")) throw new Error("--key-id requires the 16 upper-case hex digits of the updater key id");
|
|
@@ -77,9 +80,9 @@ export function runSignUpdater(args, {
|
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
80
|
-
try { runSignUpdater(process.argv.slice(2)); }
|
|
83
|
+
try { runSignUpdater(process.argv.slice(2), { artifactPaths: await loadSplitArtifactContext({ cwd: process.cwd() }) }); }
|
|
81
84
|
catch (error) {
|
|
82
|
-
console.error(`sign-updater: ${error.code ? `[${error.code}] ` : ""}${error.message}`);
|
|
85
|
+
console.error(`sign-updater: ${error instanceof ArtifactPathError ? "" : error.code ? `[${error.code}] ` : ""}${error.message}`);
|
|
83
86
|
process.exitCode = error.exitCode ?? 1;
|
|
84
87
|
}
|
|
85
88
|
}
|