@kungfu-tech/buildchain 2.4.7-alpha.1 → 2.4.8-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "2.4.7-alpha.1",
3
+ "version": "2.4.8-alpha.0",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -18,6 +18,21 @@ function nonEmptyString(value, label) {
18
18
  return normalized;
19
19
  }
20
20
 
21
+ function normalizeTargetChannel(value) {
22
+ const normalized = optionalString(value).trim();
23
+ if (!normalized || normalized === "none") {
24
+ return "";
25
+ }
26
+ const refMatch = normalized.match(/^(alpha|release)\/v\d+\/v\d+\.\d+$/);
27
+ if (refMatch) {
28
+ return refMatch[1];
29
+ }
30
+ if (normalized === "publish-gate/major" || normalized === "major-gate") {
31
+ return "major";
32
+ }
33
+ return normalized;
34
+ }
35
+
21
36
  function stableJson(value) {
22
37
  if (Array.isArray(value)) {
23
38
  return `[${value.map(stableJson).join(",")}]`;
@@ -81,7 +96,10 @@ export function createReleaseCandidatePassport({
81
96
  } = {}) {
82
97
  const normalizedSummary = buildSummary && typeof buildSummary === "object" ? buildSummary : {};
83
98
  const sourceSha = sourceHeadSha || normalizedSummary.publishSource?.sha || normalizedSummary.git?.sha || "";
84
- const channel = targetChannel || normalizedSummary.publishSource?.channel || normalizedSummary.publishGate?.channel || "";
99
+ const channel = normalizeTargetChannel(targetChannel)
100
+ || normalizeTargetChannel(normalizedSummary.publishSource?.channel)
101
+ || normalizeTargetChannel(normalizedSummary.publishGate?.channel)
102
+ || normalizeTargetChannel(pullRequest.baseRef);
85
103
  const candidate = {
86
104
  schemaVersion: 1,
87
105
  contract: RELEASE_CANDIDATE_PASSPORT_CONTRACT,
@@ -158,7 +176,11 @@ export function validateReleaseCandidatePassport({
158
176
  check(passport.repository === repository, `repository mismatch: expected ${repository}, got ${passport.repository || "<empty>"}`);
159
177
  }
160
178
  if (targetChannel) {
161
- check(passport.target?.channel === targetChannel, `target channel mismatch: expected ${targetChannel}, got ${passport.target?.channel || "<empty>"}`);
179
+ const expectedChannel = normalizeTargetChannel(targetChannel);
180
+ const actualChannel = normalizeTargetChannel(passport.target?.channel);
181
+ if (actualChannel) {
182
+ check(actualChannel === expectedChannel, `target channel mismatch: expected ${expectedChannel}, got ${actualChannel}`);
183
+ }
162
184
  }
163
185
  if (version) {
164
186
  check(passport.target?.version === version, `version mismatch: expected ${version}, got ${passport.target?.version || "<empty>"}`);
@@ -90,18 +90,34 @@ export function selectMergedChannelPullRequest({ pullRequests = [], targetRef, r
90
90
  return candidates[0];
91
91
  }
92
92
 
93
- export function selectReleaseCandidateRun({ runs = [], pullRequest, workflowName = "Build Surface Fixture" }) {
93
+ export function selectReleaseCandidateRun({ runs = [], pullRequest, workflowName = "" }) {
94
94
  const prNumber = Number(pullRequest?.number || 0);
95
+ const prHeadSha = String(pullRequest?.head?.sha || pullRequest?.headRefOid || "").trim();
96
+ const prHeadBranch = normalizeBranch(pullRequest?.head?.ref || pullRequest?.headRefName || "");
97
+ const prHeadRepository = pullRequest?.head?.repo?.full_name || pullRequest?.headRepository?.nameWithOwner || "";
95
98
  const candidates = runs.filter((run) => {
96
99
  const runPrs = Array.isArray(run.pull_requests) ? run.pull_requests : [];
97
- const matchesPr = runPrs.some((pr) => Number(pr.number || 0) === prNumber);
98
- const matchesWorkflow = !workflowName || run.name === workflowName || run.display_title === workflowName;
100
+ const runHeadBranch = normalizeBranch(run.head_branch || "");
101
+ const runHeadSha = String(run.head_sha || "").trim();
102
+ const runHeadRepository = run.head_repository?.full_name || run.headRepository?.nameWithOwner || "";
103
+ const matchesPrNumber = runPrs.some((pr) => Number(pr.number || 0) === prNumber);
104
+ const matchesHeadSha = prHeadSha && runHeadSha === prHeadSha;
105
+ const matchesHeadBranch = prHeadBranch
106
+ && runHeadBranch === prHeadBranch
107
+ && (!prHeadRepository || !runHeadRepository || runHeadRepository === prHeadRepository);
108
+ const matchesPr = matchesPrNumber || matchesHeadSha || matchesHeadBranch;
109
+ const matchesWorkflow = !workflowName || run.name === workflowName || run.workflow_name === workflowName;
99
110
  return matchesPr && matchesWorkflow && run.event === "pull_request" && run.status === "completed" && run.conclusion === "success";
100
111
  });
101
112
  candidates.sort((left, right) => Date.parse(right.updated_at || right.created_at || "") - Date.parse(left.updated_at || left.created_at || ""));
102
113
  return candidates[0];
103
114
  }
104
115
 
116
+ function outputPath(filePath) {
117
+ const relative = path.relative(process.cwd(), filePath).split(path.sep).join("/");
118
+ return relative.startsWith("../") || relative === ".." ? filePath : relative;
119
+ }
120
+
105
121
  export function selectReleaseCandidateArtifacts({ artifacts = [] }) {
106
122
  const active = artifacts.filter((artifact) => !artifact.expired);
107
123
  const passports = active.filter((artifact) => /-release-candidate-[0-9a-f]{40}$/i.test(artifact.name || ""));
@@ -256,8 +272,8 @@ export async function resolveReleaseCandidateArtifacts({
256
272
  return {
257
273
  ...result,
258
274
  paths: {
259
- passport: path.relative(process.cwd(), passportPath).split(path.sep).join("/"),
260
- buildSummary: path.relative(process.cwd(), buildSummaryPath).split(path.sep).join("/"),
275
+ passport: outputPath(passportPath),
276
+ buildSummary: outputPath(buildSummaryPath),
261
277
  },
262
278
  version: passport.target?.version || "",
263
279
  candidateHash: passport.candidateHash || "",
@@ -270,7 +286,7 @@ export async function resolveReleaseCandidateArtifactsCli() {
270
286
  targetRef: env("BUILDCHAIN_TARGET_REF"),
271
287
  targetSha: env("BUILDCHAIN_TARGET_SHA"),
272
288
  workflowFile: env("BUILDCHAIN_RC_WORKFLOW_FILE", DEFAULT_WORKFLOW_FILE),
273
- workflowName: env("BUILDCHAIN_RC_WORKFLOW_NAME", "Build Surface Fixture"),
289
+ workflowName: env("BUILDCHAIN_RC_WORKFLOW_NAME", ""),
274
290
  outputDir: env("BUILDCHAIN_RC_OUTPUT_DIR", ".buildchain/release-candidate"),
275
291
  });
276
292
  writeGitHubOutputs({