@kungfu-tech/buildchain 0.0.0-bootstrap.0 → 2.0.13-alpha.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.
Files changed (35) hide show
  1. package/README.md +262 -0
  2. package/bin/buildchain.mjs +222 -0
  3. package/docs/cli.md +124 -0
  4. package/docs/lifecycle-protocol.md +422 -0
  5. package/docs/publish-transaction.md +285 -0
  6. package/docs/reusable-build-surface.md +350 -0
  7. package/docs/web-surface-deployments.md +211 -0
  8. package/package.json +52 -1
  9. package/packages/core/README.md +15 -0
  10. package/packages/core/buildchain-config.js +721 -0
  11. package/packages/core/index.js +40 -0
  12. package/packages/core/package-manager.js +291 -0
  13. package/packages/core/publish-transaction.js +418 -0
  14. package/packages/core/release-line-dry-run.js +296 -0
  15. package/scripts/aggregate-build-summary.mjs +88 -0
  16. package/scripts/build-contract-core.mjs +731 -0
  17. package/scripts/check-inventory.mjs +325 -0
  18. package/scripts/init-repo.mjs +316 -0
  19. package/scripts/npm-publish-dry-run.mjs +176 -0
  20. package/scripts/npm-publish-transaction.mjs +268 -0
  21. package/scripts/publish-source-ref-resolver.mjs +113 -0
  22. package/scripts/release-line-dry-run.mjs +53 -0
  23. package/scripts/release-line-policy.mjs +141 -0
  24. package/scripts/release-transaction.mjs +212 -0
  25. package/scripts/resolve-build-contract.mjs +63 -0
  26. package/scripts/resolve-publish-gate.mjs +33 -0
  27. package/scripts/resolve-publish-source.mjs +99 -0
  28. package/scripts/run-lifecycle-core.mjs +162 -0
  29. package/scripts/run-lifecycle.mjs +40 -0
  30. package/scripts/strip-trailing-whitespace.mjs +14 -0
  31. package/scripts/tsup-action.config.mjs +19 -0
  32. package/scripts/verify-publish-source-lock.mjs +37 -0
  33. package/scripts/verify-release-pr.mjs +34 -0
  34. package/scripts/web-surface-core.mjs +382 -0
  35. package/scripts/web-surface.mjs +112 -0
