@treeseed/sdk 0.12.17 → 0.12.19
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.
|
@@ -3308,12 +3308,20 @@ async function resolveRailwayTopologyForScope(input, scope, {
|
|
|
3308
3308
|
includeInstances = ensure,
|
|
3309
3309
|
includeVariables = false
|
|
3310
3310
|
} = {}) {
|
|
3311
|
+
const imageRefValues = resolveReconcileEnvironmentValues(input, scope);
|
|
3312
|
+
const imageRefFingerprint = [
|
|
3313
|
+
"TREESEED_API_IMAGE_REF",
|
|
3314
|
+
"TREESEED_OPERATIONS_RUNNER_IMAGE_REF",
|
|
3315
|
+
"TREESEED_AGENT_MANAGER_IMAGE_REF",
|
|
3316
|
+
"TREESEED_AGENT_RUNNER_IMAGE_REF",
|
|
3317
|
+
"TREESEED_PUBLIC_TREEDX_IMAGE_REF"
|
|
3318
|
+
].map((key) => `${key}=${imageRefValues[key] ?? ""}`).join("|");
|
|
3311
3319
|
const normalizedServiceKeys = Array.isArray(serviceKeys) && serviceKeys.length > 0 ? [...new Set(serviceKeys.map((value) => String(value).trim()).filter(Boolean))].sort() : ["__all__"];
|
|
3312
|
-
const cacheKey = `railway:topology:${scope}:${ensure ? "ensure" : "observe"}:${includeInstances ? "instances" : "no-instances"}:${includeVariables ? "variables" : "no-variables"}:${normalizedServiceKeys.join(",")}`;
|
|
3320
|
+
const cacheKey = `railway:topology:${scope}:${ensure ? "ensure" : "observe"}:${includeInstances ? "instances" : "no-instances"}:${includeVariables ? "variables" : "no-variables"}:${normalizedServiceKeys.join(",")}:${imageRefFingerprint}`;
|
|
3313
3321
|
return await providerCache(input, cacheKey, async () => {
|
|
3314
3322
|
const env = buildRailwayEnv(input, scope);
|
|
3315
3323
|
const deployState = loadDeployState(input.context.tenantRoot, input.context.deployConfig, { target: toDeployTarget(input.context.target) });
|
|
3316
|
-
const services =
|
|
3324
|
+
const services = configuredRailwayServicesForInput(input, scope).filter((service) => normalizedServiceKeys.includes("__all__") || normalizedServiceKeys.includes(service.key));
|
|
3317
3325
|
traceRailwayReconcile(env, "topology:start", `scope=${scope} ensure=${ensure ? "yes" : "no"} services=${services.map((service) => service.key).join(",")}`);
|
|
3318
3326
|
let workspace = null;
|
|
3319
3327
|
const knownProjects = [];
|
|
@@ -190,7 +190,7 @@ function deriveTreeseedDesiredUnits({
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
const scope = target.kind === "persistent" ? target.scope : "staging";
|
|
193
|
-
for (const configuredService of configuredRailwayServices(tenantRoot, scope)) {
|
|
193
|
+
for (const configuredService of configuredRailwayServices(tenantRoot, scope, env)) {
|
|
194
194
|
const serviceKey = configuredService.key;
|
|
195
195
|
const service = configuredService.serviceConfig ?? deployConfig.services?.[serviceKey];
|
|
196
196
|
const serviceState = legacyState.services?.[serviceKey];
|
|
@@ -217,6 +217,13 @@ function deriveTreeseedDesiredUnits({
|
|
|
217
217
|
serviceId: persistedServiceMatchesDesired ? serviceState?.serviceId ?? configuredService.serviceId : configuredService.serviceId,
|
|
218
218
|
serviceName: desiredServiceName,
|
|
219
219
|
rootDir: configuredService.rootDir ?? serviceState?.rootDir,
|
|
220
|
+
imageRef: configuredService.imageRef,
|
|
221
|
+
imageRefEnv: configuredService.serviceConfig?.railway?.imageRefEnv,
|
|
222
|
+
sourceMode: configuredService.sourceMode,
|
|
223
|
+
sourceRepo: configuredService.sourceRepo,
|
|
224
|
+
sourceBranch: configuredService.sourceBranch,
|
|
225
|
+
sourceCommit: configuredService.sourceCommit,
|
|
226
|
+
sourceRootDirectory: configuredService.sourceRootDirectory,
|
|
220
227
|
environment: normalizeRailwayEnvironmentName(configuredService.railwayEnvironment ?? serviceState?.environment),
|
|
221
228
|
buildCommand: configuredService.buildCommand,
|
|
222
229
|
startCommand: configuredService.startCommand,
|
|
@@ -12,7 +12,7 @@ import type { TreeseedCloseInput, TreeseedCiInput, TreeseedConfigInput, Treeseed
|
|
|
12
12
|
type WorkflowWrite = NonNullable<TreeseedWorkflowContext['write']>;
|
|
13
13
|
type WorkflowStatePayload = ReturnType<typeof resolveTreeseedWorkflowState>;
|
|
14
14
|
type ReleaseCandidateMode = TreeseedReleaseCandidateMode;
|
|
15
|
-
export type TreeseedWorkflowErrorCode = 'validation_failed' | 'merge_conflict' | 'missing_runtime_auth' | 'deployment_timeout' | 'confirmation_required' | 'unsupported_transport' | 'unsupported_state' | 'workflow_locked' | 'resume_unavailable' | 'workflow_contract_missing' | 'github_workflow_failed' | 'github_auth_unavailable' | 'hosted_reconcile_failed' | 'hosted_live_verification_failed';
|
|
15
|
+
export type TreeseedWorkflowErrorCode = 'validation_failed' | 'merge_conflict' | 'missing_runtime_auth' | 'deployment_timeout' | 'confirmation_required' | 'unsupported_transport' | 'unsupported_state' | 'workflow_locked' | 'resume_unavailable' | 'workflow_contract_missing' | 'github_workflow_failed' | 'github_auth_unavailable' | 'release_gate_failed' | 'hosted_reconcile_failed' | 'hosted_live_verification_failed';
|
|
16
16
|
export declare class TreeseedWorkflowError extends Error {
|
|
17
17
|
code: TreeseedWorkflowErrorCode;
|
|
18
18
|
operation: TreeseedWorkflowOperationId;
|
|
@@ -91,7 +91,7 @@ export declare function workflowReleaseCandidate(helpers: WorkflowOperationHelpe
|
|
|
91
91
|
}>>;
|
|
92
92
|
type PublishedArtifactCheck = {
|
|
93
93
|
id: string;
|
|
94
|
-
kind: 'npm' | 'docker' | 'pypi' | 'crates' | 'hex';
|
|
94
|
+
kind: 'npm' | 'docker' | 'pypi' | 'crates' | 'hex' | 'github-tag';
|
|
95
95
|
name: string;
|
|
96
96
|
version: string;
|
|
97
97
|
url: string;
|
|
@@ -1153,6 +1153,20 @@ export declare function workflowRelease(helpers: WorkflowOperationHelpers, input
|
|
|
1153
1153
|
liveVerification: import("../workflow-support.js").TreeseedLiveHostedServiceCheckReport;
|
|
1154
1154
|
reason?: undefined;
|
|
1155
1155
|
};
|
|
1156
|
+
productionApiGuarantees: {
|
|
1157
|
+
ok: true;
|
|
1158
|
+
environment: string;
|
|
1159
|
+
runId: string;
|
|
1160
|
+
outputRoot: string;
|
|
1161
|
+
counts: {
|
|
1162
|
+
planned: number;
|
|
1163
|
+
passed: number;
|
|
1164
|
+
failed: number;
|
|
1165
|
+
skipped: number;
|
|
1166
|
+
blocked: number;
|
|
1167
|
+
releaseBlockingFailures: number;
|
|
1168
|
+
};
|
|
1169
|
+
};
|
|
1156
1170
|
backMerge: {
|
|
1157
1171
|
packages: {
|
|
1158
1172
|
status: string;
|
|
@@ -159,6 +159,7 @@ import {
|
|
|
159
159
|
} from "./session.js";
|
|
160
160
|
import { checkedOutManagedWorkflowRepos } from "../operations/services/managed-repositories.js";
|
|
161
161
|
import { runTreeseedLocalCleanup } from "../operations/services/local-cleanup.js";
|
|
162
|
+
import { runTreeseedGuarantees } from "../guarantees/index.js";
|
|
162
163
|
import {
|
|
163
164
|
classifyTreeseedBranchRole,
|
|
164
165
|
resolveTreeseedWorkflowPaths
|
|
@@ -633,6 +634,49 @@ function productionReleaseImageRefEnv(selectedVersions) {
|
|
|
633
634
|
}
|
|
634
635
|
return refs;
|
|
635
636
|
}
|
|
637
|
+
async function runReleaseApiGuarantees(root, environment, helpers, operation, sceneArtifacts) {
|
|
638
|
+
const env = {
|
|
639
|
+
...helpers.context.env,
|
|
640
|
+
...collectTreeseedConfigSeedValues(root, environment, helpers.context.env)
|
|
641
|
+
};
|
|
642
|
+
env.TREESEED_ACCEPTANCE_SERVICE_ID ??= env.TREESEED_API_WEB_SERVICE_ID ?? env.TREESEED_WEB_SERVICE_ID;
|
|
643
|
+
env.TREESEED_ACCEPTANCE_SERVICE_SECRET ??= env.TREESEED_API_WEB_SERVICE_SECRET ?? env.TREESEED_WEB_SERVICE_SECRET;
|
|
644
|
+
if (!env.TREESEED_ACCEPTANCE_SERVICE_ID || !env.TREESEED_ACCEPTANCE_SERVICE_SECRET) {
|
|
645
|
+
workflowError(operation, "release_gate_failed", `${environment} API release guarantees cannot run because API acceptance service credentials are missing.`, {
|
|
646
|
+
details: {
|
|
647
|
+
environment,
|
|
648
|
+
missing: [
|
|
649
|
+
!env.TREESEED_ACCEPTANCE_SERVICE_ID ? "TREESEED_ACCEPTANCE_SERVICE_ID" : null,
|
|
650
|
+
!env.TREESEED_ACCEPTANCE_SERVICE_SECRET ? "TREESEED_ACCEPTANCE_SERVICE_SECRET" : null
|
|
651
|
+
].filter((value) => Boolean(value))
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
helpers.write(`[${operation}][workflow] Running ${environment} API release guarantees before root deployment.`);
|
|
656
|
+
return await withContextEnv(env, async () => {
|
|
657
|
+
const report = await runTreeseedGuarantees({
|
|
658
|
+
workspaceRoot: root,
|
|
659
|
+
filter: { ownerPackage: "@treeseed/api" },
|
|
660
|
+
environment,
|
|
661
|
+
evidenceTarget: "release",
|
|
662
|
+
sceneArtifacts
|
|
663
|
+
});
|
|
664
|
+
if (!report.ok) {
|
|
665
|
+
const diagnostics = report.diagnostics.filter((entry) => entry.severity === "error").slice(0, 20).map((entry) => `${entry.code}: ${entry.message}${entry.sourcePath ? ` (${entry.sourcePath})` : ""}`);
|
|
666
|
+
workflowError(operation, "release_gate_failed", `API release guarantees for ${environment} failed:
|
|
667
|
+
${diagnostics.join("\n") || `See ${report.outputRoot}`}`, {
|
|
668
|
+
details: { environment, outputRoot: report.outputRoot, counts: report.counts, diagnostics: report.diagnostics }
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
ok: report.ok,
|
|
673
|
+
environment: report.environment,
|
|
674
|
+
runId: report.runId,
|
|
675
|
+
outputRoot: report.outputRoot,
|
|
676
|
+
counts: report.counts
|
|
677
|
+
};
|
|
678
|
+
});
|
|
679
|
+
}
|
|
636
680
|
function recordHostedDeploymentStatesFromRootGates(root, rootRelease, workflowGates) {
|
|
637
681
|
const gates = Array.isArray(workflowGates) ? workflowGates.map((gate) => stringRecord(gate)).filter((gate) => Boolean(gate)) : [];
|
|
638
682
|
const releaseRecord = stringRecord(rootRelease) ?? {};
|
|
@@ -2532,6 +2576,46 @@ async function verifyNpmArtifact(packageName, version) {
|
|
|
2532
2576
|
};
|
|
2533
2577
|
}
|
|
2534
2578
|
}
|
|
2579
|
+
async function fetchDockerRegistryManifestStatus(image, version) {
|
|
2580
|
+
const [namespace, repository] = image.split("/");
|
|
2581
|
+
if (!namespace || !repository) {
|
|
2582
|
+
return { ok: false, status: null, message: `Invalid Docker image name ${image}.` };
|
|
2583
|
+
}
|
|
2584
|
+
const tokenUrl = `https://auth.docker.io/token?service=registry.docker.io&scope=repository:${namespace}/${repository}:pull`;
|
|
2585
|
+
try {
|
|
2586
|
+
const tokenResponse = await fetchJsonForArtifact(tokenUrl);
|
|
2587
|
+
const token = typeof stringRecord(tokenResponse.json)?.token === "string" ? String(stringRecord(tokenResponse.json)?.token) : "";
|
|
2588
|
+
if (!tokenResponse.ok || !token) {
|
|
2589
|
+
return { ok: false, status: tokenResponse.status, message: `Docker registry token request failed for ${image}.` };
|
|
2590
|
+
}
|
|
2591
|
+
const controller = new AbortController();
|
|
2592
|
+
const timeout = setTimeout(() => controller.abort(), 2e4);
|
|
2593
|
+
try {
|
|
2594
|
+
const manifestResponse = await fetch(`https://registry-1.docker.io/v2/${namespace}/${repository}/manifests/${version}`, {
|
|
2595
|
+
method: "HEAD",
|
|
2596
|
+
headers: {
|
|
2597
|
+
accept: [
|
|
2598
|
+
"application/vnd.docker.distribution.manifest.list.v2+json",
|
|
2599
|
+
"application/vnd.oci.image.index.v1+json",
|
|
2600
|
+
"application/vnd.docker.distribution.manifest.v2+json"
|
|
2601
|
+
].join(", "),
|
|
2602
|
+
authorization: `Bearer ${token}`,
|
|
2603
|
+
"user-agent": "treeseed-release-verifier/1.0 (https://treeseed.dev)"
|
|
2604
|
+
},
|
|
2605
|
+
signal: controller.signal
|
|
2606
|
+
});
|
|
2607
|
+
return {
|
|
2608
|
+
ok: manifestResponse.ok,
|
|
2609
|
+
status: manifestResponse.status,
|
|
2610
|
+
...manifestResponse.ok ? {} : { message: `Docker registry manifest for ${image}:${version} is not pullable yet.` }
|
|
2611
|
+
};
|
|
2612
|
+
} finally {
|
|
2613
|
+
clearTimeout(timeout);
|
|
2614
|
+
}
|
|
2615
|
+
} catch (error) {
|
|
2616
|
+
return { ok: false, status: null, message: error instanceof Error ? error.message : String(error) };
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2535
2619
|
async function verifyDockerHubArtifact(image, version) {
|
|
2536
2620
|
const [namespace, repository] = image.split("/");
|
|
2537
2621
|
const url = `https://hub.docker.com/v2/repositories/${namespace}/${repository}/tags/${version}`;
|
|
@@ -2539,7 +2623,8 @@ async function verifyDockerHubArtifact(image, version) {
|
|
|
2539
2623
|
const response = await fetchJsonForArtifact(url);
|
|
2540
2624
|
const images = Array.isArray(stringRecord(response.json)?.images) ? stringRecord(response.json)?.images : [];
|
|
2541
2625
|
const architectures = new Set(images.map((entry) => stringRecord(entry)).map((entry) => typeof entry?.architecture === "string" ? entry.architecture : null).filter((entry) => Boolean(entry)));
|
|
2542
|
-
const
|
|
2626
|
+
const registry = await fetchDockerRegistryManifestStatus(image, version);
|
|
2627
|
+
const ok = response.ok && architectures.has("amd64") && architectures.has("arm64") && registry.ok;
|
|
2543
2628
|
return {
|
|
2544
2629
|
id: `docker:${image}:${version}`,
|
|
2545
2630
|
kind: "docker",
|
|
@@ -2547,8 +2632,8 @@ async function verifyDockerHubArtifact(image, version) {
|
|
|
2547
2632
|
version,
|
|
2548
2633
|
url,
|
|
2549
2634
|
ok,
|
|
2550
|
-
status: response.status,
|
|
2551
|
-
...ok ? {} : { message: `${image}:${version} was not found on Docker Hub with amd64 and arm64 images.` }
|
|
2635
|
+
status: registry.status ?? response.status,
|
|
2636
|
+
...ok ? {} : { message: registry.message ?? `${image}:${version} was not found on Docker Hub with amd64 and arm64 images.` }
|
|
2552
2637
|
};
|
|
2553
2638
|
} catch (error) {
|
|
2554
2639
|
return {
|
|
@@ -2563,6 +2648,33 @@ async function verifyDockerHubArtifact(image, version) {
|
|
|
2563
2648
|
};
|
|
2564
2649
|
}
|
|
2565
2650
|
}
|
|
2651
|
+
async function verifyGitHubTagArtifact(repository, version) {
|
|
2652
|
+
const url = `https://api.github.com/repos/${repository}/git/ref/tags/${encodeURIComponent(version)}`;
|
|
2653
|
+
try {
|
|
2654
|
+
const response = await fetchJsonForArtifact(url);
|
|
2655
|
+
return {
|
|
2656
|
+
id: `github-tag:${repository}:${version}`,
|
|
2657
|
+
kind: "github-tag",
|
|
2658
|
+
name: repository,
|
|
2659
|
+
version,
|
|
2660
|
+
url,
|
|
2661
|
+
ok: response.ok,
|
|
2662
|
+
status: response.status,
|
|
2663
|
+
...response.ok ? {} : { message: `GitHub tag ${repository}@${version} was not found.` }
|
|
2664
|
+
};
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
return {
|
|
2667
|
+
id: `github-tag:${repository}:${version}`,
|
|
2668
|
+
kind: "github-tag",
|
|
2669
|
+
name: repository,
|
|
2670
|
+
version,
|
|
2671
|
+
url,
|
|
2672
|
+
ok: false,
|
|
2673
|
+
status: null,
|
|
2674
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2566
2678
|
async function verifySimpleRegistryArtifact(input) {
|
|
2567
2679
|
try {
|
|
2568
2680
|
const response = await fetchJsonForArtifact(input.url);
|
|
@@ -2591,6 +2703,21 @@ async function verifySimpleRegistryArtifact(input) {
|
|
|
2591
2703
|
}
|
|
2592
2704
|
async function collectPublishedReleaseArtifactChecks(selectedVersions) {
|
|
2593
2705
|
const checks = [];
|
|
2706
|
+
const githubRepositories = {
|
|
2707
|
+
"@treeseed/sdk": "treeseed-ai/sdk",
|
|
2708
|
+
"@treeseed/ui": "treeseed-ai/ui",
|
|
2709
|
+
"@treeseed/core": "treeseed-ai/core",
|
|
2710
|
+
"@treeseed/admin": "treeseed-ai/admin",
|
|
2711
|
+
"@treeseed/cli": "treeseed-ai/cli",
|
|
2712
|
+
"@treeseed/agent": "treeseed-ai/agent",
|
|
2713
|
+
"@treeseed/api": "treeseed-ai/api",
|
|
2714
|
+
treedx: "treeseed-ai/treedx",
|
|
2715
|
+
"@treeseed/treedx": "treeseed-ai/treedx"
|
|
2716
|
+
};
|
|
2717
|
+
for (const [packageName, repository] of Object.entries(githubRepositories)) {
|
|
2718
|
+
const version = selectedVersions.get(packageName);
|
|
2719
|
+
if (version) checks.push(await verifyGitHubTagArtifact(repository, version));
|
|
2720
|
+
}
|
|
2594
2721
|
const npmPackages = ["@treeseed/sdk", "@treeseed/ui", "@treeseed/core", "@treeseed/admin", "@treeseed/cli", "@treeseed/agent"];
|
|
2595
2722
|
for (const packageName of npmPackages) {
|
|
2596
2723
|
const version = selectedVersions.get(packageName);
|
|
@@ -5372,10 +5499,11 @@ ${blockers.join("\n")}`, {
|
|
|
5372
5499
|
resumable: true
|
|
5373
5500
|
};
|
|
5374
5501
|
}),
|
|
5502
|
+
{ id: "verify-published-artifacts", description: "Verify immutable registry artifacts exist after publish workflows", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5503
|
+
{ id: "production-hosting", description: "Reconcile and live-verify production hosted resources before root deploy", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5504
|
+
{ id: "production-api-guarantees", description: "Run production API release guarantees before root deploy", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5375
5505
|
{ id: "release-root", description: `Release market ${plannedRelease.rootVersion}`, repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
5376
5506
|
{ id: "publish-wait", description: "Wait for production release workflows", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5377
|
-
{ id: "verify-published-artifacts", description: "Verify immutable registry artifacts exist after publish workflows", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5378
|
-
{ id: "production-hosting", description: "Reconcile and live-verify production hosted resources after publish", repoName: rootRepo.name, repoPath: rootRepo.path, branch: PRODUCTION_BRANCH, resumable: true },
|
|
5379
5507
|
{ id: "release-back-merge", description: "Back-merge production release history into staging", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
5380
5508
|
{ id: "workspace-link", description: "Restore local workspace links after release", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true }
|
|
5381
5509
|
],
|
|
@@ -5482,6 +5610,9 @@ ${rendered}`);
|
|
|
5482
5610
|
});
|
|
5483
5611
|
packageReleases.push(packageRelease);
|
|
5484
5612
|
}
|
|
5613
|
+
const publishedArtifacts = await executeJournalStep(root, workflowRun.runId, "verify-published-artifacts", () => verifyPublishedReleaseArtifacts(selectedVersions));
|
|
5614
|
+
const productionHosting = await executeJournalStep(root, workflowRun.runId, "production-hosting", () => reconcileSaveHostedEnvironment(root, "prod", helpers, workflowRun.runId, "release", productionReleaseImageRefEnv(selectedVersions)));
|
|
5615
|
+
const productionApiGuarantees = await executeJournalStep(root, workflowRun.runId, "production-api-guarantees", () => runReleaseApiGuarantees(root, "prod", helpers, "release", normalizeSceneArtifactsMode(effectiveInput.sceneArtifacts)));
|
|
5485
5616
|
const rootRelease = await executeJournalStep(root, workflowRun.runId, "release-root", () => {
|
|
5486
5617
|
const rootInstall = runReleaseNpmInstall(root, { workspaceRoot: root });
|
|
5487
5618
|
const changelog = updateReleaseChangelog(repoRoot(root), {
|
|
@@ -5532,8 +5663,6 @@ ${rendered}`);
|
|
|
5532
5663
|
runId: workflowRun.runId,
|
|
5533
5664
|
onProgress: (line, stream) => helpers.write(line, stream)
|
|
5534
5665
|
}).then((workflowGates) => ({ workflowGates })));
|
|
5535
|
-
const publishedArtifacts = await executeJournalStep(root, workflowRun.runId, "verify-published-artifacts", () => verifyPublishedReleaseArtifacts(selectedVersions));
|
|
5536
|
-
const productionHosting = await executeJournalStep(root, workflowRun.runId, "production-hosting", () => reconcileSaveHostedEnvironment(root, "prod", helpers, workflowRun.runId, "release", productionReleaseImageRefEnv(selectedVersions)));
|
|
5537
5666
|
const backMerge = await executeJournalStep(root, workflowRun.runId, "release-back-merge", () => {
|
|
5538
5667
|
const packageBackMerges = checkedOutWorkspacePackageRepos(root).filter((pkg) => selectedPackageSet.has(pkg.name)).map((pkg) => backMergeProductionIntoStaging(pkg.dir, pkg.name, releaseAdminMessage({
|
|
5539
5668
|
subject: `release: back-merge ${PRODUCTION_BRANCH} into ${STAGING_BRANCH}`,
|
|
@@ -5561,6 +5690,7 @@ ${rendered}`);
|
|
|
5561
5690
|
publishWait: publishWait.workflowGates,
|
|
5562
5691
|
publishedArtifacts,
|
|
5563
5692
|
productionHosting,
|
|
5693
|
+
productionApiGuarantees,
|
|
5564
5694
|
backMerge,
|
|
5565
5695
|
workspaceLinks,
|
|
5566
5696
|
releasedCommit: String(rootRelease.commit.commitSha ?? ""),
|