@treeseed/sdk 0.8.3 → 0.8.5
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/dist/capacity.d.ts +33 -0
- package/dist/fixture-support.d.ts +1 -1
- package/dist/fixture-support.js +5 -5
- package/dist/managed-dependencies.js +132 -10
- package/dist/operations/services/bootstrap-runner.js +7 -1
- package/dist/operations/services/config-runtime.js +13 -4
- package/dist/operations/services/github-actions-verification.d.ts +3 -0
- package/dist/operations/services/github-actions-verification.js +3 -0
- package/dist/operations/services/github-api.d.ts +4 -1
- package/dist/operations/services/github-api.js +26 -8
- package/dist/operations/services/github-automation.d.ts +14 -5
- package/dist/operations/services/github-automation.js +45 -11
- package/dist/operations/services/hub-provider-launch.js +9 -8
- package/dist/operations/services/project-platform.d.ts +93 -210
- package/dist/operations/services/project-platform.js +74 -34
- package/dist/operations/services/railway-deploy.d.ts +25 -2
- package/dist/operations/services/railway-deploy.js +312 -20
- package/dist/operations/services/repository-save-orchestrator.d.ts +8 -0
- package/dist/operations/services/repository-save-orchestrator.js +40 -3
- package/dist/operations/services/runtime-paths.d.ts +1 -0
- package/dist/operations/services/runtime-paths.js +3 -1
- package/dist/operations/services/runtime-tools.d.ts +1 -0
- package/dist/operations/services/runtime-tools.js +2 -0
- package/dist/operations/services/template-registry.js +3 -0
- package/dist/platform/contracts.d.ts +9 -0
- package/dist/platform/deploy-config.js +28 -0
- package/dist/platform/env.yaml +1 -745
- package/dist/platform/environment.js +69 -9
- package/dist/reconcile/builtin-adapters.js +7 -2
- package/dist/scripts/install-managed-dependencies.js +12 -0
- package/dist/scripts/tenant-workflow-action.js +11 -9
- package/dist/scripts/test-scaffold.js +3 -1
- package/dist/scripts/workflow-commands.test.js +10 -6
- package/dist/scripts/workspace-command-e2e.js +1 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +1 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +7 -6
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +6 -0
- package/dist/workflow/operations.d.ts +41 -8
- package/dist/workflow/operations.js +119 -24
- package/dist/workflow/runs.js +31 -0
- package/package.json +1 -1
- package/templates/github/deploy-processing.workflow.yml +120 -0
- package/templates/github/deploy-web.workflow.yml +116 -0
- package/templates/github/hosted-project.workflow.yml +4 -4
- package/templates/github/deploy.managed.workflow.yml +0 -208
- package/templates/github/deploy.workflow.yml +0 -746
|
@@ -209,7 +209,8 @@ function readPackageScript(root, packageDir, scriptName) {
|
|
|
209
209
|
function ensureWorkflowWorkspacePackageArtifacts(root, helpers) {
|
|
210
210
|
const packages = [
|
|
211
211
|
{ name: "@treeseed/sdk", dir: "packages/sdk", artifacts: ["dist/workflow-support.js", "dist/plugin-default.js", "dist/platform/env.yaml"] },
|
|
212
|
-
{ name: "@treeseed/
|
|
212
|
+
{ name: "@treeseed/agent", dir: "packages/agent", artifacts: ["dist/api/index.js", "dist/services/worker.js"] },
|
|
213
|
+
{ name: "@treeseed/core", dir: "packages/core", artifacts: ["dist/plugin-default.js"] },
|
|
213
214
|
{ name: "@treeseed/cli", dir: "packages/cli", artifacts: ["dist/cli/main.js"] }
|
|
214
215
|
];
|
|
215
216
|
for (const entry of packages) {
|
|
@@ -301,6 +302,10 @@ function normalizeCiMode(mode, operation) {
|
|
|
301
302
|
if (mode === "hosted" || mode === "off") return mode;
|
|
302
303
|
return operation === "save" ? "off" : "hosted";
|
|
303
304
|
}
|
|
305
|
+
function normalizeSaveCiMode(mode, branch) {
|
|
306
|
+
if (mode === "hosted" || mode === "off") return mode;
|
|
307
|
+
return branch === STAGING_BRANCH ? "hosted" : "off";
|
|
308
|
+
}
|
|
304
309
|
function normalizeSaveVerifyMode(mode) {
|
|
305
310
|
switch (mode) {
|
|
306
311
|
case "skip":
|
|
@@ -319,8 +324,8 @@ function normalizeSaveVerifyMode(mode) {
|
|
|
319
324
|
return "skip";
|
|
320
325
|
}
|
|
321
326
|
}
|
|
322
|
-
function shouldUseHostedSaveCi(input) {
|
|
323
|
-
return
|
|
327
|
+
function shouldUseHostedSaveCi(input, branch) {
|
|
328
|
+
return normalizeSaveCiMode(input.ciMode, branch) === "hosted" || input.verifyMode === "hosted" || input.verifyMode === "both" || input.verifyDeployedResources === true;
|
|
324
329
|
}
|
|
325
330
|
function worktreePayload(root, requestedMode) {
|
|
326
331
|
const metadata = managedWorkflowWorktreeMetadata(root);
|
|
@@ -425,11 +430,11 @@ async function waitForWorkflowGates(operation, gates, ciMode, options = {}) {
|
|
|
425
430
|
}
|
|
426
431
|
return results;
|
|
427
432
|
}
|
|
428
|
-
const
|
|
429
|
-
function
|
|
433
|
+
const HOSTED_DEPLOY_GATE_TIMEOUT_SECONDS = 45 * 60;
|
|
434
|
+
function hostedDeployGate(gate) {
|
|
430
435
|
return {
|
|
431
436
|
...gate,
|
|
432
|
-
timeoutSeconds: gate.timeoutSeconds ??
|
|
437
|
+
timeoutSeconds: gate.timeoutSeconds ?? HOSTED_DEPLOY_GATE_TIMEOUT_SECONDS
|
|
433
438
|
};
|
|
434
439
|
}
|
|
435
440
|
function recordHostedDeploymentStatesFromRootGates(root, rootRelease, workflowGates) {
|
|
@@ -441,7 +446,7 @@ function recordHostedDeploymentStatesFromRootGates(root, rootRelease, workflowGa
|
|
|
441
446
|
{ scope: "staging", branch: STAGING_BRANCH, commit: releaseRecord.stagingCommit },
|
|
442
447
|
{ scope: "prod", branch: releaseTag ?? PRODUCTION_BRANCH, commit: releaseRecord.releasedCommit }
|
|
443
448
|
]) {
|
|
444
|
-
const gate = gates.find((candidate) => candidate.workflow === "deploy.yml" && candidate.branch === target.branch && candidate.status === "completed" && candidate.conclusion === "success");
|
|
449
|
+
const gate = gates.find((candidate) => (candidate.workflow === "deploy-web.yml" || candidate.workflow === "deploy-processing.yml") && candidate.branch === target.branch && candidate.status === "completed" && candidate.conclusion === "success");
|
|
445
450
|
const timestamp = typeof gate?.updatedAt === "string" && gate.updatedAt.trim() ? gate.updatedAt : null;
|
|
446
451
|
if (!gate || !timestamp) {
|
|
447
452
|
continue;
|
|
@@ -478,7 +483,7 @@ function ensureTreeseedCommandReadiness(root) {
|
|
|
478
483
|
{ id: "sdk", path: resolve(root, "node_modules/@treeseed/sdk/package.json") },
|
|
479
484
|
{ id: "sdk-workflow-support", path: resolve(root, "node_modules/@treeseed/sdk/dist/workflow-support.js") },
|
|
480
485
|
{ id: "core", path: resolve(root, "node_modules/@treeseed/core/package.json") },
|
|
481
|
-
{ id: "
|
|
486
|
+
{ id: "agent-api", path: resolve(root, "node_modules/@treeseed/agent/dist/api/index.js") },
|
|
482
487
|
{ id: "cli", path: resolve(root, "node_modules/@treeseed/cli/package.json") },
|
|
483
488
|
{ id: "cli-entrypoint", path: resolve(root, "node_modules/@treeseed/cli/dist/cli/main.js") },
|
|
484
489
|
{ id: "trsd-bin", path: resolve(root, "node_modules/.bin/trsd") }
|
|
@@ -838,7 +843,7 @@ function defaultCiWorkflows(kind, branch) {
|
|
|
838
843
|
return ["verify.yml"];
|
|
839
844
|
}
|
|
840
845
|
if (branch === STAGING_BRANCH || branch === PRODUCTION_BRANCH) {
|
|
841
|
-
return ["deploy.yml"];
|
|
846
|
+
return ["deploy-web.yml", "deploy-processing.yml"];
|
|
842
847
|
}
|
|
843
848
|
return ["verify.yml"];
|
|
844
849
|
}
|
|
@@ -1147,8 +1152,41 @@ function nextPendingJournalStep(journal) {
|
|
|
1147
1152
|
}
|
|
1148
1153
|
function findAutoResumableSaveRun(root, branch) {
|
|
1149
1154
|
if (!branch) return null;
|
|
1155
|
+
if (branch === STAGING_BRANCH && (hasMeaningfulChanges(repoRoot(root)) || checkedOutWorkspacePackageRepos(root).some((repo) => hasMeaningfulChanges(repo.dir)))) {
|
|
1156
|
+
return null;
|
|
1157
|
+
}
|
|
1150
1158
|
return listInterruptedWorkflowRuns(root).find((journal) => journal.command === "save" && journal.resumable && journal.session.branchName === branch) ?? null;
|
|
1151
1159
|
}
|
|
1160
|
+
function gatesForSavedPackageReports(reports) {
|
|
1161
|
+
return reports.filter((repo) => repo.pushed && repo.commitSha && repo.branch).map((repo) => ({
|
|
1162
|
+
name: repo.name,
|
|
1163
|
+
repoPath: repo.path,
|
|
1164
|
+
workflow: "verify.yml",
|
|
1165
|
+
branch: String(repo.branch),
|
|
1166
|
+
headSha: String(repo.commitSha)
|
|
1167
|
+
}));
|
|
1168
|
+
}
|
|
1169
|
+
function gateForSavedRootReport(report, branch, scope) {
|
|
1170
|
+
if (!branch || scope === "local" || !report.pushed || !report.commitSha) {
|
|
1171
|
+
return [];
|
|
1172
|
+
}
|
|
1173
|
+
if (branch === STAGING_BRANCH) {
|
|
1174
|
+
return [hostedDeployGate({
|
|
1175
|
+
name: report.name,
|
|
1176
|
+
repoPath: report.path,
|
|
1177
|
+
workflow: "deploy.yml",
|
|
1178
|
+
branch,
|
|
1179
|
+
headSha: report.commitSha
|
|
1180
|
+
})];
|
|
1181
|
+
}
|
|
1182
|
+
return [{
|
|
1183
|
+
name: report.name,
|
|
1184
|
+
repoPath: report.path,
|
|
1185
|
+
workflow: "verify.yml",
|
|
1186
|
+
branch,
|
|
1187
|
+
headSha: report.commitSha
|
|
1188
|
+
}];
|
|
1189
|
+
}
|
|
1152
1190
|
function findAutoResumableTaskRun(root, command, branch) {
|
|
1153
1191
|
if (!branch) return null;
|
|
1154
1192
|
return listInterruptedWorkflowRuns(root).find((journal) => journal.command === command && journal.resumable && journal.session.branchName === branch) ?? null;
|
|
@@ -1476,7 +1514,7 @@ function validateStagingWorkflowContracts(root) {
|
|
|
1476
1514
|
return;
|
|
1477
1515
|
}
|
|
1478
1516
|
const missing = [];
|
|
1479
|
-
for (const fileName of ["verify.yml", "deploy.yml"]) {
|
|
1517
|
+
for (const fileName of ["verify.yml", "deploy-web.yml", "deploy-processing.yml"]) {
|
|
1480
1518
|
if (!existsSync(resolve(root, ".github", "workflows", fileName))) {
|
|
1481
1519
|
missing.push(fileName);
|
|
1482
1520
|
}
|
|
@@ -2863,7 +2901,7 @@ async function workflowSave(helpers, input) {
|
|
|
2863
2901
|
failure: planAutoResumeRun.failure
|
|
2864
2902
|
} : null,
|
|
2865
2903
|
workspaceLinks,
|
|
2866
|
-
ciMode:
|
|
2904
|
+
ciMode: normalizeSaveCiMode(effectiveInput.ciMode, branch),
|
|
2867
2905
|
verifyMode: effectiveInput.verifyMode ?? "fast",
|
|
2868
2906
|
...worktreePayload(root, effectiveInput.worktreeMode),
|
|
2869
2907
|
repositoryPlan,
|
|
@@ -2873,6 +2911,7 @@ async function workflowSave(helpers, input) {
|
|
|
2873
2911
|
{ id: "workspace-unlink", description: "Remove local workspace links before deployment install and lockfile updates" },
|
|
2874
2912
|
...repositoryPlan.plannedSteps,
|
|
2875
2913
|
{ id: "lockfile-validation", description: "Validate refreshed package-lock.json files before any save commit is pushed" },
|
|
2914
|
+
...shouldUseHostedSaveCi(effectiveInput, branch) ? [{ id: "hosted-ci", description: `Wait for hosted save workflows on ${branch}` }] : [],
|
|
2876
2915
|
...branch === STAGING_BRANCH ? [{ id: "release-candidate", description: "Run release-candidate readiness checks for the saved staging state" }] : [],
|
|
2877
2916
|
{ id: "workspace-link", description: "Restore local workspace links after save" },
|
|
2878
2917
|
...beforeState.branchRole === "feature" && (effectiveInput.preview === true || previewInitialized) ? [{ id: "preview", description: `Refresh preview deployment for ${branch}` }] : []
|
|
@@ -2909,7 +2948,7 @@ async function workflowSave(helpers, input) {
|
|
|
2909
2948
|
gitDependencyProtocol: effectiveInput.gitDependencyProtocol ?? "preserve-origin",
|
|
2910
2949
|
gitRemoteWriteMode: effectiveInput.gitRemoteWriteMode ?? "ssh-pushurl",
|
|
2911
2950
|
verifyMode: effectiveInput.verifyMode ?? (effectiveInput.verify === false ? "skip" : "fast"),
|
|
2912
|
-
ciMode: effectiveInput.ciMode ?? "auto",
|
|
2951
|
+
ciMode: effectiveInput.ciMode ?? (branch === STAGING_BRANCH ? "hosted" : "auto"),
|
|
2913
2952
|
worktreeMode: effectiveInput.worktreeMode ?? "auto",
|
|
2914
2953
|
commitMessageMode: effectiveInput.commitMessageMode ?? "auto",
|
|
2915
2954
|
workspaceLinks: effectiveInput.workspaceLinks ?? "auto",
|
|
@@ -2924,7 +2963,7 @@ async function workflowSave(helpers, input) {
|
|
|
2924
2963
|
branch,
|
|
2925
2964
|
resumable: true
|
|
2926
2965
|
},
|
|
2927
|
-
...shouldUseHostedSaveCi(effectiveInput) ? [{
|
|
2966
|
+
...shouldUseHostedSaveCi(effectiveInput, branch) ? [{
|
|
2928
2967
|
id: "hosted-ci",
|
|
2929
2968
|
description: `Wait for hosted save workflows on ${branch}`,
|
|
2930
2969
|
repoName: rootRepo.name,
|
|
@@ -2979,7 +3018,29 @@ async function workflowSave(helpers, input) {
|
|
|
2979
3018
|
verifyMode: normalizeSaveVerifyMode(effectiveInput.verify === false ? "skip" : effectiveInput.verifyMode),
|
|
2980
3019
|
commitMessageMode: effectiveInput.commitMessageMode ?? "auto",
|
|
2981
3020
|
workflowRunId: workflowRun.runId,
|
|
2982
|
-
onProgress: (line, stream) => helpers.write(line, stream)
|
|
3021
|
+
onProgress: (line, stream) => helpers.write(line, stream),
|
|
3022
|
+
onWaveSaved: branch === STAGING_BRANCH && shouldUseHostedSaveCi(effectiveInput, branch) ? async ({ nodes, reports, rootRepo: waveRootRepo }) => {
|
|
3023
|
+
const packageReportsForWave = reports.filter((repo, index) => nodes[index]?.kind === "package");
|
|
3024
|
+
const rootReportForWave = nodes.some((node) => node.kind === "project") ? waveRootRepo : null;
|
|
3025
|
+
const gates = [
|
|
3026
|
+
...gatesForSavedPackageReports(packageReportsForWave),
|
|
3027
|
+
...rootReportForWave ? gateForSavedRootReport(rootReportForWave, branch, scope) : []
|
|
3028
|
+
];
|
|
3029
|
+
if (gates.length === 0) {
|
|
3030
|
+
return [];
|
|
3031
|
+
}
|
|
3032
|
+
const packageNames = packageReportsForWave.map((repo) => repo.name).join(", ");
|
|
3033
|
+
if (packageNames) {
|
|
3034
|
+
helpers.write(`[save][workflow] Waiting for hosted package gates before saving dependents: ${packageNames}.`);
|
|
3035
|
+
} else if (rootReportForWave) {
|
|
3036
|
+
helpers.write("[save][workflow] Waiting for hosted market deploy gate.");
|
|
3037
|
+
}
|
|
3038
|
+
return waitForWorkflowGates("save", gates, "hosted", {
|
|
3039
|
+
root,
|
|
3040
|
+
runId: workflowRun.runId,
|
|
3041
|
+
onProgress: (line, stream) => helpers.write(line, stream)
|
|
3042
|
+
});
|
|
3043
|
+
} : void 0
|
|
2983
3044
|
});
|
|
2984
3045
|
} finally {
|
|
2985
3046
|
ensureWorkflowWorkspaceLinks(root, helpers, effectiveInput.workspaceLinks ?? "auto");
|
|
@@ -3004,23 +3065,26 @@ async function workflowSave(helpers, input) {
|
|
|
3004
3065
|
lockfileValidation: repo.lockfileValidation
|
|
3005
3066
|
}))
|
|
3006
3067
|
};
|
|
3007
|
-
const saveWorkflowGates = shouldUseHostedSaveCi(effectiveInput) ? await executeJournalStep(root, workflowRun.runId, "hosted-ci", () => {
|
|
3068
|
+
const saveWorkflowGates = shouldUseHostedSaveCi(effectiveInput, branch) ? await executeJournalStep(root, workflowRun.runId, "hosted-ci", () => {
|
|
3069
|
+
if (branch === STAGING_BRANCH) {
|
|
3070
|
+
return { workflowGates: saveResult?.workflowGates ?? [] };
|
|
3071
|
+
}
|
|
3008
3072
|
helpers.write("[save][workflow] Waiting for hosted save workflow gates.");
|
|
3009
3073
|
return waitForWorkflowGates("save", [
|
|
3010
|
-
...savedRootRepo.pushed && savedRootRepo.commitSha && branch ? [{
|
|
3074
|
+
...branch !== STAGING_BRANCH && savedRootRepo.pushed && savedRootRepo.commitSha && branch ? [{
|
|
3011
3075
|
name: savedRootRepo.name,
|
|
3012
3076
|
repoPath: savedRootRepo.path,
|
|
3013
3077
|
workflow: "verify.yml",
|
|
3014
3078
|
branch,
|
|
3015
3079
|
headSha: savedRootRepo.commitSha
|
|
3016
3080
|
}] : [],
|
|
3017
|
-
...effectiveInput.verifyDeployedResources === true && scope !== "local" && savedRootRepo.pushed && savedRootRepo.commitSha && branch ? [{
|
|
3081
|
+
...(branch === STAGING_BRANCH || effectiveInput.verifyDeployedResources === true) && scope !== "local" && savedRootRepo.pushed && savedRootRepo.commitSha && branch ? [hostedDeployGate({
|
|
3018
3082
|
name: savedRootRepo.name,
|
|
3019
3083
|
repoPath: savedRootRepo.path,
|
|
3020
3084
|
workflow: "deploy.yml",
|
|
3021
3085
|
branch,
|
|
3022
3086
|
headSha: savedRootRepo.commitSha
|
|
3023
|
-
}] : [],
|
|
3087
|
+
})] : [],
|
|
3024
3088
|
...savedPackageReports.filter((repo) => repo.pushed && repo.commitSha && repo.branch).map((repo) => ({
|
|
3025
3089
|
name: repo.name,
|
|
3026
3090
|
repoPath: repo.path,
|
|
@@ -3092,7 +3156,7 @@ async function workflowSave(helpers, input) {
|
|
|
3092
3156
|
workspaceLinks,
|
|
3093
3157
|
commandReadiness,
|
|
3094
3158
|
lockfileValidation,
|
|
3095
|
-
ciMode:
|
|
3159
|
+
ciMode: normalizeSaveCiMode(effectiveInput.ciMode, branch),
|
|
3096
3160
|
verifyMode: effectiveInput.verifyMode ?? "fast",
|
|
3097
3161
|
workflowGates: saveWorkflowGates?.workflowGates ?? [],
|
|
3098
3162
|
releaseCandidate,
|
|
@@ -3558,13 +3622,13 @@ async function workflowStage(helpers, input) {
|
|
|
3558
3622
|
});
|
|
3559
3623
|
}
|
|
3560
3624
|
const stageWorkflowGateResult = !waitForStaging ? (skipJournalStep(root, workflowRun.runId, "wait-staging", { status: "skipped", reason: "disabled" }), { status: "skipped", reason: "disabled" }) : await executeJournalStep(root, workflowRun.runId, "wait-staging", () => waitForWorkflowGates("stage", [
|
|
3561
|
-
{
|
|
3625
|
+
hostedDeployGate({
|
|
3562
3626
|
name: rootRepo.name,
|
|
3563
3627
|
repoPath: rootRepo.path,
|
|
3564
3628
|
workflow: "deploy.yml",
|
|
3565
3629
|
branch: STAGING_BRANCH,
|
|
3566
3630
|
headSha: rootRepo.commitSha
|
|
3567
|
-
},
|
|
3631
|
+
}),
|
|
3568
3632
|
...packageReports.filter((report) => report.merged && report.commitSha).map((report) => ({
|
|
3569
3633
|
name: report.name,
|
|
3570
3634
|
repoPath: report.path,
|
|
@@ -3791,6 +3855,7 @@ async function workflowRelease(helpers, input) {
|
|
|
3791
3855
|
},
|
|
3792
3856
|
[
|
|
3793
3857
|
{ id: "release-plan", description: "Record release plan", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
3858
|
+
{ id: "release-staging-gates", description: "Verify current staging GitHub Actions gates", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
3794
3859
|
{ id: "release-candidate", description: "Run release-candidate readiness checks", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
3795
3860
|
{ id: "workspace-unlink", description: "Remove local workspace links before release", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true },
|
|
3796
3861
|
...mode === "recursive-workspace" ? [{ id: "prepare-release-metadata", description: "Rewrite stable release metadata", repoName: rootRepo.name, repoPath: rootRepo.path, branch: STAGING_BRANCH, resumable: true }] : [],
|
|
@@ -3831,6 +3896,30 @@ async function workflowRelease(helpers, input) {
|
|
|
3831
3896
|
const rootVersion = String(releasePlan.rootVersion);
|
|
3832
3897
|
applyTreeseedEnvironmentToProcess({ tenantRoot: root, scope: "staging", override: true });
|
|
3833
3898
|
assertReleaseGitHubAutomationReady(root, effectiveSelectedPackageNames, ciMode);
|
|
3899
|
+
const stagingGateResult = resumeAtRootGates ? completedJournalStepData(root, workflowRun.runId, "release-staging-gates") : await executeJournalStep(root, workflowRun.runId, "release-staging-gates", () => {
|
|
3900
|
+
helpers.write("[release][workflow] Verifying current staging gates before production release.");
|
|
3901
|
+
const packageGates = checkedOutWorkspacePackageRepos(root).filter((pkg) => effectiveSelectedPackageNames.has(pkg.name)).map((pkg) => ({
|
|
3902
|
+
name: pkg.name,
|
|
3903
|
+
repoPath: pkg.dir,
|
|
3904
|
+
workflow: "verify.yml",
|
|
3905
|
+
branch: STAGING_BRANCH,
|
|
3906
|
+
headSha: headCommit(pkg.dir)
|
|
3907
|
+
}));
|
|
3908
|
+
return waitForWorkflowGates("release", [
|
|
3909
|
+
hostedDeployGate({
|
|
3910
|
+
name: rootRepo.name,
|
|
3911
|
+
repoPath: rootRepo.path,
|
|
3912
|
+
workflow: "deploy.yml",
|
|
3913
|
+
branch: STAGING_BRANCH,
|
|
3914
|
+
headSha: headCommit(gitRoot)
|
|
3915
|
+
}),
|
|
3916
|
+
...packageGates
|
|
3917
|
+
], ciMode, {
|
|
3918
|
+
root,
|
|
3919
|
+
runId: workflowRun.runId,
|
|
3920
|
+
onProgress: (line, stream) => helpers.write(line, stream)
|
|
3921
|
+
}).then((workflowGates) => ({ workflowGates }));
|
|
3922
|
+
});
|
|
3834
3923
|
const releaseCandidate = resumeAtRootGates ? completedJournalStepData(root, workflowRun.runId, "release-candidate") : await executeJournalStep(root, workflowRun.runId, "release-candidate", () => runReleaseCandidateForPlan("release", root, releasePlan, { allowReuse: true }));
|
|
3835
3924
|
if (!resumeAtRootGates && !isResume) {
|
|
3836
3925
|
assertSessionBranchSafety("release", session, { requireCleanPackages: true, requireCurrentBranch: true });
|
|
@@ -3901,7 +3990,7 @@ async function workflowRelease(helpers, input) {
|
|
|
3901
3990
|
rootRepo.commitSha = String(rootRelease2?.releasedCommit ?? headCommit(gitRoot));
|
|
3902
3991
|
rootRepo.tagName = String(rootRelease2?.rootVersion ?? "");
|
|
3903
3992
|
const rootWorkflowGateResult2 = await executeJournalStep(root, workflowRun.runId, "release-root-gates", () => waitForWorkflowGates("release", [
|
|
3904
|
-
|
|
3993
|
+
hostedDeployGate({
|
|
3905
3994
|
name: rootRepo.name,
|
|
3906
3995
|
repoPath: rootRepo.path,
|
|
3907
3996
|
workflow: "deploy.yml",
|
|
@@ -3944,13 +4033,17 @@ async function workflowRelease(helpers, input) {
|
|
|
3944
4033
|
repos: [],
|
|
3945
4034
|
rootRepo,
|
|
3946
4035
|
releaseCandidate,
|
|
4036
|
+
stagingWorkflowGates: stagingGateResult?.workflowGates ?? [],
|
|
3947
4037
|
releaseBackMerge: releaseBackMerge2,
|
|
3948
4038
|
hostedDeploymentState: hostedDeploymentState2,
|
|
3949
4039
|
finalBranch: currentBranch(gitRoot) || STAGING_BRANCH,
|
|
3950
4040
|
pushStatus: { stagingPushed: true, productionPushed: true, tagPushed: true },
|
|
3951
4041
|
workspaceLinks: workspaceLinks2,
|
|
3952
4042
|
ciMode,
|
|
3953
|
-
workflowGates:
|
|
4043
|
+
workflowGates: [
|
|
4044
|
+
...Array.isArray(stagingGateResult?.workflowGates) ? stagingGateResult.workflowGates : [],
|
|
4045
|
+
...Array.isArray(rootWorkflowGateResult2?.workflowGates) ? rootWorkflowGateResult2.workflowGates : []
|
|
4046
|
+
],
|
|
3954
4047
|
hostingAudit: hostingAudit2,
|
|
3955
4048
|
...worktreePayload(root, effectiveInput.worktreeMode)
|
|
3956
4049
|
};
|
|
@@ -4208,7 +4301,7 @@ async function workflowRelease(helpers, input) {
|
|
|
4208
4301
|
rootRepo.commitSha = String(rootRelease?.releasedCommit ?? headCommit(gitRoot));
|
|
4209
4302
|
rootRepo.tagName = String(rootRelease?.rootVersion ?? "");
|
|
4210
4303
|
const rootWorkflowGateResult = await executeJournalStep(root, workflowRun.runId, "release-root-gates", () => waitForWorkflowGates("release", [
|
|
4211
|
-
|
|
4304
|
+
hostedDeployGate({
|
|
4212
4305
|
name: rootRepo.name,
|
|
4213
4306
|
repoPath: rootRepo.path,
|
|
4214
4307
|
workflow: "deploy.yml",
|
|
@@ -4264,6 +4357,7 @@ async function workflowRelease(helpers, input) {
|
|
|
4264
4357
|
repos: packageReports,
|
|
4265
4358
|
rootRepo,
|
|
4266
4359
|
releaseCandidate,
|
|
4360
|
+
stagingWorkflowGates: stagingGateResult?.workflowGates ?? [],
|
|
4267
4361
|
releaseBackMerge,
|
|
4268
4362
|
hostedDeploymentState,
|
|
4269
4363
|
finalBranch: currentBranch(gitRoot) || STAGING_BRANCH,
|
|
@@ -4275,6 +4369,7 @@ async function workflowRelease(helpers, input) {
|
|
|
4275
4369
|
workspaceLinks,
|
|
4276
4370
|
ciMode,
|
|
4277
4371
|
workflowGates: [
|
|
4372
|
+
...Array.isArray(stagingGateResult?.workflowGates) ? stagingGateResult.workflowGates : [],
|
|
4278
4373
|
...packageReports.flatMap((report) => report.workflowGates),
|
|
4279
4374
|
...Array.isArray(rootWorkflowGateResult?.workflowGates) ? rootWorkflowGateResult.workflowGates : []
|
|
4280
4375
|
],
|
package/dist/workflow/runs.js
CHANGED
|
@@ -257,6 +257,28 @@ function expectedPackageHeadAfterReleaseGate(journal, packageName) {
|
|
|
257
257
|
if (typeof data?.commitSha === "string") return data.commitSha;
|
|
258
258
|
return null;
|
|
259
259
|
}
|
|
260
|
+
function savePartialFailureData(journal) {
|
|
261
|
+
const details = stringRecord(journal.failure?.details);
|
|
262
|
+
return stringRecord(details?.partialFailure);
|
|
263
|
+
}
|
|
264
|
+
function collectSaveExpectedHeads(journal) {
|
|
265
|
+
const heads = {};
|
|
266
|
+
const saveData = stringRecord(journal.steps.find((step) => step.id === "save-repositories")?.data);
|
|
267
|
+
const partialFailure = savePartialFailureData(journal);
|
|
268
|
+
const source = saveData ?? partialFailure;
|
|
269
|
+
const rootRepo = stringRecord(source?.rootRepo);
|
|
270
|
+
if (typeof rootRepo?.commitSha === "string") {
|
|
271
|
+
heads["@treeseed/market"] = rootRepo.commitSha;
|
|
272
|
+
}
|
|
273
|
+
const repos = Array.isArray(source?.repos) ? source.repos : [];
|
|
274
|
+
for (const entry of repos) {
|
|
275
|
+
const repo = stringRecord(entry);
|
|
276
|
+
if (typeof repo?.name === "string" && typeof repo.commitSha === "string") {
|
|
277
|
+
heads[repo.name] = repo.commitSha;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return heads;
|
|
281
|
+
}
|
|
260
282
|
function classifyWorkflowRunJournal(journal, options = {}) {
|
|
261
283
|
const reasons = [];
|
|
262
284
|
const now = options.now ?? nowIso();
|
|
@@ -326,6 +348,15 @@ function classifyWorkflowRunJournal(journal, options = {}) {
|
|
|
326
348
|
}
|
|
327
349
|
}
|
|
328
350
|
}
|
|
351
|
+
if (journal.command === "save" && options.currentHeads) {
|
|
352
|
+
const expectedHeads = collectSaveExpectedHeads(journal);
|
|
353
|
+
for (const [name, expectedHead] of Object.entries(expectedHeads)) {
|
|
354
|
+
const currentHead = options.currentHeads[name];
|
|
355
|
+
if (currentHead && expectedHead && currentHead !== expectedHead) {
|
|
356
|
+
reasons.push(`${name} head changed from ${expectedHead} to ${currentHead}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
329
360
|
return {
|
|
330
361
|
state: reasons.length > 0 ? "stale" : "resumable",
|
|
331
362
|
reasons: reasons.length > 0 ? reasons : releaseGateOnlyCompletion ? ["release commits already exist; remaining release gates can be rechecked"] : ["workflow run can be resumed"],
|
package/package.json
CHANGED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
name: Treeseed Processing Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
environment:
|
|
7
|
+
required: true
|
|
8
|
+
type: string
|
|
9
|
+
action_kind:
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
project_id:
|
|
13
|
+
required: false
|
|
14
|
+
type: string
|
|
15
|
+
preview_id:
|
|
16
|
+
required: false
|
|
17
|
+
type: string
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
environment:
|
|
21
|
+
required: true
|
|
22
|
+
default: staging
|
|
23
|
+
type: choice
|
|
24
|
+
options:
|
|
25
|
+
- staging
|
|
26
|
+
- prod
|
|
27
|
+
action_kind:
|
|
28
|
+
required: true
|
|
29
|
+
default: deploy_processing
|
|
30
|
+
type: choice
|
|
31
|
+
options:
|
|
32
|
+
- deploy_processing
|
|
33
|
+
- monitor
|
|
34
|
+
project_id:
|
|
35
|
+
required: false
|
|
36
|
+
type: string
|
|
37
|
+
preview_id:
|
|
38
|
+
required: false
|
|
39
|
+
type: string
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
__WORKING_DIRECTORY_BLOCK__ processing:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
permissions:
|
|
45
|
+
contents: read
|
|
46
|
+
environment: ${{ inputs.environment == 'prod' && 'production' || 'staging' }}
|
|
47
|
+
env:
|
|
48
|
+
TREESEED_BOOTSTRAP_MODE: auto
|
|
49
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
50
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
|
|
51
|
+
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
|
|
52
|
+
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
|
53
|
+
TREESEED_RAILWAY_WORKSPACE: ${{ vars.TREESEED_RAILWAY_WORKSPACE }}
|
|
54
|
+
TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
|
|
55
|
+
TREESEED_API_AUTH_SECRET: ${{ secrets.TREESEED_API_AUTH_SECRET }}
|
|
56
|
+
TREESEED_API_D1_DATABASE_ID: ${{ vars.TREESEED_API_D1_DATABASE_ID }}
|
|
57
|
+
TREESEED_API_WEB_SERVICE_ID: ${{ vars.TREESEED_API_WEB_SERVICE_ID }}
|
|
58
|
+
TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
|
|
59
|
+
TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
|
|
60
|
+
TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
|
|
61
|
+
TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
62
|
+
TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
|
|
63
|
+
TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
|
|
64
|
+
TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
|
|
65
|
+
TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
|
|
66
|
+
TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
|
|
67
|
+
TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
|
|
68
|
+
TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
|
|
69
|
+
TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
|
|
70
|
+
TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
|
|
71
|
+
TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
|
|
72
|
+
TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
|
|
73
|
+
TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
|
|
74
|
+
TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
|
|
75
|
+
TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
|
|
76
|
+
TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
|
|
77
|
+
TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
|
|
78
|
+
TREESEED_CAPACITY_PROVIDER_ID: ${{ vars.TREESEED_CAPACITY_PROVIDER_ID }}
|
|
79
|
+
TREESEED_CAPACITY_PROVIDER_TEAM_ID: ${{ vars.TREESEED_CAPACITY_PROVIDER_TEAM_ID }}
|
|
80
|
+
TREESEED_CAPACITY_PROVIDER_SERVICE_BASE_URL: ${{ vars.TREESEED_CAPACITY_PROVIDER_SERVICE_BASE_URL }}
|
|
81
|
+
TREESEED_PROCESSING_DRAIN: ${{ vars.TREESEED_PROCESSING_DRAIN }}
|
|
82
|
+
TREESEED_WORKFLOW_ACTION: ${{ inputs.action_kind }}
|
|
83
|
+
TREESEED_WORKFLOW_ENVIRONMENT: ${{ inputs.environment }}
|
|
84
|
+
TREESEED_WORKFLOW_PLANE: processing
|
|
85
|
+
TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
86
|
+
TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id }}
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@v4
|
|
89
|
+
with:
|
|
90
|
+
submodules: recursive
|
|
91
|
+
|
|
92
|
+
- uses: actions/setup-node@v4
|
|
93
|
+
with:
|
|
94
|
+
node-version: 22
|
|
95
|
+
cache: npm
|
|
96
|
+
cache-dependency-path: __CACHE_DEPENDENCY_PATH__
|
|
97
|
+
|
|
98
|
+
- name: Install dependencies
|
|
99
|
+
shell: bash
|
|
100
|
+
run: |
|
|
101
|
+
set -euo pipefail
|
|
102
|
+
node -e "const fs = require('fs'); for (const file of ['packages/sdk/package.json', 'packages/agent/package.json', 'packages/core/package.json', 'packages/cli/package.json']) { if (!fs.existsSync(file)) continue; const p = JSON.parse(fs.readFileSync(file, 'utf8')); if (p.scripts) delete p.scripts.prepare; fs.writeFileSync(file, JSON.stringify(p, null, '\t') + '\n'); }"
|
|
103
|
+
npm ci --ignore-scripts
|
|
104
|
+
|
|
105
|
+
- name: Build package artifacts
|
|
106
|
+
shell: bash
|
|
107
|
+
run: |
|
|
108
|
+
set -euo pipefail
|
|
109
|
+
for dir in packages/sdk packages/agent packages/core packages/cli; do
|
|
110
|
+
if test -f "${dir}/package.json"; then npm --prefix "${dir}" run build:dist; fi
|
|
111
|
+
done
|
|
112
|
+
|
|
113
|
+
- name: Run processing workflow action
|
|
114
|
+
shell: bash
|
|
115
|
+
run: |
|
|
116
|
+
set -euo pipefail
|
|
117
|
+
EXTRA_ARGS=()
|
|
118
|
+
if [[ -n "${TREESEED_WORKFLOW_PROJECT:-}" ]]; then EXTRA_ARGS+=(--project-id "${TREESEED_WORKFLOW_PROJECT}"); fi
|
|
119
|
+
if [[ -n "${TREESEED_WORKFLOW_PREVIEW_ID:-}" ]]; then EXTRA_ARGS+=(--preview-id "${TREESEED_WORKFLOW_PREVIEW_ID}"); fi
|
|
120
|
+
node ./packages/sdk/scripts/run-ts.mjs ./packages/sdk/scripts/tenant-workflow-action.ts --action "${TREESEED_WORKFLOW_ACTION}" --environment "${TREESEED_WORKFLOW_ENVIRONMENT}" "${EXTRA_ARGS[@]}"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
name: Treeseed Web Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
environment:
|
|
7
|
+
required: true
|
|
8
|
+
type: string
|
|
9
|
+
action_kind:
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
project_id:
|
|
13
|
+
required: false
|
|
14
|
+
type: string
|
|
15
|
+
preview_id:
|
|
16
|
+
required: false
|
|
17
|
+
type: string
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
environment:
|
|
21
|
+
required: true
|
|
22
|
+
default: staging
|
|
23
|
+
type: choice
|
|
24
|
+
options:
|
|
25
|
+
- staging
|
|
26
|
+
- prod
|
|
27
|
+
action_kind:
|
|
28
|
+
required: true
|
|
29
|
+
default: deploy_web
|
|
30
|
+
type: choice
|
|
31
|
+
options:
|
|
32
|
+
- deploy_web
|
|
33
|
+
- publish_content
|
|
34
|
+
- monitor
|
|
35
|
+
project_id:
|
|
36
|
+
required: false
|
|
37
|
+
type: string
|
|
38
|
+
preview_id:
|
|
39
|
+
required: false
|
|
40
|
+
type: string
|
|
41
|
+
|
|
42
|
+
jobs:
|
|
43
|
+
__WORKING_DIRECTORY_BLOCK__ web:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
permissions:
|
|
46
|
+
contents: read
|
|
47
|
+
environment: ${{ inputs.environment == 'prod' && 'production' || 'staging' }}
|
|
48
|
+
env:
|
|
49
|
+
TREESEED_BOOTSTRAP_MODE: auto
|
|
50
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
51
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
|
|
52
|
+
TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
|
|
53
|
+
TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
|
|
54
|
+
TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
|
|
55
|
+
TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
|
|
56
|
+
TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
|
|
57
|
+
TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
|
|
58
|
+
TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
|
|
59
|
+
TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
|
|
60
|
+
TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
|
|
61
|
+
TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
|
|
62
|
+
TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
|
|
63
|
+
TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
|
|
64
|
+
TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
|
|
65
|
+
TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
|
|
66
|
+
TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
|
|
67
|
+
TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
|
|
68
|
+
TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
|
|
69
|
+
TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
|
|
70
|
+
TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
|
|
71
|
+
TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
|
|
72
|
+
TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
|
|
73
|
+
TREESEED_CATALOG_MARKET_API_BASE_URLS: ${{ vars.TREESEED_CATALOG_MARKET_API_BASE_URLS || vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
|
|
74
|
+
TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
|
|
75
|
+
TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
|
|
76
|
+
TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
|
|
77
|
+
TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
78
|
+
TREESEED_WORKFLOW_ACTION: ${{ inputs.action_kind }}
|
|
79
|
+
TREESEED_WORKFLOW_ENVIRONMENT: ${{ inputs.environment }}
|
|
80
|
+
TREESEED_WORKFLOW_PLANE: web
|
|
81
|
+
TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
82
|
+
TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id }}
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
with:
|
|
86
|
+
submodules: recursive
|
|
87
|
+
|
|
88
|
+
- uses: actions/setup-node@v4
|
|
89
|
+
with:
|
|
90
|
+
node-version: 22
|
|
91
|
+
cache: npm
|
|
92
|
+
cache-dependency-path: __CACHE_DEPENDENCY_PATH__
|
|
93
|
+
|
|
94
|
+
- name: Install dependencies
|
|
95
|
+
shell: bash
|
|
96
|
+
run: |
|
|
97
|
+
set -euo pipefail
|
|
98
|
+
node -e "const fs = require('fs'); for (const file of ['packages/sdk/package.json', 'packages/agent/package.json', 'packages/core/package.json', 'packages/cli/package.json']) { if (!fs.existsSync(file)) continue; const p = JSON.parse(fs.readFileSync(file, 'utf8')); if (p.scripts) delete p.scripts.prepare; fs.writeFileSync(file, JSON.stringify(p, null, '\t') + '\n'); }"
|
|
99
|
+
npm ci --ignore-scripts
|
|
100
|
+
|
|
101
|
+
- name: Build package artifacts
|
|
102
|
+
shell: bash
|
|
103
|
+
run: |
|
|
104
|
+
set -euo pipefail
|
|
105
|
+
for dir in packages/sdk packages/agent packages/core packages/cli; do
|
|
106
|
+
if test -f "${dir}/package.json"; then npm --prefix "${dir}" run build:dist; fi
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
- name: Run web workflow action
|
|
110
|
+
shell: bash
|
|
111
|
+
run: |
|
|
112
|
+
set -euo pipefail
|
|
113
|
+
EXTRA_ARGS=()
|
|
114
|
+
if [[ -n "${TREESEED_WORKFLOW_PROJECT:-}" ]]; then EXTRA_ARGS+=(--project-id "${TREESEED_WORKFLOW_PROJECT}"); fi
|
|
115
|
+
if [[ -n "${TREESEED_WORKFLOW_PREVIEW_ID:-}" ]]; then EXTRA_ARGS+=(--preview-id "${TREESEED_WORKFLOW_PREVIEW_ID}"); fi
|
|
116
|
+
node ./packages/sdk/scripts/run-ts.mjs ./packages/sdk/scripts/tenant-workflow-action.ts --action "${TREESEED_WORKFLOW_ACTION}" --environment "${TREESEED_WORKFLOW_ENVIRONMENT}" "${EXTRA_ARGS[@]}"
|
|
@@ -14,7 +14,7 @@ on:
|
|
|
14
14
|
workflow_file:
|
|
15
15
|
description: Workflow file to dispatch in the tenant repository
|
|
16
16
|
required: false
|
|
17
|
-
default: deploy.yml
|
|
17
|
+
default: deploy-web.yml
|
|
18
18
|
type: string
|
|
19
19
|
project_id:
|
|
20
20
|
description: Treeseed project id recorded in the market control plane
|
|
@@ -31,11 +31,11 @@ on:
|
|
|
31
31
|
action_kind:
|
|
32
32
|
description: Requested orchestration action
|
|
33
33
|
required: true
|
|
34
|
-
default:
|
|
34
|
+
default: deploy_web
|
|
35
35
|
type: choice
|
|
36
36
|
options:
|
|
37
|
-
-
|
|
38
|
-
-
|
|
37
|
+
- deploy_web
|
|
38
|
+
- deploy_processing
|
|
39
39
|
- publish_content
|
|
40
40
|
- monitor
|
|
41
41
|
|