@@ -0,0 +1,141 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export const MAJOR_GATE_REF = "publish-gate/major";
5
+ export const LEGACY_MAJOR_GATE_REF = "major-gate";
6
+ export const MAJOR_GATE_CHANNEL = "major";
7
+
8
+ export function normalizeRef(ref) {
9
+ return String(ref || "").replace(/^refs\/heads\//, "");
10
+ }
11
+
12
+ export function isMajorGateRef(ref) {
13
+ const normalizedRef = normalizeRef(ref);
14
+ return normalizedRef === MAJOR_GATE_REF || normalizedRef === LEGACY_MAJOR_GATE_REF;
15
+ }
16
+
17
+ export function parseVersionStateRef(ref) {
18
+ const normalizedRef = normalizeRef(ref);
19
+ if (/^buildchain\/version-state\/publish-gate-major\/[0-9a-f]{12,40}$/.test(normalizedRef)) {
20
+ return {
21
+ channel: MAJOR_GATE_CHANNEL,
22
+ normalizedRef: MAJOR_GATE_REF,
23
+ lineSuffix: "",
24
+ };
25
+ }
26
+
27
+ if (/^buildchain\/version-state\/major-gate\/[0-9a-f]{12,40}$/.test(normalizedRef)) {
28
+ return {
29
+ channel: MAJOR_GATE_CHANNEL,
30
+ normalizedRef: LEGACY_MAJOR_GATE_REF,
31
+ lineSuffix: "",
32
+ };
33
+ }
34
+
35
+ const match = normalizedRef.match(
36
+ /^buildchain\/version-state\/(alpha|release)-v(\d+)-v(\d+\.\d+)\/[0-9a-f]{12,40}$/,
37
+ );
38
+ if (!match) return undefined;
39
+ return {
40
+ channel: match[1],
41
+ major: Number(match[2]),
42
+ loose: Number(match[3]),
43
+ normalizedRef: `${match[1]}/v${match[2]}/v${match[3]}`,
44
+ lineSuffix: `/v${match[2]}/v${match[3]}`,
45
+ };
46
+ }
47
+
48
+ export function getChannel(ref) {
49
+ const versionStateTarget = parseVersionStateRef(ref);
50
+ if (versionStateTarget) return versionStateTarget.channel;
51
+ const normalizedRef = normalizeRef(ref);
52
+ if (isMajorGateRef(normalizedRef)) return MAJOR_GATE_CHANNEL;
53
+ return normalizedRef.split("/")[0];
54
+ }
55
+
56
+ export function getLineSuffix(ref, channel) {
57
+ const versionStateTarget = parseVersionStateRef(ref);
58
+ if (versionStateTarget) return versionStateTarget.lineSuffix;
59
+ if (isMajorGateRef(ref)) return "";
60
+ return normalizeRef(ref).replace(channel, "");
61
+ }
62
+
63
+ export function readCurrentVersion(cwd = process.cwd()) {
64
+ const packagePath = path.join(cwd, fs.existsSync(path.join(cwd, "lerna.json")) ? "lerna.json" : "package.json");
65
+ const config = JSON.parse(fs.readFileSync(packagePath, "utf8"));
66
+ return parseVersion(config.version);
67
+ }
68
+
69
+ export function parseVersion(value) {
70
+ const match = String(value || "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
71
+ if (!match) {
72
+ throw new Error(`Invalid version: ${value}`);
73
+ }
74
+ return {
75
+ version: match[0],
76
+ major: Number(match[1]),
77
+ minor: Number(match[2]),
78
+ patch: Number(match[3]),
79
+ prerelease: match[4] ? match[4].split(".") : [],
80
+ };
81
+ }
82
+
83
+ export function getBumpKeyword({ cwd = process.cwd(), headRef, baseRef, loose = false } = {}) {
84
+ const version = readCurrentVersion(cwd);
85
+ const looseVersionNumber = Number(`${version.major}.${version.minor}`);
86
+ const lastLooseVersionNumber = Number((looseVersionNumber - 0.1).toFixed(1));
87
+ const versionStateTarget = parseVersionStateRef(headRef);
88
+ const headChannel = getChannel(headRef);
89
+ const baseChannel = getChannel(baseRef);
90
+ const key = `${headChannel}->${baseChannel}`;
91
+ const keywords = {
92
+ "dev->alpha": "prerelease",
93
+ "alpha->release": "patch",
94
+ "release->major": "premajor",
95
+ "release->release": "preminor",
96
+ };
97
+
98
+ const lts = baseChannel === "release" && normalizeRef(baseRef).split("/").pop() === "lts";
99
+ const preminor = headChannel === "release" && lts;
100
+ const majorGate = headChannel === "release" && baseChannel === MAJOR_GATE_CHANNEL;
101
+
102
+ if (getLineSuffix(headRef, headChannel) !== getLineSuffix(baseRef, baseChannel) && !preminor && !majorGate) {
103
+ throw new Error(`Versions not match for head/base refs: ${headRef} -> ${baseRef}`);
104
+ }
105
+
106
+ if (versionStateTarget) {
107
+ if (versionStateTarget.channel !== baseChannel) {
108
+ throw new Error(`Versions not match for head/base refs: ${headRef} -> ${baseRef}`);
109
+ }
110
+ return baseChannel === "release" || baseChannel === MAJOR_GATE_CHANNEL ? "patch" : "prerelease";
111
+ }
112
+
113
+ const normalizedHeadRef = normalizeRef(headRef);
114
+ const headMatch = normalizedHeadRef.match(/(\w+)\/v(\d+)\/v(\d+\.\d)/);
115
+ const mismatchMsg = `The version of head ref ${headRef} does not match current ${version.version}`;
116
+
117
+ if (!headMatch) {
118
+ throw new Error(mismatchMsg);
119
+ }
120
+
121
+ const headMajor = Number(headMatch[2]);
122
+ const headLoose = Number(headMatch[3]);
123
+
124
+ if (headMajor !== version.major || headLoose > looseVersionNumber) {
125
+ throw new Error(mismatchMsg);
126
+ }
127
+
128
+ if (headLoose < lastLooseVersionNumber) {
129
+ throw new Error(mismatchMsg);
130
+ }
131
+
132
+ if (headLoose === lastLooseVersionNumber && !loose) {
133
+ throw new Error(mismatchMsg);
134
+ }
135
+
136
+ const keyword = keywords[key];
137
+ if (!keyword) {
138
+ throw new Error(`No rule to bump for head/base refs: ${headRef} -> ${baseRef}`);
139
+ }
140
+ return keyword;
141
+ }
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import {
5
+ createReleaseTransaction,
6
+ defaultPublishEvidencePath,
7
+ defaultReleaseStatePath,
8
+ planTransactionRecovery,
9
+ readPublishEvidence,
10
+ readReleaseTransaction,
11
+ transitionReleaseTransaction,
12
+ validatePublishEvidence,
13
+ writeReleaseTransaction,
14
+ } from "../packages/core/publish-transaction.js";
15
+
16
+ function usage() {
17
+ return `Usage:
18
+ buildchain release inspect --version <tag> [--state-path <path>] [--evidence-path <path>]
19
+ buildchain release recover --version <tag> [--state-path <path>] [--evidence-path <path>] [--override]
20
+ buildchain release finalize --version <tag> [--state-path <path>] [--evidence-path <path>]
21
+ buildchain release abort --version <tag> --superseded-by <tag> [--state-path <path>]
22
+
23
+ Required creation flags when no state file exists:
24
+ --repository <owner/repo> --source-sha <sha> --release-sha <sha> --target-ref <ref> --channel <channel>
25
+
26
+ Optional validation flags:
27
+ --release-material-sha <sha> --publish-tooling-sha <sha> --required-artifacts-json <json>
28
+ `;
29
+ }
30
+
31
+ function parseArgs(argv) {
32
+ const [command, ...rest] = argv;
33
+ if (!command || command === "-h" || command === "--help") {
34
+ return { command: "help" };
35
+ }
36
+ const options = { _: [] };
37
+ for (let index = 0; index < rest.length; index += 1) {
38
+ const value = rest[index];
39
+ if (!value.startsWith("--")) {
40
+ options._.push(value);
41
+ continue;
42
+ }
43
+ const key = value.slice(2);
44
+ if (key === "override") {
45
+ options.override = true;
46
+ continue;
47
+ }
48
+ const next = rest[index + 1];
49
+ if (next === undefined || next.startsWith("--")) {
50
+ throw new Error(`missing value for --${key}`);
51
+ }
52
+ options[key.replaceAll("-", "_")] = next;
53
+ index += 1;
54
+ }
55
+ return { command, options };
56
+ }
57
+
58
+ function requireOption(options, key) {
59
+ if (!options[key]) {
60
+ throw new Error(`--${key.replaceAll("_", "-")} is required`);
61
+ }
62
+ return options[key];
63
+ }
64
+
65
+ function statePath(options) {
66
+ return path.resolve(options.state_path || defaultReleaseStatePath(requireOption(options, "version")));
67
+ }
68
+
69
+ function evidencePath(options) {
70
+ return path.resolve(options.evidence_path || defaultPublishEvidencePath(requireOption(options, "version")));
71
+ }
72
+
73
+ function loadOrCreate(options) {
74
+ const filePath = statePath(options);
75
+ const existing = readReleaseTransaction(filePath);
76
+ if (existing) {
77
+ return { record: existing, filePath, created: false };
78
+ }
79
+ const record = createReleaseTransaction({
80
+ repository: requireOption(options, "repository"),
81
+ version: requireOption(options, "version"),
82
+ exactTag: options.exact_tag || options.version,
83
+ channel: requireOption(options, "channel"),
84
+ line: options.line || "",
85
+ sourceSha: requireOption(options, "source_sha"),
86
+ targetRef: requireOption(options, "target_ref"),
87
+ releaseSha: requireOption(options, "release_sha"),
88
+ releaseMaterialSha: options.release_material_sha || options.release_sha,
89
+ publishToolingSha: options.publish_tooling_sha || options.release_sha,
90
+ statePath: filePath,
91
+ evidencePath: evidencePath(options),
92
+ actor: process.env.GITHUB_ACTOR || process.env.USER || "",
93
+ runId: process.env.GITHUB_RUN_ID || "",
94
+ });
95
+ writeReleaseTransaction(filePath, record);
96
+ return { record, filePath, created: true };
97
+ }
98
+
99
+ function validateIfPossible(record, options) {
100
+ const evidence = readPublishEvidence(evidencePath(options));
101
+ if (!evidence) {
102
+ return { evidence: undefined, validation: undefined };
103
+ }
104
+ const requiredArtifacts = options.required_artifacts_json
105
+ ? JSON.parse(options.required_artifacts_json)
106
+ : [];
107
+ const validation = validatePublishEvidence({
108
+ evidence,
109
+ version: record.version,
110
+ channel: record.channel,
111
+ sourceSha: record.source_sha,
112
+ releaseSha: record.release_sha,
113
+ targetRef: record.target_ref,
114
+ releaseMaterialSha: record.release_material_sha,
115
+ publishToolingSha: options.publish_tooling_sha || record.publish_tooling_sha || "",
116
+ requiredArtifacts,
117
+ });
118
+ return { evidence, validation };
119
+ }
120
+
121
+ function printJson(value) {
122
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
123
+ }
124
+
125
+ async function main() {
126
+ const { command, options = {} } = parseArgs(process.argv.slice(2));
127
+ if (command === "help") {
128
+ process.stdout.write(usage());
129
+ return;
130
+ }
131
+ if (!["inspect", "recover", "finalize", "abort"].includes(command)) {
132
+ throw new Error(`unsupported release transaction command: ${command}`);
133
+ }
134
+ requireOption(options, "version");
135
+ const { record, filePath, created } = loadOrCreate(options);
136
+ const { evidence, validation } = validateIfPossible(record, options);
137
+
138
+ if (command === "inspect") {
139
+ printJson({
140
+ command,
141
+ statePath: filePath,
142
+ durableStateRef: record.state_ref || "",
143
+ durableBoundary: "remote durable refs and public Git ref finalization are owned by actions/promote-buildchain-ref",
144
+ created,
145
+ transaction: record,
146
+ evidence,
147
+ validation,
148
+ });
149
+ return;
150
+ }
151
+
152
+ if (command === "recover") {
153
+ const recovery = planTransactionRecovery({
154
+ transaction: record,
155
+ evidence,
156
+ validation,
157
+ explicitOverride: Boolean(options.override),
158
+ });
159
+ printJson({
160
+ command,
161
+ statePath: filePath,
162
+ durableStateRef: record.state_ref || "",
163
+ durableBoundary: "remote durable refs and public Git ref finalization are owned by actions/promote-buildchain-ref",
164
+ recovery,
165
+ transaction: record,
166
+ validation,
167
+ });
168
+ if (recovery.blocked) {
169
+ process.exitCode = 1;
170
+ }
171
+ return;
172
+ }
173
+
174
+ if (command === "finalize") {
175
+ if (!validation?.valid) {
176
+ throw new Error(`cannot finalize release transaction without valid evidence: ${(validation?.errors || ["missing evidence"]).join("; ")}`);
177
+ }
178
+ const next = transitionReleaseTransaction(
179
+ record.state === "published" ? transitionReleaseTransaction(record, "finalizing") : record,
180
+ "complete",
181
+ );
182
+ writeReleaseTransaction(filePath, next);
183
+ printJson({
184
+ command,
185
+ statePath: filePath,
186
+ durableStateRef: next.state_ref || "",
187
+ durableBoundary: "local transaction state finalized; public Git refs are finalized by actions/promote-buildchain-ref",
188
+ transaction: next,
189
+ validation,
190
+ });
191
+ return;
192
+ }
193
+
194
+ const supersededBy = requireOption(options, "superseded_by");
195
+ const next = transitionReleaseTransaction(record, "abandoned", {
196
+ supersededBy,
197
+ failure: `abandoned in favor of ${supersededBy}`,
198
+ });
199
+ writeReleaseTransaction(filePath, next);
200
+ printJson({
201
+ command,
202
+ statePath: filePath,
203
+ durableStateRef: next.state_ref || "",
204
+ durableBoundary: "local transaction state abandoned; remote durable state is written by actions/promote-buildchain-ref",
205
+ transaction: next,
206
+ });
207
+ }
208
+
209
+ main().catch((error) => {
210
+ console.error(error.message);
211
+ process.exitCode = 1;
212
+ });
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import {
4
+ resolveArtifactContract,
5
+ resolveRunnerMatrix,
6
+ writeGitHubOutputs,
7
+ } from "./build-contract-core.mjs";
8
+
9
+ function readArg(name, fallback = "") {
10
+ const index = process.argv.indexOf(`--${name}`);
11
+ if (index === -1) {
12
+ return fallback;
13
+ }
14
+ return process.argv[index + 1] || "";
15
+ }
16
+
17
+ export function resolveBuildContractCli() {
18
+ const mode = readArg("mode", process.env.BUILDCHAIN_CONTRACT_MODE || "artifact");
19
+ if (mode === "runners") {
20
+ const resolved = resolveRunnerMatrix({
21
+ runnerPreset: process.env.BUILDCHAIN_RUNNER_PRESET || "github-hosted",
22
+ platformsJson: process.env.BUILDCHAIN_PLATFORMS_JSON || "",
23
+ });
24
+ writeGitHubOutputs({
25
+ "runner-preset": resolved.runnerPreset,
26
+ "platforms-json": resolved.platformsJson,
27
+ "platform-count": String(resolved.platformCount),
28
+ "platform-source": resolved.source,
29
+ });
30
+ return resolved;
31
+ }
32
+ if (mode === "artifact") {
33
+ const resolved = resolveArtifactContract({
34
+ artifactName: process.env.BUILDCHAIN_ARTIFACT_NAME || "buildchain-artifact",
35
+ artifactNameTemplate:
36
+ process.env.BUILDCHAIN_ARTIFACT_NAME_TEMPLATE || "{artifact}-{platform}-{sha}",
37
+ platformId: process.env.BUILDCHAIN_PLATFORM_ID || "",
38
+ platformName: process.env.BUILDCHAIN_PLATFORM_NAME || "",
39
+ sha: process.env.BUILDCHAIN_SOURCE_SHA || process.env.GITHUB_SHA || "",
40
+ ref: process.env.GITHUB_REF || "",
41
+ runId: process.env.GITHUB_RUN_ID || "",
42
+ runAttempt: process.env.GITHUB_RUN_ATTEMPT || "",
43
+ });
44
+ writeGitHubOutputs({
45
+ "artifact-name": resolved.artifactName,
46
+ "artifact-base-name": resolved.artifactBaseName,
47
+ "artifact-name-template": resolved.artifactNameTemplate,
48
+ "platform-id": resolved.platform.id,
49
+ "platform-name": resolved.platform.name,
50
+ });
51
+ return resolved;
52
+ }
53
+ throw new Error(`unsupported build contract mode: ${mode}`);
54
+ }
55
+
56
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
57
+ try {
58
+ resolveBuildContractCli();
59
+ } catch (error) {
60
+ console.error(`::error::${String(error.message || error).replace(/\r?\n/g, "%0A")}`);
61
+ process.exitCode = 1;
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import { resolvePublishGate, writeGitHubOutputs } from "./build-contract-core.mjs";
4
+
5
+ function readEnv(name, fallback = "") {
6
+ return process.env[name] || fallback;
7
+ }
8
+
9
+ export function resolvePublishGateCli() {
10
+ const gate = resolvePublishGate({
11
+ trusted: readEnv("BUILDCHAIN_TRUSTED_EVENT", "true"),
12
+ publishChannel: readEnv("BUILDCHAIN_PUBLISH_CHANNEL", "none"),
13
+ eventName: readEnv("GITHUB_EVENT_NAME", ""),
14
+ ref: readEnv("GITHUB_REF", ""),
15
+ publishRefsJson: readEnv("BUILDCHAIN_PUBLISH_REFS_JSON", ""),
16
+ });
17
+ writeGitHubOutputs({
18
+ "trusted-event": String(gate.trusted),
19
+ "publish-channel": gate.publishChannel,
20
+ "publish-allowed": String(gate.publishAllowed),
21
+ "publish-reason": gate.publishReason,
22
+ });
23
+ return gate;
24
+ }
25
+
26
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
27
+ try {
28
+ resolvePublishGateCli();
29
+ } catch (error) {
30
+ console.error(`::error::${String(error.message || error).replace(/\r?\n/g, "%0A")}`);
31
+ process.exitCode = 1;
32
+ }
33
+ }
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import {
6
+ createResolvedReleaseManifest,
7
+ parsePublishSourceRef,
8
+ resolvePublishSourceLock,
9
+ writeGitHubOutputs,
10
+ } from "./build-contract-core.mjs";
11
+ import {
12
+ resolvePublishSourceRefSha,
13
+ sourceRefFromEnv,
14
+ } from "./publish-source-ref-resolver.mjs";
15
+
16
+ function readArg(args, name, fallback = "") {
17
+ const index = args.indexOf(`--${name}`);
18
+ if (index === -1) {
19
+ return fallback;
20
+ }
21
+ return args[index + 1] || "";
22
+ }
23
+
24
+ function readEnv(env, name, fallback = "") {
25
+ return env[name] || fallback;
26
+ }
27
+
28
+ export async function resolvePublishSourceCli({
29
+ args = process.argv.slice(2),
30
+ env = process.env,
31
+ fetchImpl = globalThis.fetch,
32
+ } = {}) {
33
+ const mode = readArg(args, "mode", readEnv(env, "BUILDCHAIN_PUBLISH_SOURCE_MODE", "lock"));
34
+ const sourceRef = sourceRefFromEnv(env);
35
+ const parsed = parsePublishSourceRef(sourceRef);
36
+ const repository = readEnv(env, "BUILDCHAIN_SOURCE_REPOSITORY", readEnv(env, "GITHUB_REPOSITORY"));
37
+ const sourceSha = readEnv(env, "BUILDCHAIN_PUBLISH_SOURCE_SHA")
38
+ || (parsed.enabled
39
+ ? await resolvePublishSourceRefSha({ repository, sourceRef: parsed.sourceRef, env, fetchImpl })
40
+ : readEnv(env, "GITHUB_SHA"));
41
+ const lock = resolvePublishSourceLock({
42
+ publishSourceRef: parsed.sourceRef,
43
+ publishSourceSha: sourceSha,
44
+ fallbackRef: readEnv(env, "GITHUB_REF_NAME", readEnv(env, "GITHUB_REF")),
45
+ fallbackSha: readEnv(env, "GITHUB_SHA"),
46
+ });
47
+
48
+ if (mode === "lock") {
49
+ writeGitHubOutputs({
50
+ "publish-source-ref": lock.sourceRef,
51
+ "publish-source-full-ref": lock.fullRef,
52
+ "publish-source-sha": lock.sourceSha,
53
+ "publish-source-locked": String(lock.sourceLocked),
54
+ "publish-source-channel": lock.channel,
55
+ "publish-source-line": lock.line,
56
+ "publish-source-consumer-version": lock.consumerVersion,
57
+ "publish-source-reason": lock.sourceReason,
58
+ });
59
+ return lock;
60
+ }
61
+ if (mode === "manifest") {
62
+ const cwd = path.resolve(readEnv(env, "BUILDCHAIN_SOURCE_CWD", "."));
63
+ const outputPath = path.resolve(
64
+ readEnv(env, "BUILDCHAIN_RELEASE_MANIFEST", ".buildchain/artifacts/publish-source-manifest.json"),
65
+ );
66
+ const manifest = await createResolvedReleaseManifest({
67
+ cwd,
68
+ repository,
69
+ sourceRef: lock.sourceLocked ? lock.sourceRef : "",
70
+ sourceSha: lock.sourceSha,
71
+ anchorRequestJson: readEnv(env, "BUILDCHAIN_PUBLISH_ANCHOR_REQUEST_JSON"),
72
+ publishRegistry: readEnv(env, "BUILDCHAIN_PUBLISH_REGISTRY", "https://registry.npmjs.org/"),
73
+ distTag: readEnv(env, "BUILDCHAIN_PUBLISH_DIST_TAG"),
74
+ });
75
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
76
+ fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
77
+ writeGitHubOutputs({
78
+ "publish-source-ref": lock.sourceRef,
79
+ "publish-source-sha": lock.sourceSha,
80
+ "publish-source-locked": String(lock.sourceLocked),
81
+ "publish-source-channel": lock.channel,
82
+ "publish-source-line": lock.line,
83
+ "publish-source-consumer-version": lock.consumerVersion,
84
+ "release-manifest-path": path.relative(process.cwd(), outputPath).split(path.sep).join("/"),
85
+ "release-manifest-json": JSON.stringify(manifest),
86
+ });
87
+ return manifest;
88
+ }
89
+ throw new Error(`unsupported publish source mode: ${mode}`);
90
+ }
91
+
92
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
93
+ try {
94
+ await resolvePublishSourceCli();
95
+ } catch (error) {
96
+ console.error(`::error::${String(error.message || error).replace(/\r?\n/g, "%0A")}`);
97
+ process.exitCode = 1;
98
+ }
99
+ }