@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.
Files changed (47) hide show
  1. package/dist/capacity.d.ts +33 -0
  2. package/dist/fixture-support.d.ts +1 -1
  3. package/dist/fixture-support.js +5 -5
  4. package/dist/managed-dependencies.js +132 -10
  5. package/dist/operations/services/bootstrap-runner.js +7 -1
  6. package/dist/operations/services/config-runtime.js +13 -4
  7. package/dist/operations/services/github-actions-verification.d.ts +3 -0
  8. package/dist/operations/services/github-actions-verification.js +3 -0
  9. package/dist/operations/services/github-api.d.ts +4 -1
  10. package/dist/operations/services/github-api.js +26 -8
  11. package/dist/operations/services/github-automation.d.ts +14 -5
  12. package/dist/operations/services/github-automation.js +45 -11
  13. package/dist/operations/services/hub-provider-launch.js +9 -8
  14. package/dist/operations/services/project-platform.d.ts +93 -210
  15. package/dist/operations/services/project-platform.js +74 -34
  16. package/dist/operations/services/railway-deploy.d.ts +25 -2
  17. package/dist/operations/services/railway-deploy.js +312 -20
  18. package/dist/operations/services/repository-save-orchestrator.d.ts +8 -0
  19. package/dist/operations/services/repository-save-orchestrator.js +40 -3
  20. package/dist/operations/services/runtime-paths.d.ts +1 -0
  21. package/dist/operations/services/runtime-paths.js +3 -1
  22. package/dist/operations/services/runtime-tools.d.ts +1 -0
  23. package/dist/operations/services/runtime-tools.js +2 -0
  24. package/dist/operations/services/template-registry.js +3 -0
  25. package/dist/platform/contracts.d.ts +9 -0
  26. package/dist/platform/deploy-config.js +28 -0
  27. package/dist/platform/env.yaml +1 -745
  28. package/dist/platform/environment.js +69 -9
  29. package/dist/reconcile/builtin-adapters.js +7 -2
  30. package/dist/scripts/install-managed-dependencies.js +12 -0
  31. package/dist/scripts/tenant-workflow-action.js +11 -9
  32. package/dist/scripts/test-scaffold.js +3 -1
  33. package/dist/scripts/workflow-commands.test.js +10 -6
  34. package/dist/scripts/workspace-command-e2e.js +1 -1
  35. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +1 -0
  36. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +1 -1
  37. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +7 -6
  38. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +6 -0
  39. package/dist/workflow/operations.d.ts +41 -8
  40. package/dist/workflow/operations.js +119 -24
  41. package/dist/workflow/runs.js +31 -0
  42. package/package.json +1 -1
  43. package/templates/github/deploy-processing.workflow.yml +120 -0
  44. package/templates/github/deploy-web.workflow.yml +116 -0
  45. package/templates/github/hosted-project.workflow.yml +4 -4
  46. package/templates/github/deploy.managed.workflow.yml +0 -208
  47. package/templates/github/deploy.workflow.yml +0 -746
