diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 75b57bee7..7ee0e8414 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -2,14 +2,20 @@ name: Master # The single master-push pipeline: deploy first, verify production after. # -# changes ─┬─► deploy-authoring ─┐ -# └─► deploy-api ───────┴─► smoke (@smoke e2e against prod) +# changes ─► build ─┬─► deploy-authoring ─┐ +# └─► deploy-api ───────┴─► smoke (@smoke e2e against prod) +# +# One build, artifacts reused (Dan, #189 review): the workspace packages and +# the authoring app are built once, and the deploy jobs only download what +# they ship — before this, a push touching runner/packages/** installed and +# built the workspace twice, once per deploy job. # # No test gate before the deploys, deliberately (Dan, #184 review): the full -# suite already ran on the PR, each deploy job runs its own `pnpm build` (a -# broken build cannot reach wrangler), and what a master push needs verified -# is PRODUCTION — which only exists after the deploy. The smoke job is that -# verification; the weekly e2e-live canary covers the rest. The compensating +# suite already ran on the PR, the shared `build` job below still has to +# succeed before either deploy runs (a broken build cannot reach wrangler), +# and what a master push needs verified is PRODUCTION — which only exists +# after the deploy. The smoke job is that verification; the nightly e2e-live +# canary covers the rest (03:00 UTC). The compensating # control for merge skew (a PR tested before master moved) is branch # protection's "require branches to be up to date" — a repo setting, not a # workflow. @@ -84,9 +90,10 @@ jobs: echo "authoring=$authoring" >> "$GITHUB_OUTPUT" echo "api=$api" >> "$GITHUB_OUTPUT" - deploy-authoring: + # One install, one workspace build — shared by both deploys via artifacts. + build: needs: [changes] - if: needs.changes.outputs.authoring == 'true' + if: needs.changes.outputs.authoring == 'true' || needs.changes.outputs.api == 'true' runs-on: ubuntu-latest defaults: run: @@ -106,19 +113,57 @@ jobs: - run: pnpm install --frozen-lockfile - # Build workspace packages, then the authoring app. VITE_API_BASE comes - # from apps/authoring/.env.production (committed) so it targets prod. - run: pnpm build - # SENTRY_* are only set here, on the deploying build. PR CI (ci.yml) - # gets no token, so PR builds neither emit source maps nor upload a - # release — see apps/authoring/vite.config.ts. - - run: pnpm --filter @handsontable/demo-authoring build + + - name: Upload the runtime build + uses: actions/upload-artifact@v4 + with: + name: runtime-dist + path: runner/packages/runtime/dist/ + retention-days: 1 + if-no-files-found: error + + # The authoring app builds here too — the deploy job then only ships it. + # VITE_API_BASE comes from apps/authoring/.env.production (committed) so + # it targets prod. SENTRY_* are only set on this deploying build; PR CI + # (ci.yml) gets no token, so PR builds neither emit source maps nor + # upload a release — see apps/authoring/vite.config.ts. + - name: Build authoring (skipped when only the api deploys) + if: needs.changes.outputs.authoring == 'true' + run: pnpm --filter @handsontable/demo-authoring build env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ vars.SENTRY_ORG }} SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }} GITHUB_SHA: ${{ github.sha }} + - name: Upload the authoring build + if: needs.changes.outputs.authoring == 'true' + uses: actions/upload-artifact@v4 + with: + name: authoring-dist + path: runner/apps/authoring/dist/ + retention-days: 1 + if-no-files-found: error + + deploy-authoring: + needs: [changes, build] + if: needs.changes.outputs.authoring == 'true' + runs-on: ubuntu-latest + defaults: + run: + working-directory: runner + steps: + - uses: actions/checkout@v4 + + - name: Download the authoring build + uses: actions/download-artifact@v4 + with: + name: authoring-dist + path: runner/apps/authoring/dist/ + + # No pnpm install: wrangler is pinned through npx and ships ./dist as + # Workers Assets — the checkout only supplies wrangler.jsonc. - name: Deploy authoring worker working-directory: runner/apps/authoring env: @@ -163,7 +208,7 @@ jobs: smoke: true deploy-api: - needs: [changes] + needs: [changes, build] if: needs.changes.outputs.api == 'true' runs-on: ubuntu-latest defaults: @@ -182,8 +227,16 @@ jobs: cache: pnpm cache-dependency-path: runner/pnpm-lock.yaml + # Install stays: `pnpm run deploy` runs the workspace's own wrangler and + # bundles the worker, which resolves @handsontable/demo-runtime from the + # artifact downloaded below instead of rebuilding it. - run: pnpm install --frozen-lockfile - - run: pnpm build + + - name: Download the runtime build + uses: actions/download-artifact@v4 + with: + name: runtime-dist + path: runner/packages/runtime/dist/ # Apply pending D1 schema changes to the remote DB before shipping code # that may depend on them. Migrations are idempotent (IF NOT EXISTS). diff --git a/runner/AGENTS.md b/runner/AGENTS.md index ffebe20ba..c1cd61069 100644 --- a/runner/AGENTS.md +++ b/runner/AGENTS.md @@ -170,7 +170,7 @@ Six workflows live in `.github/workflows/` at the repo root: | Workflow | Trigger | What it does | |----------|---------|--------------| | `ci.yml` | every PR (+ manual dispatch) | the CI DAG: presence + unit → build → authoring → e2e (in the pinned Playwright container). PRs are the only place the full suite runs — master does not repeat it. | -| `master.yml` | every push to `master` (or manual dispatch with per-target checkboxes) | deploy-first: path-gated `deploy-authoring`/`deploy-api` (each self-builds — a broken build never reaches wrangler), then one `@smoke` E2E run against prod. Merge-skew is covered by branch protection ("require branches to be up to date"), not by re-running the suite. | +| `master.yml` | every push to `master` (or manual dispatch with per-target checkboxes) | deploy-first: one shared `build` job (workspace + authoring, artifacts reused), then path-gated `deploy-authoring`/`deploy-api` ship the downloads — a broken build still never reaches wrangler — then one `@smoke` E2E run against prod. Merge-skew is covered by branch protection ("require branches to be up to date"), not by re-running the suite. | | `e2e-live.yml` | manual, nightly canary (03:00 UTC, prod + AI), or `workflow_call` with `smoke: true` from `master.yml` | everything ci.yml cannot run: live renders, container suites, the share viewer/round-trip, AI answer checks. Dispatch inputs: `base_url`, `ai`, `pkg_pr_new_ref` (DEV-2198). | | `e2e-starter-matrix.yml` | manual + nightly (01:00 UTC) | every starter × major through a live session; serialized against the global container cap. | | `import-docs.yml` | manual, or `repository_dispatch: docs-examples-sync` from the docs repo | re-imports the documentation-guide examples. |