@kungfu-tech/buildchain 4.0.1-alpha.8 → 4.0.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/README.md +9 -6
- package/actions/v4-release-candidate-promote/README.md +3 -0
- package/architecture/agent-change-map.md +1015 -0
- package/architecture/ci-lane-change-budget.json +70 -1
- package/architecture/decisions/0004-v4-declarative-release-tail.md +47 -0
- package/architecture/internal-capabilities.json +156 -11
- package/architecture/maintainability-debt.json +3229 -0
- package/architecture/maintainability-policy.json +480 -129
- package/architecture/v3-core-mechanism-inventory.json +4 -3
- package/architecture/v3-v4-capability-closure.md +59 -0
- package/architecture/v3-v4-live-capability-inventory.json +102404 -0
- package/architecture/v4-cross-platform-adopter-qualification.json +52 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.json +3 -3
- package/architecture/v4-runtime-semantic-closure.json +710 -0
- package/bin/internal/trust-release-release-handlers.mjs +5 -0
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-publication-qualification-v1.schema.json +51 -0
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +2 -0
- package/dist/site/buildchain-contract.json +123 -32
- package/dist/site/buildchain-site.json +96 -28
- package/dist/site/capability-registry.json +6 -6
- package/dist/site/cli-registry.json +5 -2
- package/dist/site/controller-registry.json +41 -5
- package/dist/site/kfd-claims.json +170 -21
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +6 -6
- package/dist/site/node-api-registry.json +1474 -215
- package/dist/site/page-registry.json +85 -17
- package/dist/site/public-surface-audit.json +85 -20
- package/dist/site/publication-authority-registry.json +28 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +5 -0
- package/dist/site/schemas/v4-publication-qualification-v1.schema.json +51 -0
- package/dist/site/site-manifest.json +10 -10
- package/dist/site/workflow-registry.json +94 -18
- package/docs/MAP.md +1 -1
- package/docs/cli-reference.md +4 -4
- package/docs/dev-delivery-warrant.md +12 -9
- package/docs/node-api-reference.md +291 -206
- package/docs/publish-transaction.md +11 -4
- package/docs/release-candidate.md +7 -0
- package/docs/v4-adopter-delivery.md +23 -4
- package/docs/v4-declarative-release-tail-migration.md +43 -0
- package/package.json +8 -3
- package/packages/core/adopter-delivery-passport.js +36 -0
- package/packages/core/buildchain-contract.js +31 -1
- package/packages/core/buildchain-publication-authority.js +1 -0
- package/packages/core/dev-delivery-warrant-settlement.js +239 -3
- package/packages/core/dev-delivery-warrant-state.js +15 -2
- package/packages/core/dev-delivery-warrant.js +21 -4
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/index.js +1 -0
- package/packages/core/paper-scaffold-content.js +401 -0
- package/packages/core/paper.js +12 -378
- package/packages/core/publication-control-plane-audit.js +135 -111
- package/packages/core/publication-rehearsal-projection.js +104 -0
- package/packages/core/publication-rehearsal-runtime.js +190 -0
- package/packages/core/release-candidate-recovery.js +6 -5
- package/packages/core/release-passport.js +82 -184
- package/packages/core/v4-cross-platform-adopter-qualification.js +343 -0
- package/packages/core/v4-floating-consumer-policy.js +3 -2
- package/packages/core/v4-floating-consumer-release-passport.js +134 -15
- package/packages/core/v4-publication-qualification.js +222 -0
- package/scripts/artifact-signing-controller-core.mjs +1 -1
- package/scripts/audit-publication-control-plane.mjs +17 -17
- package/scripts/buildchain-cli-help.mjs +3 -0
- package/scripts/check-internal-architecture.mjs +23 -3
- package/scripts/check-inventory.mjs +23 -5
- package/scripts/check-maintainability.mjs +145 -4
- package/scripts/check-project-cut-merge-queue-admission.mjs +87 -0
- package/scripts/check-v3-v4-capability-inventory.mjs +574 -0
- package/scripts/check-v4-floating-consumer-policy-contract.mjs +10 -3
- package/scripts/check-v4-runtime-semantic-closure.mjs +266 -0
- package/scripts/dev-delivery-warrant-options.mjs +27 -11
- package/scripts/dev-delivery-warrant.mjs +45 -5
- package/scripts/dev-pr-auto-merge.mjs +25 -11
- package/scripts/dev-pr-delivery-warrant.mjs +44 -0
- package/scripts/dev-pr-prequeue-guard.mjs +0 -18
- package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
- package/scripts/generate-agent-change-map.mjs +118 -0
- package/scripts/generate-release-candidate-passport.mjs +26 -1
- package/scripts/generate-site-bundle.mjs +6 -0
- package/scripts/maintainability-domain-metrics.mjs +237 -0
- package/scripts/maintainability-governance.mjs +473 -0
- package/scripts/maintainability-metrics.mjs +28 -6
- package/scripts/project-cut-merge-queue-admission.mjs +394 -0
- package/scripts/promotion-routing-evidence.mjs +35 -6
- package/scripts/release-candidate-resolver.mjs +44 -0
- package/scripts/release-line-policy.mjs +25 -15
- package/scripts/release-tail.mjs +19 -2
- package/scripts/resume-from-candidate-run.mjs +106 -103
- package/scripts/run-lifecycle-core.mjs +341 -376
- package/scripts/site-capability-metadata.mjs +4 -0
- package/scripts/stable-candidate-qualification.mjs +9 -10
- package/scripts/v3-v4-capability-catalog.mjs +439 -0
- package/scripts/v4-cross-platform-adopter-qualification.mjs +228 -0
- package/scripts/v4-declarative-promotion-admission.mjs +42 -0
|
@@ -4,9 +4,10 @@ import fs from "node:fs";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
|
-
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
8
|
|
|
9
9
|
import { writeGitHubOutputs } from "./build-contract-core.mjs";
|
|
10
|
+
import { compareSemver } from "./publication-registry-hydrate.mjs";
|
|
10
11
|
import { normalizeAnchorProvenance, normalizeCandidateRun, recoverCandidateProvenance } from "./release-candidate-anchor-provenance.mjs";
|
|
11
12
|
export { resolveAnchorRecoveryRequest } from "./release-candidate-anchor-provenance.mjs";
|
|
12
13
|
import {
|
|
@@ -40,10 +41,7 @@ import {
|
|
|
40
41
|
verifyV4RuntimeAuthorizationReceipt,
|
|
41
42
|
} from "../packages/core/v4-runtime-ref-resume-authority.js";
|
|
42
43
|
|
|
43
|
-
function env(name, fallback = "") {
|
|
44
|
-
return process.env[name] || fallback;
|
|
45
|
-
}
|
|
46
|
-
|
|
44
|
+
function env(name, fallback = "") { return process.env[name] || fallback; }
|
|
47
45
|
function requiredEnv(name) {
|
|
48
46
|
const value = env(name).trim();
|
|
49
47
|
if (!value) throw new Error(`${name} is required for candidate recovery`);
|
|
@@ -56,9 +54,7 @@ function splitRepository(repository) {
|
|
|
56
54
|
return { owner: match[1], repo: match[2], fullName: `${match[1]}/${match[2]}` };
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
function splitPatterns(value = "") {
|
|
60
|
-
return String(value || "").split(/\r?\n|,/).map((entry) => entry.trim()).filter(Boolean);
|
|
61
|
-
}
|
|
57
|
+
function splitPatterns(value = "") { return String(value || "").split(/\r?\n|,/).map((entry) => entry.trim()).filter(Boolean); }
|
|
62
58
|
|
|
63
59
|
function patternMatcher(pattern) {
|
|
64
60
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*");
|
|
@@ -111,15 +107,17 @@ function readOnlyJson(files, label) {
|
|
|
111
107
|
return JSON.parse(fs.readFileSync(files[0].absolutePath, "utf8"));
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
function trackedRuntimePersistenceScan(
|
|
110
|
+
export function trackedRuntimePersistenceScan({
|
|
111
|
+
runtimeRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."),
|
|
112
|
+
} = {}) {
|
|
115
113
|
const paths = execFileSync(
|
|
116
114
|
"git",
|
|
117
|
-
["ls-files", ".github/workflows", ".github/actions", ".buildchain"],
|
|
115
|
+
["-C", runtimeRoot, "ls-files", ".github/workflows", ".github/actions", ".buildchain"],
|
|
118
116
|
{ encoding: "utf8" },
|
|
119
117
|
)
|
|
120
118
|
.split(/\r?\n/)
|
|
121
119
|
.filter((entry) => /\.(?:json|toml|ya?ml)$/u.test(entry));
|
|
122
|
-
return scanV4RuntimeSelectorPersistence({ root:
|
|
120
|
+
return scanV4RuntimeSelectorPersistence({ root: runtimeRoot, paths });
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
export function verifyReleaseCandidateStageCapsules({ sidecar, passport, downloads }) {
|
|
@@ -201,23 +199,36 @@ export function verifyReleaseCandidateStageCapsules({ sidecar, passport, downloa
|
|
|
201
199
|
export function validateV4RuntimeResumePublicReadback({
|
|
202
200
|
targetRef,
|
|
203
201
|
targetSha,
|
|
202
|
+
targetVersion,
|
|
204
203
|
alphaSha,
|
|
205
204
|
exactTagSha,
|
|
206
205
|
tagLineage,
|
|
206
|
+
runtimeLineage,
|
|
207
|
+
floatingTargetLineage,
|
|
207
208
|
runtimeSha,
|
|
208
209
|
version,
|
|
209
210
|
transaction,
|
|
210
211
|
main,
|
|
211
212
|
npm,
|
|
212
213
|
}) {
|
|
214
|
+
const channelVersion = npm["dist-tags"]?.alpha;
|
|
215
|
+
let channelDidNotRegress = false;
|
|
216
|
+
try {
|
|
217
|
+
channelDidNotRegress = compareSemver(channelVersion, version) >= 0;
|
|
218
|
+
} catch { channelDidNotRegress = false; }
|
|
213
219
|
if (
|
|
214
220
|
transaction?.target_ref !== targetRef ||
|
|
215
221
|
transaction?.version !== version ||
|
|
216
222
|
exactTagSha !== transaction?.source_sha ||
|
|
217
223
|
!["ahead", "identical"].includes(tagLineage?.status) ||
|
|
218
|
-
|
|
224
|
+
!["ahead", "identical"].includes(runtimeLineage?.status) ||
|
|
225
|
+
!["ahead", "identical"].includes(floatingTargetLineage?.status) ||
|
|
226
|
+
!alphaSha ||
|
|
219
227
|
!targetSha ||
|
|
220
|
-
|
|
228
|
+
!runtimeSha ||
|
|
229
|
+
channelVersion !== targetVersion ||
|
|
230
|
+
!channelDidNotRegress ||
|
|
231
|
+
!npm.versions?.[channelVersion]?.dist?.integrity ||
|
|
221
232
|
npm.versions?.[version]?.dist?.integrity !== main.digest
|
|
222
233
|
) {
|
|
223
234
|
throw new Error(
|
|
@@ -236,21 +247,12 @@ export async function readPublicResumeState({
|
|
|
236
247
|
apiUrl,
|
|
237
248
|
fetchImpl,
|
|
238
249
|
}) {
|
|
239
|
-
const readRef = async (ref) =>
|
|
240
|
-
|
|
241
|
-
apiUrl,
|
|
242
|
-
token,
|
|
243
|
-
fetchImpl,
|
|
244
|
-
path: `/repos/${repoInfo.owner}/${repoInfo.repo}/git/ref/${ref}`,
|
|
245
|
-
})).object?.sha || "";
|
|
250
|
+
const readRef = async (ref) => (await githubJson({ apiUrl, token, fetchImpl,
|
|
251
|
+
path: `/repos/${repoInfo.owner}/${repoInfo.repo}/git/ref/${ref}` })).object?.sha || "";
|
|
246
252
|
const main = transaction?.artifacts?.find((entry) => entry.kind === "npm" && entry.required !== false);
|
|
247
|
-
if (!main || main.ref !== version || !main.digest)
|
|
248
|
-
throw new Error(
|
|
249
|
-
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
const packageUrl =
|
|
253
|
-
`https://registry.npmjs.org/${encodeURIComponent(main.name)}`;
|
|
253
|
+
if (!main || main.ref !== version || !main.digest)
|
|
254
|
+
throw new Error("cross-runtime recovery requires exact durable npm publication evidence");
|
|
255
|
+
const packageUrl = `https://registry.npmjs.org/${encodeURIComponent(main.name)}`;
|
|
254
256
|
const exactTag = transaction.exact_tag || `v${version}`;
|
|
255
257
|
const [targetSha, alphaSha, exactTagSha, npmResponse] = await Promise.all([
|
|
256
258
|
readRef(`heads/${targetRef}`),
|
|
@@ -262,24 +264,18 @@ export async function readPublicResumeState({
|
|
|
262
264
|
throw new Error(`npm public readback failed with HTTP ${npmResponse.status}`);
|
|
263
265
|
}
|
|
264
266
|
const npm = await npmResponse.json();
|
|
265
|
-
const tagLineage = await
|
|
266
|
-
apiUrl,
|
|
267
|
-
token,
|
|
268
|
-
fetchImpl,
|
|
269
|
-
path: `/repos/${repoInfo.owner}/${repoInfo.repo}/
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
exactTagSha,
|
|
276
|
-
|
|
277
|
-
runtimeSha,
|
|
278
|
-
version,
|
|
279
|
-
transaction,
|
|
280
|
-
main,
|
|
281
|
-
npm,
|
|
282
|
-
});
|
|
267
|
+
const [tagLineage, runtimeLineage, floatingTargetLineage, targetPackageFile] = await Promise.all([
|
|
268
|
+
githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${exactTagSha}...${targetSha}` }),
|
|
269
|
+
githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${runtimeSha}...${alphaSha}` }),
|
|
270
|
+
githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${alphaSha}...${targetSha}` }),
|
|
271
|
+
githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/contents/package.json?ref=${encodeURIComponent(targetSha)}` }),
|
|
272
|
+
]);
|
|
273
|
+
if (targetPackageFile?.type !== "file" || targetPackageFile.encoding !== "base64" || !targetPackageFile.content)
|
|
274
|
+
throw new Error("cross-runtime recovery requires protected target version state");
|
|
275
|
+
const targetVersion = JSON.parse(Buffer.from(String(targetPackageFile.content).replace(/\s/g, ""), "base64").toString("utf8")).version;
|
|
276
|
+
validateV4RuntimeResumePublicReadback({ targetRef, targetSha, targetVersion, alphaSha,
|
|
277
|
+
exactTagSha, tagLineage, runtimeLineage, floatingTargetLineage, runtimeSha,
|
|
278
|
+
version, transaction, main, npm });
|
|
283
279
|
const body = {
|
|
284
280
|
schemaVersion: 1,
|
|
285
281
|
contract: "kungfu-buildchain-v4-runtime-resume-public-readback/v1",
|
|
@@ -296,11 +292,16 @@ export async function readPublicResumeState({
|
|
|
296
292
|
version,
|
|
297
293
|
distTag: "alpha",
|
|
298
294
|
integrity: npm.versions[version].dist.integrity,
|
|
295
|
+
targetVersion, distTagVersion: npm["dist-tags"].alpha,
|
|
296
|
+
distTagIntegrity: npm.versions[npm["dist-tags"].alpha].dist.integrity,
|
|
299
297
|
},
|
|
300
298
|
};
|
|
301
299
|
return { ...body, root: v4RuntimeResumeDocumentRoot(body) };
|
|
302
300
|
}
|
|
303
301
|
|
|
302
|
+
export const resolveV4RuntimeResumePublicRuntimeSha = (material) =>
|
|
303
|
+
material?.buildAttempt?.runtimeSha || "";
|
|
304
|
+
|
|
304
305
|
function prepareRuntimeResumeEvidence({
|
|
305
306
|
repoInfo,
|
|
306
307
|
targetRef,
|
|
@@ -312,15 +313,13 @@ function prepareRuntimeResumeEvidence({
|
|
|
312
313
|
recovery,
|
|
313
314
|
outputDir,
|
|
314
315
|
}) {
|
|
315
|
-
const authorizationPath = path.resolve(
|
|
316
|
-
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
const delegated = readOnlyJson([{ absolutePath: authorizationPath }], "runtime authorization");
|
|
316
|
+
const authorizationPath = path.resolve(".buildchain/release-candidate/v4-runtime-authorization.json");
|
|
317
|
+
const delegatedRaw = env("BUILDCHAIN_RUNTIME_AUTHORIZATION_JSON").trim();
|
|
318
|
+
const delegatedRoot = env("BUILDCHAIN_RUNTIME_AUTHORIZATION_ROOT").trim();
|
|
319
|
+
const authorizationFileExists = fs.existsSync(authorizationPath);
|
|
320
|
+
if (!authorizationFileExists && (!delegatedRaw || !delegatedRoot)) throw new Error("cross-runtime recovery requires a fresh runtime authorization receipt");
|
|
321
|
+
const delegated = authorizationFileExists ? readOnlyJson([{ absolutePath: authorizationPath }], "runtime authorization") : JSON.parse(delegatedRaw);
|
|
322
|
+
if (!authorizationFileExists && delegated.receiptRoot !== delegatedRoot) throw new Error("fresh recovery runtime authorization handoff root mismatch");
|
|
324
323
|
const delegatedVerification = verifyV4RuntimeAuthorizationReceipt({
|
|
325
324
|
receipt: delegated.receipt,
|
|
326
325
|
receiptRoot: delegated.receiptRoot,
|
|
@@ -437,7 +436,7 @@ export async function finalizeRuntimeResumeEvidence({
|
|
|
437
436
|
const readback = await readPublicResumeState({
|
|
438
437
|
repoInfo,
|
|
439
438
|
targetRef,
|
|
440
|
-
runtimeSha: material
|
|
439
|
+
runtimeSha: resolveV4RuntimeResumePublicRuntimeSha(material),
|
|
441
440
|
version,
|
|
442
441
|
transaction,
|
|
443
442
|
token,
|
|
@@ -456,7 +455,7 @@ export async function finalizeRuntimeResumeEvidence({
|
|
|
456
455
|
resumePlanRoot: material.resumePlanRoot,
|
|
457
456
|
finalPublicReadbackRoot: readback.root,
|
|
458
457
|
floatingRefBefore: material.floatingRefBefore,
|
|
459
|
-
floatingRefAfter: { ref: "v4-alpha", sha:
|
|
458
|
+
floatingRefAfter: { ref: "v4-alpha", sha: readback.refs.floating.sha },
|
|
460
459
|
});
|
|
461
460
|
const evidence = {
|
|
462
461
|
authorization: material.authorization,
|
|
@@ -696,14 +695,26 @@ export function createRecoveredPublicationCandidate({
|
|
|
696
695
|
};
|
|
697
696
|
return { ...payload, candidateDigest: publicationArtifactCandidateDigest(payload) };
|
|
698
697
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
698
|
+
export function resolveRecoveredPublicationVersion({ artifactVersion, channel, rematerializeOnResume = false } = {}) {
|
|
699
|
+
const version = String(artifactVersion || "").trim(), match = version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u);
|
|
700
|
+
if (!match) throw new Error(`recovered npm artifact has invalid publication version: ${version || "<empty>"}`);
|
|
701
|
+
return channel === "release" && rematerializeOnResume ? match[1] : version;
|
|
702
|
+
}
|
|
703
|
+
export function resolveRecoveredCandidateVersion({ artifactVersion, publicationVersion, channel, rematerializeOnResume = false, targetRef = "", candidateRef = "" } = {}) {
|
|
704
|
+
const version = String(artifactVersion || "").trim(), target = String(targetRef || "").replace(/^refs\/heads\//u, ""), candidate = String(candidateRef || "").replace(/^refs\/heads\//u, "");
|
|
705
|
+
if (channel !== "release" || !rematerializeOnResume) return version;
|
|
706
|
+
const prefix = `publish-gate/${target}/`;
|
|
707
|
+
if (!target || !candidate.startsWith(prefix)) throw new Error(`stable recovery candidate ref must descend from ${prefix || "publish-gate/<target>/"}`);
|
|
708
|
+
const candidateVersion = candidate.slice(prefix.length);
|
|
709
|
+
if (!/^\d+\.\d+\.\d+-alpha\.\d+$/u.test(candidateVersion)) throw new Error(`stable recovery candidate ref must bind an exact alpha version, got ${candidateVersion || "<empty>"}`);
|
|
710
|
+
if (candidateVersion.replace(/-alpha\.\d+$/u, "") !== publicationVersion) throw new Error(`stable recovery candidate ${candidateVersion} does not match publication ${publicationVersion || "<empty>"}`);
|
|
711
|
+
if ((version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u)?.[1] || "") !== publicationVersion) throw new Error(`recovered npm artifact version ${version || "<empty>"} does not match publication ${publicationVersion}`);
|
|
712
|
+
return candidateVersion;
|
|
713
|
+
}
|
|
714
|
+
export function createRecoveredPublication({ downloads, bundleRoot, repository, passport, candidateRuntimeSha, publishArtifactKind, publishPackageMain, releasePatterns, platformManifests, channel, targetRef = "", candidateRef = "", rematerializeOnResume = false }) {
|
|
715
|
+
const allFiles = downloads.flatMap((download) => download.files.map((file) => ({ path: path.relative(bundleRoot, file.absolutePath).split(path.sep).join("/"),
|
|
716
|
+
size: file.size, sha256: file.sha256.replace(/^sha256:/, ""), absolutePath: file.absolutePath })))
|
|
717
|
+
.sort((left, right) => left.path.localeCompare(right.path));
|
|
707
718
|
const kind = String(publishArtifactKind || "npm");
|
|
708
719
|
const releaseMatchers = splitPatterns(releasePatterns).map(patternMatcher);
|
|
709
720
|
const releaseAssets = allFiles.filter((file) => releaseMatchers.some((matcher) => matcher.test(path.basename(file.path))));
|
|
@@ -711,12 +722,8 @@ export function createRecoveredPublication({ downloads, bundleRoot, repository,
|
|
|
711
722
|
createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
|
|
712
723
|
const version = String(passport.target?.version || "").trim();
|
|
713
724
|
if (!version) throw new Error("candidate recovery requires a passport publication version");
|
|
714
|
-
return {
|
|
715
|
-
|
|
716
|
-
npmArtifacts: [],
|
|
717
|
-
allFiles,
|
|
718
|
-
releaseAssets,
|
|
719
|
-
version,
|
|
725
|
+
return { manifest: undefined, npmArtifacts: [], allFiles, releaseAssets,
|
|
726
|
+
version, candidateVersion: version,
|
|
720
727
|
publishRequiredArtifacts: generatePublishRequiredArtifacts({ manifests: platformManifests, version, kind }),
|
|
721
728
|
};
|
|
722
729
|
}
|
|
@@ -728,12 +735,9 @@ export function createRecoveredPublication({ downloads, bundleRoot, repository,
|
|
|
728
735
|
const npmReleaseAssets = allFiles.filter((file) => releaseMatchers.length
|
|
729
736
|
? releaseMatchers.some((matcher) => matcher.test(path.basename(file.path)))
|
|
730
737
|
: file.path.toLowerCase().endsWith(".tgz"));
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
passport,
|
|
735
|
-
candidateRuntimeSha,
|
|
736
|
-
});
|
|
738
|
+
const publicationVersion = resolveRecoveredPublicationVersion({ artifactVersion: main.metadata.ref, channel, rematerializeOnResume });
|
|
739
|
+
const candidateVersion = resolveRecoveredCandidateVersion({ artifactVersion: main.metadata.ref, publicationVersion, channel, rematerializeOnResume, targetRef, candidateRef });
|
|
740
|
+
const candidate = createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
|
|
737
741
|
const manifest = createPublicationSealedBundle({
|
|
738
742
|
candidate,
|
|
739
743
|
packageName: main.metadata.name,
|
|
@@ -747,12 +751,12 @@ export function createRecoveredPublication({ downloads, bundleRoot, repository,
|
|
|
747
751
|
npmArtifacts,
|
|
748
752
|
allFiles,
|
|
749
753
|
releaseAssets: npmReleaseAssets,
|
|
750
|
-
version:
|
|
754
|
+
version: publicationVersion, candidateVersion,
|
|
751
755
|
publishRequiredArtifacts: generatePublishRequiredArtifacts({
|
|
752
756
|
kind: "npm",
|
|
753
757
|
tarballPaths: npmArtifacts.map((entry) => entry.file.absolutePath),
|
|
754
758
|
mainPackage: publishPackageMain,
|
|
755
|
-
}),
|
|
759
|
+
}).map((artifact) => rematerializeOnResume ? { ...artifact, ref: publicationVersion } : artifact),
|
|
756
760
|
};
|
|
757
761
|
}
|
|
758
762
|
|
|
@@ -810,7 +814,7 @@ async function resolveTargetAdvance({ observedTargetSha, targetSha, transactionI
|
|
|
810
814
|
return { status: comparison.status, mergeIsAncestor: ["ahead", "identical"].includes(comparison.status) };
|
|
811
815
|
}
|
|
812
816
|
|
|
813
|
-
async function resolveRecoveryTransaction({
|
|
817
|
+
export async function resolveRecoveryTransaction({
|
|
814
818
|
repoInfo,
|
|
815
819
|
apiUrl,
|
|
816
820
|
token,
|
|
@@ -818,22 +822,21 @@ async function resolveRecoveryTransaction({
|
|
|
818
822
|
transactionId,
|
|
819
823
|
publicationVersion,
|
|
820
824
|
}) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
836
|
-
return { version, transaction };
|
|
825
|
+
let transaction = publicationVersion
|
|
826
|
+
? await readExistingTransaction({
|
|
827
|
+
repoInfo,
|
|
828
|
+
apiUrl,
|
|
829
|
+
token,
|
|
830
|
+
fetchImpl,
|
|
831
|
+
version: publicationVersion,
|
|
832
|
+
})
|
|
833
|
+
: undefined;
|
|
834
|
+
if (transactionId && transaction?.id !== transactionId) {
|
|
835
|
+
transaction = transactionId
|
|
836
|
+
? await readExistingTransactionById({ repoInfo, apiUrl, token, fetchImpl, transactionId })
|
|
837
|
+
: undefined;
|
|
838
|
+
}
|
|
839
|
+
return { version: transaction?.version || publicationVersion, transaction };
|
|
837
840
|
}
|
|
838
841
|
|
|
839
842
|
function resolveRecoveredStageCapsules({
|
|
@@ -862,7 +865,7 @@ export async function resumeFromCandidateRun({
|
|
|
862
865
|
channel, targetRef, targetSha,
|
|
863
866
|
expectedSourceTree = "", expectedCandidateRoot = "",
|
|
864
867
|
candidateRuntimeSha, runtimeSha,
|
|
865
|
-
transactionId = "", artifactName = "", artifactPatterns = "", releasePatterns = "",
|
|
868
|
+
transactionId = "", artifactName = "", artifactPatterns = "", releasePatterns = "", rematerializeOnResume = false,
|
|
866
869
|
requiredArtifactCount = 0,
|
|
867
870
|
publishArtifactKind = "npm", publishPackageMain = "",
|
|
868
871
|
outputDir = ".buildchain/release-candidate-recovery",
|
|
@@ -905,7 +908,7 @@ export async function resumeFromCandidateRun({
|
|
|
905
908
|
publishArtifactKind,
|
|
906
909
|
publishPackageMain,
|
|
907
910
|
releasePatterns,
|
|
908
|
-
platformManifests: platformManifestEvidence.manifests,
|
|
911
|
+
platformManifests: platformManifestEvidence.manifests, channel, targetRef, candidateRef: pullRequest.head?.ref || "", rematerializeOnResume,
|
|
909
912
|
});
|
|
910
913
|
const stageCapsules = resolveRecoveredStageCapsules({
|
|
911
914
|
candidateRuntimeSha,
|
|
@@ -915,7 +918,7 @@ export async function resumeFromCandidateRun({
|
|
|
915
918
|
downloads,
|
|
916
919
|
});
|
|
917
920
|
const {
|
|
918
|
-
version:
|
|
921
|
+
version: publicationVersion,
|
|
919
922
|
transaction: existingTransaction,
|
|
920
923
|
} = await resolveRecoveryTransaction({
|
|
921
924
|
repoInfo,
|
|
@@ -973,7 +976,7 @@ export async function resumeFromCandidateRun({
|
|
|
973
976
|
platformManifestEvidence: platformManifestEvidence.evidence,
|
|
974
977
|
productPayloadManifests,
|
|
975
978
|
artifacts: downloads.map((download) => download.record),
|
|
976
|
-
publicationVersion
|
|
979
|
+
publicationVersion,
|
|
977
980
|
currentToolingSha: runtimeSha,
|
|
978
981
|
recoveryRunId,
|
|
979
982
|
});
|
|
@@ -989,7 +992,7 @@ export async function resumeFromCandidateRun({
|
|
|
989
992
|
repoInfo,
|
|
990
993
|
targetRef,
|
|
991
994
|
runtimeSha,
|
|
992
|
-
version:
|
|
995
|
+
version: publicationVersion,
|
|
993
996
|
passport,
|
|
994
997
|
sidecar: stageCapsuleSidecar,
|
|
995
998
|
stageCapsules,
|
|
@@ -1004,7 +1007,7 @@ export async function resumeFromCandidateRun({
|
|
|
1004
1007
|
repository: repoInfo.fullName,
|
|
1005
1008
|
run: { id: runId, url: run.html_url || "", name: run.name },
|
|
1006
1009
|
artifacts: { passport: selected.passport.name, summary: selected.summary.name, payloads: chosen.map((artifact) => artifact.name), sourceSha: selected.sourceSha },
|
|
1007
|
-
version: candidateVersion,
|
|
1010
|
+
version: publicationVersion, candidateVersion: publication.candidateVersion,
|
|
1008
1011
|
candidateRoot: recovery.receipt.recovered.candidateRoot,
|
|
1009
1012
|
artifactRoot: recovery.receipt.recovered.artifactRoot,
|
|
1010
1013
|
receipt: recovery.receipt,
|
|
@@ -1045,7 +1048,7 @@ export async function resumeFromCandidateRunCli() {
|
|
|
1045
1048
|
expectedCandidateRoot: env("BUILDCHAIN_RESUME_EXPECTED_CANDIDATE_ROOT"),
|
|
1046
1049
|
candidateRuntimeSha: requiredEnv("BUILDCHAIN_RESUME_EXPECTED_CANDIDATE_RUNTIME_SHA"),
|
|
1047
1050
|
runtimeSha: requiredEnv("BUILDCHAIN_RESUME_RUNTIME_SHA"),
|
|
1048
|
-
transactionId: env("BUILDCHAIN_RESUME_TRANSACTION_ID"),
|
|
1051
|
+
transactionId: env("BUILDCHAIN_RESUME_TRANSACTION_ID"), rematerializeOnResume: env("BUILDCHAIN_PUBLISH_REMATERIALIZE_ON_RESUME") === "true",
|
|
1049
1052
|
artifactName: env("BUILDCHAIN_ARTIFACT_NAME"),
|
|
1050
1053
|
artifactPatterns: env("BUILDCHAIN_ARTIFACT_PATTERNS"),
|
|
1051
1054
|
releasePatterns: env("BUILDCHAIN_GITHUB_RELEASE_PAYLOAD_PATTERNS"),
|
|
@@ -1059,7 +1062,7 @@ export async function resumeFromCandidateRunCli() {
|
|
|
1059
1062
|
"release-candidate-action": result.action,
|
|
1060
1063
|
"release-candidate-passport-path": result.paths.passport,
|
|
1061
1064
|
"release-candidate-build-summary-path": result.paths.buildSummary,
|
|
1062
|
-
"release-candidate-version": result.version,
|
|
1065
|
+
"release-candidate-version": result.candidateVersion, "release-candidate-publication-version": result.version,
|
|
1063
1066
|
"release-candidate-source-sha": result.artifacts.sourceSha,
|
|
1064
1067
|
"release-candidate-artifact": result.artifacts.passport,
|
|
1065
1068
|
"release-candidate-build-summary-artifact": result.artifacts.summary,
|