@@ -1,746 +0,0 @@
1
- name: Treeseed Deploy
2
-
3
- on:
4
- push:
5
- branches:
6
- - staging
7
- tags:
8
- - '*.*.*'
9
- workflow_dispatch:
10
- inputs:
11
- environment:
12
- description: Target environment
13
- required: true
14
- default: staging
15
- type: choice
16
- options:
17
- - staging
18
- - prod
19
- action_kind:
20
- description: Workflow action to perform
21
- required: true
22
- default: deploy_code
23
- type: choice
24
- options:
25
- - provision
26
- - deploy_code
27
- - publish_content
28
- - monitor
29
- project_id:
30
- description: Treeseed project id for control-plane reporting
31
- required: false
32
- type: string
33
- preview_id:
34
- description: Optional preview overlay id for editorial publishes
35
- required: false
36
- type: string
37
-
38
- jobs:
39
- classify:
40
- runs-on: ubuntu-latest
41
- outputs:
42
- scope: ${{ steps.classify.outputs.scope }}
43
- code_changed: ${{ steps.classify.outputs.code_changed }}
44
- content_changed: ${{ steps.classify.outputs.content_changed }}
45
- release_tag: ${{ steps.classify.outputs.release_tag }}
46
- workflow_action: ${{ steps.classify.outputs.workflow_action }}
47
- preview_id: ${{ steps.classify.outputs.preview_id }}
48
- steps:
49
- - name: Checkout
50
- uses: actions/checkout@v4
51
- with:
52
- fetch-depth: 0
53
-
54
- - name: Classify changes
55
- id: classify
56
- shell: bash
57
- run: |
58
- set -euo pipefail
59
-
60
- if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
61
- scope="${{ inputs.environment }}"
62
- workflow_action="${{ inputs.action_kind }}"
63
- release_tag="false"
64
- code_changed=$([[ "${workflow_action}" == "deploy_code" ]] && echo "true" || echo "false")
65
- content_changed=$([[ "${workflow_action}" == "publish_content" ]] && echo "true" || echo "false")
66
- preview_id="${{ inputs.preview_id }}"
67
- else
68
- ref_name="${GITHUB_REF_NAME}"
69
- ref_type="${GITHUB_REF_TYPE}"
70
- before_sha="${{ github.event.before }}"
71
- head_sha="${GITHUB_SHA}"
72
- workflow_action="auto"
73
- preview_id="staging-${GITHUB_SHA}"
74
-
75
- if [[ "${ref_type}" == "tag" ]]; then
76
- scope="prod"
77
- if [[ "${ref_name}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
78
- release_tag="true"
79
- compare_ref="$(git rev-list --parents -n 1 "${head_sha}" | awk '{print $2}')"
80
- else
81
- release_tag="false"
82
- compare_ref=""
83
- fi
84
- else
85
- scope="staging"
86
- release_tag="false"
87
- compare_ref="${before_sha}"
88
- fi
89
-
90
- if [[ -z "${compare_ref}" || "${compare_ref}" == "0000000000000000000000000000000000000000" ]]; then
91
- compare_ref="$(git rev-list --max-count=1 "${head_sha}^" 2>/dev/null || true)"
92
- fi
93
-
94
- code_changed="false"
95
- content_changed="false"
96
-
97
- if [[ "${ref_type}" == "tag" && "${release_tag}" != "true" ]]; then
98
- code_changed="false"
99
- content_changed="false"
100
- elif [[ -n "${compare_ref}" ]]; then
101
- while IFS= read -r path; do
102
- [[ -z "${path}" ]] && continue
103
- case "${path}" in
104
- src/content/*|content/*|books/*|docs/*)
105
- content_changed="true"
106
- ;;
107
- migrations/*)
108
- code_changed="true"
109
- ;;
110
- *)
111
- code_changed="true"
112
- ;;
113
- esac
114
- done < <(git diff --name-only "${compare_ref}" "${head_sha}")
115
- else
116
- code_changed="true"
117
- fi
118
- fi
119
-
120
- {
121
- echo "scope=${scope}"
122
- echo "code_changed=${code_changed}"
123
- echo "content_changed=${content_changed}"
124
- echo "release_tag=${release_tag}"
125
- echo "workflow_action=${workflow_action}"
126
- echo "preview_id=${preview_id}"
127
- } >> "${GITHUB_OUTPUT}"
128
-
129
- verify:
130
- runs-on: ubuntu-latest
131
- needs: classify
132
- if: |
133
- needs.classify.outputs.workflow_action == 'deploy_code' ||
134
- needs.classify.outputs.workflow_action == 'publish_content' ||
135
- needs.classify.outputs.code_changed == 'true' ||
136
- needs.classify.outputs.content_changed == 'true' ||
137
- needs.classify.outputs.release_tag == 'true'
138
- permissions:
139
- contents: read
140
- env:
141
- TREESEED_BOOTSTRAP_MODE: auto
142
- steps:
143
- - name: Checkout
144
- uses: actions/checkout@v4
145
- with:
146
- submodules: recursive
147
-
148
- - name: Setup Node
149
- uses: actions/setup-node@v4
150
- with:
151
- node-version: 22
152
- cache: npm
153
- cache-dependency-path: __CACHE_DEPENDENCY_PATH__
154
-
155
- - name: Install dependencies
156
- run: |
157
- node -e "const fs = require('fs'); for (const file of ['packages/sdk/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'); }"
158
- for attempt in 1 2 3; do
159
- if npm ci --ignore-scripts; then
160
- break
161
- fi
162
- if test "${attempt}" = "3"; then
163
- exit 1
164
- fi
165
- echo "npm ci failed; retrying (${attempt}/3)."
166
- sleep $((attempt * 10))
167
- done
168
- for dir in packages/sdk packages/core packages/cli; do
169
- if test -d "${dir}/.git" || git -C "${dir}" rev-parse --git-dir >/dev/null 2>&1; then
170
- git -C "${dir}" checkout -- package.json
171
- fi
172
- done
173
-
174
- - name: Build workspace package artifacts
175
- shell: bash
176
- run: |
177
- set -euo pipefail
178
- for dir in packages/sdk packages/core packages/cli; do
179
- if test -f "${dir}/package.json"; then
180
- npm --prefix "${dir}" run build:dist
181
- fi
182
- done
183
-
184
- - name: Verify workspace
185
- shell: bash
186
- run: |
187
- set -euo pipefail
188
- npm run verify:local 2>&1 | tee verify.log
189
- if test -f ./packages/sdk/scripts/check-build-warnings.mjs; then
190
- node ./packages/sdk/scripts/check-build-warnings.mjs verify.log
191
- elif test -f ./node_modules/@treeseed/sdk/dist/scripts/check-build-warnings.js; then
192
- node ./node_modules/@treeseed/sdk/dist/scripts/check-build-warnings.js verify.log
193
- else
194
- echo "Unable to resolve @treeseed/sdk warning scanner entrypoint."
195
- exit 1
196
- fi
197
- __WORKING_DIRECTORY_BLOCK__
198
-
199
- provision:
200
- runs-on: ubuntu-latest
201
- needs:
202
- - classify
203
- - verify
204
- if: |
205
- needs.classify.outputs.workflow_action == 'provision' ||
206
- needs.classify.outputs.workflow_action == 'deploy_code' ||
207
- needs.classify.outputs.workflow_action == 'publish_content' ||
208
- needs.classify.outputs.workflow_action == 'monitor' ||
209
- needs.classify.outputs.code_changed == 'true' ||
210
- needs.classify.outputs.content_changed == 'true' ||
211
- needs.classify.outputs.release_tag == 'true'
212
- permissions:
213
- contents: read
214
- environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
215
- env:
216
- TREESEED_BOOTSTRAP_MODE: auto
217
- CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
218
- CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
219
- TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
220
- TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
221
- TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
222
- TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
223
- TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
224
- TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
225
- TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
226
- TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
227
- TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
228
- TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
229
- TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
230
- TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
231
- TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
232
- TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
233
- RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
234
- TREESEED_RAILWAY_WORKSPACE: ${{ vars.TREESEED_RAILWAY_WORKSPACE }}
235
- TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
236
- TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
237
- TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
238
- TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
239
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
240
- 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' }}
241
- TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
242
- TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
243
- TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
244
- TREESEED_API_AUTH_SECRET: ${{ secrets.TREESEED_API_AUTH_SECRET }}
245
- TREESEED_WEB_SERVICE_ID: ${{ vars.TREESEED_WEB_SERVICE_ID }}
246
- TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
247
- TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
248
- TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
249
- TREESEED_AUTH_GITHUB_CLIENT_ID: ${{ vars.TREESEED_AUTH_GITHUB_CLIENT_ID }}
250
- TREESEED_AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GITHUB_CLIENT_SECRET }}
251
- TREESEED_AUTH_GOOGLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_GOOGLE_CLIENT_ID }}
252
- TREESEED_AUTH_GOOGLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GOOGLE_CLIENT_SECRET }}
253
- TREESEED_AUTH_MICROSOFT_CLIENT_ID: ${{ vars.TREESEED_AUTH_MICROSOFT_CLIENT_ID }}
254
- TREESEED_AUTH_MICROSOFT_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_MICROSOFT_CLIENT_SECRET }}
255
- TREESEED_AUTH_APPLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_APPLE_CLIENT_ID }}
256
- TREESEED_AUTH_APPLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_APPLE_CLIENT_SECRET }}
257
- TREESEED_API_D1_DATABASE_ID: ${{ vars.TREESEED_API_D1_DATABASE_ID }}
258
- TREESEED_API_WEB_SERVICE_ID: ${{ vars.TREESEED_API_WEB_SERVICE_ID }}
259
- TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
260
- TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
261
- TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
262
- TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
263
- TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
264
- TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
265
- TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
266
- TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
267
- TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
268
- TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
269
- TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
270
- TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
271
- TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
272
- TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
273
- TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
274
- TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
275
- TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
276
- TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
277
- TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
278
- TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
279
- TREESEED_WORKFLOW_ACTION: provision
280
- TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
281
- TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
282
- TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
283
- steps:
284
- - name: Checkout
285
- uses: actions/checkout@v4
286
- with:
287
- submodules: recursive
288
-
289
- - name: Setup Node
290
- uses: actions/setup-node@v4
291
- with:
292
- node-version: 22
293
- cache: npm
294
- cache-dependency-path: __CACHE_DEPENDENCY_PATH__
295
-
296
- - name: Install dependencies
297
- run: |
298
- node -e "const fs = require('fs'); for (const file of ['packages/sdk/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'); }"
299
- for attempt in 1 2 3; do
300
- if npm ci --ignore-scripts; then
301
- break
302
- fi
303
- if test "${attempt}" = "3"; then
304
- exit 1
305
- fi
306
- echo "npm ci failed; retrying (${attempt}/3)."
307
- sleep $((attempt * 10))
308
- done
309
- for dir in packages/sdk packages/core packages/cli; do
310
- if test -d "${dir}/.git" || git -C "${dir}" rev-parse --git-dir >/dev/null 2>&1; then
311
- git -C "${dir}" checkout -- package.json
312
- fi
313
- done
314
-
315
- - name: Build workspace package artifacts
316
- shell: bash
317
- run: |
318
- set -euo pipefail
319
- for dir in packages/sdk packages/core packages/cli; do
320
- if test -f "${dir}/package.json"; then
321
- npm --prefix "${dir}" run build:dist
322
- fi
323
- done
324
-
325
- - name: Install Railway CLI
326
- run: npm install -g @railway/cli
327
-
328
- - name: Provision Treeseed platform
329
- shell: bash
330
- run: |
331
- __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
332
-
333
- - name: Ensure Treeseed deployment state
334
- shell: bash
335
- run: |
336
- node --input-type=module -e "import { existsSync, readFileSync, writeFileSync } from 'node:fs'; const scope = process.env.TREESEED_WORKFLOW_ENVIRONMENT || 'staging'; const filePath = '.treeseed/state/environments/' + scope + '/deploy.json'; if (!existsSync(filePath)) { throw new Error('Provision did not write deployment state at ' + filePath); } const state = JSON.parse(readFileSync(filePath, 'utf8')); const dbId = state?.d1Databases?.SITE_DATA_DB?.databaseId; if (!dbId || String(dbId).startsWith('dryrun-')) { throw new Error('Provision deployment state is missing a live D1 database id.'); } const now = new Date().toISOString(); state.target = state.target || { kind: 'persistent', scope }; state.readiness = { ...(state.readiness || {}), initialized: true, configured: true, phase: state.readiness?.phase || 'config_complete', initializedAt: state.readiness?.initializedAt || now, lastValidatedAt: now, blockers: state.readiness?.blockers || [], warnings: state.readiness?.warnings || [] }; writeFileSync(filePath, JSON.stringify(state, null, 2) + '\n');"
337
-
338
- - name: Upload Treeseed deployment state
339
- if: always()
340
- uses: actions/upload-artifact@v4
341
- with:
342
- name: treeseed-deploy-state-${{ needs.classify.outputs.scope }}
343
- path: .treeseed/state
344
- if-no-files-found: error
345
- retention-days: 1
346
- include-hidden-files: true
347
- __WORKING_DIRECTORY_BLOCK__
348
-
349
- deploy-code:
350
- runs-on: ubuntu-latest
351
- needs:
352
- - classify
353
- - verify
354
- - provision
355
- permissions:
356
- contents: read
357
- if: |
358
- needs.classify.outputs.workflow_action == 'deploy_code' ||
359
- needs.classify.outputs.code_changed == 'true' ||
360
- needs.classify.outputs.release_tag == 'true'
361
- environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
362
- env:
363
- TREESEED_BOOTSTRAP_MODE: auto
364
- CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
365
- CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
366
- TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
367
- TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
368
- TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
369
- TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
370
- TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
371
- TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
372
- TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
373
- TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
374
- TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
375
- TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
376
- TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
377
- TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
378
- TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
379
- TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
380
- RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
381
- TREESEED_RAILWAY_WORKSPACE: ${{ vars.TREESEED_RAILWAY_WORKSPACE }}
382
- TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
383
- TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
384
- TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
385
- TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
386
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
387
- 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' }}
388
- TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
389
- TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
390
- TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
391
- TREESEED_API_AUTH_SECRET: ${{ secrets.TREESEED_API_AUTH_SECRET }}
392
- TREESEED_WEB_SERVICE_ID: ${{ vars.TREESEED_WEB_SERVICE_ID }}
393
- TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
394
- TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
395
- TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
396
- TREESEED_AUTH_GITHUB_CLIENT_ID: ${{ vars.TREESEED_AUTH_GITHUB_CLIENT_ID }}
397
- TREESEED_AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GITHUB_CLIENT_SECRET }}
398
- TREESEED_AUTH_GOOGLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_GOOGLE_CLIENT_ID }}
399
- TREESEED_AUTH_GOOGLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GOOGLE_CLIENT_SECRET }}
400
- TREESEED_AUTH_MICROSOFT_CLIENT_ID: ${{ vars.TREESEED_AUTH_MICROSOFT_CLIENT_ID }}
401
- TREESEED_AUTH_MICROSOFT_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_MICROSOFT_CLIENT_SECRET }}
402
- TREESEED_AUTH_APPLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_APPLE_CLIENT_ID }}
403
- TREESEED_AUTH_APPLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_APPLE_CLIENT_SECRET }}
404
- TREESEED_API_D1_DATABASE_ID: ${{ vars.TREESEED_API_D1_DATABASE_ID }}
405
- TREESEED_API_WEB_SERVICE_ID: ${{ vars.TREESEED_API_WEB_SERVICE_ID }}
406
- TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
407
- TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
408
- TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
409
- TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
410
- TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
411
- TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
412
- TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
413
- TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
414
- TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
415
- TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
416
- TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
417
- TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
418
- TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
419
- TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
420
- TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
421
- TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
422
- TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
423
- TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
424
- TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
425
- TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
426
- TREESEED_CONTENT_SERVING_MODE: published_runtime
427
- TREESEED_WORKFLOW_ACTION: deploy_code
428
- TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
429
- TREESEED_WORKFLOW_SKIP_PROVISION: "1"
430
- TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
431
- TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
432
- steps:
433
- - name: Checkout
434
- uses: actions/checkout@v4
435
- with:
436
- submodules: recursive
437
-
438
- - name: Setup Node
439
- uses: actions/setup-node@v4
440
- with:
441
- node-version: 22
442
- cache: npm
443
- cache-dependency-path: __CACHE_DEPENDENCY_PATH__
444
-
445
- - name: Install dependencies
446
- run: |
447
- node -e "const fs = require('fs'); for (const file of ['packages/sdk/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'); }"
448
- for attempt in 1 2 3; do
449
- if npm ci --ignore-scripts; then
450
- break
451
- fi
452
- if test "${attempt}" = "3"; then
453
- exit 1
454
- fi
455
- echo "npm ci failed; retrying (${attempt}/3)."
456
- sleep $((attempt * 10))
457
- done
458
- for dir in packages/sdk packages/core packages/cli; do
459
- if test -d "${dir}/.git" || git -C "${dir}" rev-parse --git-dir >/dev/null 2>&1; then
460
- git -C "${dir}" checkout -- package.json
461
- fi
462
- done
463
-
464
- - name: Build workspace package artifacts
465
- shell: bash
466
- run: |
467
- set -euo pipefail
468
- for dir in packages/sdk packages/core packages/cli; do
469
- if test -f "${dir}/package.json"; then
470
- npm --prefix "${dir}" run build:dist
471
- fi
472
- done
473
-
474
- - name: Install Railway CLI
475
- run: npm install -g @railway/cli
476
-
477
- - name: Download Treeseed deployment state
478
- uses: actions/download-artifact@v4
479
- with:
480
- name: treeseed-deploy-state-${{ needs.classify.outputs.scope }}
481
- path: .treeseed/state
482
-
483
- - name: Deploy Treeseed platform
484
- shell: bash
485
- run: |
486
- __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
487
- __WORKING_DIRECTORY_BLOCK__
488
-
489
- publish-content:
490
- runs-on: ubuntu-latest
491
- needs:
492
- - classify
493
- - verify
494
- - provision
495
- - deploy-code
496
- permissions:
497
- contents: read
498
- if: |
499
- always() &&
500
- needs.provision.result == 'success' &&
501
- (needs.classify.outputs.workflow_action == 'publish_content' ||
502
- needs.classify.outputs.content_changed == 'true') &&
503
- (needs['deploy-code'].result == 'success' || needs['deploy-code'].result == 'skipped')
504
- environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
505
- env:
506
- TREESEED_BOOTSTRAP_MODE: auto
507
- CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
508
- CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
509
- TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME }}
510
- TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME: ${{ vars.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME }}
511
- TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
512
- TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
513
- TREESEED_FORM_TOKEN_SECRET: ${{ secrets.TREESEED_FORM_TOKEN_SECRET }}
514
- TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
515
- TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
516
- TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
517
- TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
518
- TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
519
- TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
520
- TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
521
- TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
522
- TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
523
- RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
524
- TREESEED_RAILWAY_WORKSPACE: ${{ vars.TREESEED_RAILWAY_WORKSPACE }}
525
- TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
526
- TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
527
- TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
528
- TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
529
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
530
- 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' }}
531
- TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
532
- TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
533
- TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
534
- TREESEED_API_AUTH_SECRET: ${{ secrets.TREESEED_API_AUTH_SECRET }}
535
- TREESEED_WEB_SERVICE_ID: ${{ vars.TREESEED_WEB_SERVICE_ID }}
536
- TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
537
- TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
538
- TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
539
- TREESEED_AUTH_GITHUB_CLIENT_ID: ${{ vars.TREESEED_AUTH_GITHUB_CLIENT_ID }}
540
- TREESEED_AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GITHUB_CLIENT_SECRET }}
541
- TREESEED_AUTH_GOOGLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_GOOGLE_CLIENT_ID }}
542
- TREESEED_AUTH_GOOGLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GOOGLE_CLIENT_SECRET }}
543
- TREESEED_AUTH_MICROSOFT_CLIENT_ID: ${{ vars.TREESEED_AUTH_MICROSOFT_CLIENT_ID }}
544
- TREESEED_AUTH_MICROSOFT_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_MICROSOFT_CLIENT_SECRET }}
545
- TREESEED_AUTH_APPLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_APPLE_CLIENT_ID }}
546
- TREESEED_AUTH_APPLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_APPLE_CLIENT_SECRET }}
547
- TREESEED_API_D1_DATABASE_ID: ${{ vars.TREESEED_API_D1_DATABASE_ID }}
548
- TREESEED_API_WEB_SERVICE_ID: ${{ vars.TREESEED_API_WEB_SERVICE_ID }}
549
- TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
550
- TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
551
- TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
552
- TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
553
- TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
554
- TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
555
- TREESEED_AGENT_POOL_MIN_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MIN_WORKERS }}
556
- TREESEED_AGENT_POOL_MAX_WORKERS: ${{ vars.TREESEED_AGENT_POOL_MAX_WORKERS }}
557
- TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: ${{ vars.TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH }}
558
- TREESEED_AGENT_POOL_COOLDOWN_SECONDS: ${{ vars.TREESEED_AGENT_POOL_COOLDOWN_SECONDS }}
559
- TREESEED_WORKDAY_TIMEZONE: ${{ vars.TREESEED_WORKDAY_TIMEZONE }}
560
- TREESEED_WORKDAY_WINDOWS_JSON: ${{ vars.TREESEED_WORKDAY_WINDOWS_JSON }}
561
- TREESEED_WORKDAY_TASK_CREDIT_BUDGET: ${{ vars.TREESEED_WORKDAY_TASK_CREDIT_BUDGET }}
562
- TREESEED_MANAGER_MAX_QUEUED_TASKS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_TASKS }}
563
- TREESEED_MANAGER_MAX_QUEUED_CREDITS: ${{ vars.TREESEED_MANAGER_MAX_QUEUED_CREDITS }}
564
- TREESEED_MANAGER_PRIORITY_MODELS: ${{ vars.TREESEED_MANAGER_PRIORITY_MODELS }}
565
- TREESEED_TASK_CREDIT_WEIGHTS_JSON: ${{ vars.TREESEED_TASK_CREDIT_WEIGHTS_JSON }}
566
- TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
567
- TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
568
- TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
569
- TREESEED_WORKFLOW_ACTION: publish_content
570
- TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
571
- TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
572
- TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
573
- steps:
574
- - name: Checkout
575
- uses: actions/checkout@v4
576
- with:
577
- submodules: recursive
578
-
579
- - name: Setup Node
580
- uses: actions/setup-node@v4
581
- with:
582
- node-version: 22
583
- cache: npm
584
- cache-dependency-path: __CACHE_DEPENDENCY_PATH__
585
-
586
- - name: Install dependencies
587
- run: |
588
- node -e "const fs = require('fs'); for (const file of ['packages/sdk/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'); }"
589
- for attempt in 1 2 3; do
590
- if npm ci --ignore-scripts; then
591
- break
592
- fi
593
- if test "${attempt}" = "3"; then
594
- exit 1
595
- fi
596
- echo "npm ci failed; retrying (${attempt}/3)."
597
- sleep $((attempt * 10))
598
- done
599
- for dir in packages/sdk packages/core packages/cli; do
600
- if test -d "${dir}/.git" || git -C "${dir}" rev-parse --git-dir >/dev/null 2>&1; then
601
- git -C "${dir}" checkout -- package.json
602
- fi
603
- done
604
-
605
- - name: Build workspace package artifacts
606
- shell: bash
607
- run: |
608
- set -euo pipefail
609
- for dir in packages/sdk packages/core packages/cli; do
610
- if test -f "${dir}/package.json"; then
611
- npm --prefix "${dir}" run build:dist
612
- fi
613
- done
614
-
615
- - name: Install Railway CLI
616
- run: npm install -g @railway/cli
617
-
618
- - name: Download Treeseed deployment state
619
- uses: actions/download-artifact@v4
620
- with:
621
- name: treeseed-deploy-state-${{ needs.classify.outputs.scope }}
622
- path: .treeseed/state
623
-
624
- - name: Publish Treeseed content
625
- shell: bash
626
- run: |
627
- __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
628
- __WORKING_DIRECTORY_BLOCK__
629
-
630
- monitor:
631
- runs-on: ubuntu-latest
632
- needs:
633
- - classify
634
- - provision
635
- - deploy-code
636
- - publish-content
637
- if: |
638
- always() &&
639
- needs.provision.result == 'success' &&
640
- (needs.classify.outputs.workflow_action == 'monitor' ||
641
- needs.classify.outputs.code_changed == 'true' ||
642
- needs.classify.outputs.content_changed == 'true' ||
643
- needs.classify.outputs.release_tag == 'true') &&
644
- (needs['deploy-code'].result == 'success' || needs['deploy-code'].result == 'skipped') &&
645
- (needs['publish-content'].result == 'success' || needs['publish-content'].result == 'skipped')
646
- permissions:
647
- contents: read
648
- environment: ${{ needs.classify.outputs.scope == 'prod' && 'production' || 'staging' }}
649
- env:
650
- TREESEED_BOOTSTRAP_MODE: auto
651
- CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
652
- CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
653
- TREESEED_CONTENT_BUCKET_NAME: ${{ vars.TREESEED_CONTENT_BUCKET_NAME }}
654
- TREESEED_CONTENT_BUCKET_BINDING: ${{ vars.TREESEED_CONTENT_BUCKET_BINDING }}
655
- RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
656
- TREESEED_RAILWAY_WORKSPACE: ${{ vars.TREESEED_RAILWAY_WORKSPACE }}
657
- TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
658
- TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
659
- TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
660
- TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
661
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
662
- 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' }}
663
- TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
664
- TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
665
- TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
666
- TREESEED_API_AUTH_SECRET: ${{ secrets.TREESEED_API_AUTH_SECRET }}
667
- TREESEED_WEB_SERVICE_ID: ${{ vars.TREESEED_WEB_SERVICE_ID }}
668
- TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
669
- TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
670
- TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
671
- TREESEED_AUTH_GITHUB_CLIENT_ID: ${{ vars.TREESEED_AUTH_GITHUB_CLIENT_ID }}
672
- TREESEED_AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GITHUB_CLIENT_SECRET }}
673
- TREESEED_AUTH_GOOGLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_GOOGLE_CLIENT_ID }}
674
- TREESEED_AUTH_GOOGLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_GOOGLE_CLIENT_SECRET }}
675
- TREESEED_AUTH_MICROSOFT_CLIENT_ID: ${{ vars.TREESEED_AUTH_MICROSOFT_CLIENT_ID }}
676
- TREESEED_AUTH_MICROSOFT_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_MICROSOFT_CLIENT_SECRET }}
677
- TREESEED_AUTH_APPLE_CLIENT_ID: ${{ vars.TREESEED_AUTH_APPLE_CLIENT_ID }}
678
- TREESEED_AUTH_APPLE_CLIENT_SECRET: ${{ secrets.TREESEED_AUTH_APPLE_CLIENT_SECRET }}
679
- TREESEED_API_D1_DATABASE_ID: ${{ vars.TREESEED_API_D1_DATABASE_ID }}
680
- TREESEED_API_WEB_SERVICE_ID: ${{ vars.TREESEED_API_WEB_SERVICE_ID }}
681
- TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
682
- TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
683
- TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
684
- TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
685
- TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
686
- TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
687
- TREESEED_RAILWAY_PROJECT_ID: ${{ vars.TREESEED_RAILWAY_PROJECT_ID }}
688
- TREESEED_RAILWAY_ENVIRONMENT_ID: ${{ vars.TREESEED_RAILWAY_ENVIRONMENT_ID }}
689
- TREESEED_RAILWAY_WORKER_SERVICE_ID: ${{ vars.TREESEED_RAILWAY_WORKER_SERVICE_ID }}
690
- TREESEED_WORKFLOW_ACTION: monitor
691
- TREESEED_WORKFLOW_ENVIRONMENT: ${{ needs.classify.outputs.scope }}
692
- TREESEED_WORKFLOW_PROJECT: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
693
- TREESEED_WORKFLOW_PREVIEW_ID: ${{ inputs.preview_id || needs.classify.outputs.preview_id }}
694
- steps:
695
- - name: Checkout
696
- uses: actions/checkout@v4
697
- with:
698
- submodules: recursive
699
-
700
- - name: Setup Node
701
- uses: actions/setup-node@v4
702
- with:
703
- node-version: 22
704
- cache: npm
705
- cache-dependency-path: __CACHE_DEPENDENCY_PATH__
706
-
707
- - name: Install dependencies
708
- run: |
709
- node -e "const fs = require('fs'); for (const file of ['packages/sdk/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'); }"
710
- for attempt in 1 2 3; do
711
- if npm ci --ignore-scripts; then
712
- break
713
- fi
714
- if test "${attempt}" = "3"; then
715
- exit 1
716
- fi
717
- echo "npm ci failed; retrying (${attempt}/3)."
718
- sleep $((attempt * 10))
719
- done
720
- for dir in packages/sdk packages/core packages/cli; do
721
- if test -d "${dir}/.git" || git -C "${dir}" rev-parse --git-dir >/dev/null 2>&1; then
722
- git -C "${dir}" checkout -- package.json
723
- fi
724
- done
725
-
726
- - name: Build workspace package artifacts
727
- shell: bash
728
- run: |
729
- set -euo pipefail
730
- for dir in packages/sdk packages/core packages/cli; do
731
- if test -f "${dir}/package.json"; then
732
- npm --prefix "${dir}" run build:dist
733
- fi
734
- done
735
-
736
- - name: Download Treeseed deployment state
737
- uses: actions/download-artifact@v4
738
- with:
739
- name: treeseed-deploy-state-${{ needs.classify.outputs.scope }}
740
- path: .treeseed/state
741
-
742
- - name: Report Treeseed deployment state
743
- shell: bash
744
- run: |
745
- __TENANT_WORKFLOW_ACTION_COMMAND_BLOCK__
746
- __WORKING_DIRECTORY_BLOCK__