mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
1183 lines
48 KiB
YAML
1183 lines
48 KiB
YAML
name: Tests
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- "!*"
|
|
pull_request:
|
|
types:
|
|
- opened
|
|
- reopened
|
|
- synchronize
|
|
|
|
concurrency:
|
|
# Unique group for this workflow and branch
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
|
|
|
jobs:
|
|
ci-scope:
|
|
name: Detect CI Scope
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
fast-path: ${{ steps.scope.outputs.runtime-fast-path }}
|
|
validation-fast-path: ${{ steps.scope.outputs.validation-fast-path }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Classify changed files
|
|
id: scope
|
|
uses: ./.github/actions/detect-ci-scope
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# Phase 0: Update PR comment to show tests are running
|
|
pr-comment-start:
|
|
name: Create PR Comment
|
|
runs-on: ubuntu-latest
|
|
needs: ci-scope
|
|
if: github.event_name == 'pull_request' && needs.ci-scope.outputs.fast-path != 'true'
|
|
timeout-minutes: 2
|
|
|
|
steps:
|
|
- name: Find existing test comment
|
|
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
|
|
id: find-comment
|
|
with:
|
|
issue-number: ${{ github.event.pull_request.number }}
|
|
comment-author: 'github-actions[bot]'
|
|
body-includes: '<!-- e2e-test-results -->'
|
|
|
|
- name: Get existing comment body
|
|
if: steps.find-comment.outputs.comment-id != ''
|
|
id: get-comment
|
|
uses: actions/github-script@v7
|
|
env:
|
|
STARTED_AT: ${{ github.run_started_at }}
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const comment = await github.rest.issues.getComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: ${{ steps.find-comment.outputs.comment-id }}
|
|
});
|
|
const body = comment.data.body;
|
|
// Check if there are actual results (tables)
|
|
if (body.includes('|') && body.includes('Passed')) {
|
|
// Extract results section (everything after header)
|
|
const resultsSection = body
|
|
.replace(/<!-- e2e-test-results -->\n## 🧪 E2E Test Results\n\n> ⚠️ \*\*Results below are stale\*\*[^\n]*\n\n/g, '')
|
|
.replace(/<!-- e2e-test-results -->\n## 🧪 E2E Test Results\n\n/g, '')
|
|
.replace(/⏳ \*\*Tests are running\.\.\.\*\*\n\n---\n_Started at:[^_]*_\n\n---\n\n/g, '')
|
|
.replace(/⏳ \*\*Tests are running\.\.\.\*\*\n\n---\n_Started at:[^_]*_/g, '')
|
|
.trim();
|
|
if (resultsSection && resultsSection.includes('|')) {
|
|
// Write the full stale-banner message to disk and pass the
|
|
// path to the sticky-pull-request-comment action below.
|
|
// Inlining the previous results via `message:` blew past
|
|
// ARG_MAX once the matrix doubled (snapshot + replay).
|
|
const startedAt = process.env.STARTED_AT;
|
|
const message =
|
|
'<!-- e2e-test-results -->\n' +
|
|
'## 🧪 E2E Test Results\n\n' +
|
|
'> ⚠️ **Results below are stale** and not from the latest commit. This comment will be updated when CI completes on the latest run.\n\n' +
|
|
'⏳ **Tests are running...**\n\n' +
|
|
'---\n' +
|
|
`_Started at: ${startedAt}_\n\n` +
|
|
'---\n\n' +
|
|
resultsSection +
|
|
'\n';
|
|
const path = `${process.env.RUNNER_TEMP}/stale-comment.md`;
|
|
fs.writeFileSync(path, message);
|
|
core.setOutput('has-results', 'true');
|
|
core.setOutput('stale-comment-path', path);
|
|
} else {
|
|
core.setOutput('has-results', 'false');
|
|
}
|
|
} else {
|
|
core.setOutput('has-results', 'false');
|
|
}
|
|
|
|
- name: Create new test comment
|
|
if: steps.find-comment.outputs.comment-id == ''
|
|
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
|
|
with:
|
|
header: e2e-test-results
|
|
message: |
|
|
<!-- e2e-test-results -->
|
|
## 🧪 E2E Test Results
|
|
|
|
⏳ **Tests are running...**
|
|
|
|
This comment will be updated with the results when the tests complete.
|
|
|
|
---
|
|
_Started at: ${{ github.run_started_at }}_
|
|
|
|
- name: Update existing test comment with stale warning
|
|
if: steps.find-comment.outputs.comment-id != '' && steps.get-comment.outputs.has-results == 'true'
|
|
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
|
|
with:
|
|
header: e2e-test-results
|
|
path: ${{ steps.get-comment.outputs.stale-comment-path }}
|
|
|
|
- name: Update existing test comment without results
|
|
if: steps.find-comment.outputs.comment-id != '' && steps.get-comment.outputs.has-results != 'true'
|
|
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
|
|
with:
|
|
header: e2e-test-results
|
|
message: |
|
|
<!-- e2e-test-results -->
|
|
## 🧪 E2E Test Results
|
|
|
|
⏳ **Tests are running...**
|
|
|
|
This comment will be updated with the results when the tests complete.
|
|
|
|
---
|
|
_Started at: ${{ github.run_started_at }}_
|
|
|
|
unit:
|
|
name: Unit Tests (${{ matrix.os }})
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 30
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.validation-fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, windows-latest]
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
setup-rust: 'true'
|
|
install-args: '--ignore-scripts'
|
|
build-packages: 'false'
|
|
|
|
- name: Run Unit Tests
|
|
run: pnpm test --filter='!./docs' --filter='!./workbench/vitest'
|
|
|
|
serializable-revivers:
|
|
name: Serializable Reviver Compatibility
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.validation-fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-args: '--ignore-scripts'
|
|
build-packages: 'false'
|
|
|
|
- name: Build reviver packages
|
|
run: pnpm turbo run build --filter='@workflow/cli' --filter='@workflow/web-shared'
|
|
|
|
- name: Check web-shared and CLI revivers
|
|
run: pnpm vitest run packages/web-shared/test/serializable-revivers.test.ts
|
|
|
|
build-error-messages:
|
|
name: Node.js Module Build Errors Test
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
|
|
- name: Setup Node.js 22.x
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22.x
|
|
cache: "pnpm"
|
|
|
|
- name: Install Dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run Initial Build
|
|
run: pnpm turbo run build --filter='!./workbench/*'
|
|
|
|
- name: Generate Workflows Registry
|
|
run: node workbench/scripts/generate-workflows-registry.js workbench/nextjs-turbopack/workflows workbench/nextjs-turbopack/_workflows.ts
|
|
|
|
- name: Run Build Error Tests
|
|
run: pnpm vitest run packages/core/e2e/build-errors.test.ts
|
|
env:
|
|
APP_NAME: "nextjs-turbopack"
|
|
|
|
# Regression test for the o2flow beta.26 incident: hook.resume() from a
|
|
# plain API route must resolve the workflow world inside an isolated
|
|
# (lambda-like) route bundle. Runs in this job because it also performs
|
|
# a production Turbopack build of the nextjs-turbopack workbench.
|
|
- name: Run Route Bundle Isolation Tests
|
|
run: pnpm vitest run packages/core/e2e/route-bundle-isolation.test.ts
|
|
env:
|
|
APP_NAME: "nextjs-turbopack"
|
|
|
|
vitest-plugin:
|
|
name: Vitest Plugin Tests
|
|
runs-on: ubuntu-latest
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' }}
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
setup-rust: 'true'
|
|
install-args: '--ignore-scripts'
|
|
build-packages: 'false'
|
|
|
|
- name: Build packages
|
|
run: pnpm turbo run build --filter='!./workbench/*'
|
|
|
|
- name: Run Vitest Plugin Tests
|
|
run: pnpm test
|
|
working-directory: workbench/vitest
|
|
|
|
e2e-package-build:
|
|
name: Build Shared E2E Packages
|
|
runs-on: ubuntu-latest
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
timeout-minutes: 30
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment and build packages
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
build-packages: 'true'
|
|
|
|
- name: Upload package build artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-package-build-artifacts
|
|
# Keep this list aligned with package build outputs in turbo.json.
|
|
# upload-artifact strips the common packages/ root; consumers restore into packages/.
|
|
path: |
|
|
packages/*/dist
|
|
packages/*/.well-known
|
|
packages/*/src/version.ts
|
|
packages/swc-plugin-workflow/swc_plugin_workflow.wasm
|
|
packages/swc-plugin-workflow/build-hash.json
|
|
include-hidden-files: true
|
|
retention-days: 1
|
|
|
|
e2e-vercel-prod:
|
|
name: E2E Vercel Prod Tests (${{ matrix.app.name }})
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' }}
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
deployments: read
|
|
statuses: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
app:
|
|
- name: "example"
|
|
project-id: "prj_xWq20Dd860HHAfzMjK2Mb6TPVxMa"
|
|
project-slug: "example-workflow"
|
|
- name: "nextjs-turbopack"
|
|
project-id: "prj_yjkM7UdHliv8bfxZ1sMJQf1pMpdi"
|
|
project-slug: "example-nextjs-workflow-turbopack"
|
|
- name: "nextjs-webpack"
|
|
project-id: "prj_avRPBF3eWjh6iDNQgmhH4VOg27h0"
|
|
project-slug: "example-nextjs-workflow-webpack"
|
|
- name: "nitro"
|
|
project-id: "prj_e7DZirYdLrQKXNrlxg7KmA6ABx8r"
|
|
project-slug: "workbench-nitro-workflow"
|
|
- name: "vite"
|
|
project-id: "prj_uLIcNZNDmETulAvj5h0IcDHi5432"
|
|
project-slug: "workbench-vite-workflow"
|
|
- name: "nuxt"
|
|
project-id: "prj_oTgiz3SGX2fpZuM6E0P38Ts8de6d"
|
|
project-slug: "workbench-nuxt-workflow"
|
|
- name: "sveltekit"
|
|
project-id: "prj_MqnBLm71ceXGSnm3Fs8i8gBnI23G"
|
|
project-slug: "workbench-sveltekit-workflow"
|
|
- name: "hono"
|
|
project-id: "prj_p0GIEsfl53L7IwVbosPvi9rPSOYW"
|
|
project-slug: "workbench-hono-workflow"
|
|
- name: "express"
|
|
project-id: "prj_cCZjpBy92VRbKHHbarDMhOHtkuIr"
|
|
project-slug: "workbench-express-workflow"
|
|
- name: "fastify"
|
|
project-id: "prj_5Yap0VDQ633v998iqQ3L3aQ25Cck"
|
|
project-slug: "workbench-fastify-workflow"
|
|
- name: "nest"
|
|
project-id: "prj_AV3YrzooDhMlvfmZybqeugHRk48Y"
|
|
project-slug: "workbench-nestjs-workflow"
|
|
- name: "astro"
|
|
project-id: "prj_YDAXj3K8LM0hgejuIMhioz2yLgTI"
|
|
project-slug: "workbench-astro-workflow"
|
|
- name: "tanstack-start"
|
|
project-id: "prj_643jeVugTMq5ivsOFQHcbLG1qcnu"
|
|
project-slug: "workbench-tanstack-start-workflow"
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
build-packages: 'false'
|
|
|
|
- name: Build CLI
|
|
run: pnpm turbo run build --filter='@workflow/cli'
|
|
|
|
- name: Waiting for the Vercel deployment
|
|
id: waitForDeployment
|
|
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
|
|
with:
|
|
project-slug: ${{ matrix.app.project-slug }}
|
|
timeout: 1000
|
|
check-interval: 15
|
|
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
|
|
- name: Record E2E start time
|
|
id: e2eStart
|
|
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Run E2E Tests
|
|
run: pnpm run test:e2e --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts "--outputFile=e2e-vercel-prod-$APP_NAME.json"
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url }}
|
|
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id }}
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
|
|
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
|
|
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
|
|
WORKFLOW_VERCEL_PROJECT_SLUG: ${{ matrix.app.project-slug }}
|
|
# The trusted-sources OIDC token (x-vercel-trusted-oidc-idp-token)
|
|
# is minted on demand inside `scripts/trusted-sources-headers.mjs`
|
|
# via the runner's ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN env vars
|
|
# (exposed when `permissions: id-token: write` is set on the job),
|
|
# and re-minted before its 5-minute expiry. This lets long e2e
|
|
# suites keep a fresh token throughout the run instead of using
|
|
# a single pre-minted token that would expire mid-suite.
|
|
# See: https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources
|
|
# Point PRs at the protected workflow-server preview; unset on main
|
|
# so production runs hit the public vercel-workflow.com URL.
|
|
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}
|
|
|
|
- name: Capture runtime logs on failure
|
|
if: failure()
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
|
|
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
|
|
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
|
|
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id }}
|
|
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
|
|
run: node .github/scripts/fetch-e2e-runtime-logs.mjs
|
|
|
|
- name: Generate E2E summary
|
|
if: always()
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Vercel Prod ($APP_NAME)" >> $GITHUB_STEP_SUMMARY || true
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-vercel-prod-${{ matrix.app.name }}
|
|
path: |
|
|
e2e-vercel-prod-${{ matrix.app.name }}.json
|
|
e2e-metadata-${{ matrix.app.name }}-vercel.json
|
|
e2e-failures-${{ matrix.app.name }}-vercel.json
|
|
e2e-diagnostics-${{ matrix.app.name }}-vercel.json
|
|
e2e-runtime-logs-${{ matrix.app.name }}-vercel.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
e2e-vercel-multi-region:
|
|
# Vercel-specific multi-region routing suite (start()'s `region`
|
|
# option). Deliberately separate from e2e-vercel-prod: that job runs
|
|
# the shared suite as a matrix across all worlds/frameworks, while
|
|
# this functionality only exists for @workflow/world-vercel and only
|
|
# the nextjs-turbopack workbench is deployed multi-region
|
|
# (workbench/nextjs-turbopack/vercel.json pins iad1+sfo1+fra1).
|
|
name: E2E Vercel Multi-Region Tests (nextjs-turbopack)
|
|
runs-on: ubuntu-latest
|
|
# 19 regions: the implicit-route cases pay one cold start each,
|
|
# sequentially.
|
|
timeout-minutes: 35
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' }}
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
deployments: read
|
|
statuses: read
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
build-packages: 'false'
|
|
|
|
- name: Build CLI
|
|
run: pnpm turbo run build --filter='@workflow/cli'
|
|
|
|
- name: Waiting for the Vercel deployment
|
|
id: waitForDeployment
|
|
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
|
|
with:
|
|
project-slug: "example-nextjs-workflow-turbopack"
|
|
timeout: 1000
|
|
check-interval: 15
|
|
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
|
|
- name: Run Multi-Region E2E Tests
|
|
run: pnpm vitest run packages/core/e2e/e2e-region.test.ts --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts "--outputFile=e2e-vercel-multi-region-$APP_NAME.json"
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url }}
|
|
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id }}
|
|
APP_NAME: "nextjs-turbopack"
|
|
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
|
|
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
|
|
WORKFLOW_VERCEL_PROJECT: "prj_yjkM7UdHliv8bfxZ1sMJQf1pMpdi"
|
|
WORKFLOW_VERCEL_PROJECT_SLUG: "example-nextjs-workflow-turbopack"
|
|
# See the note on e2e-vercel-prod: PRs point at the protected
|
|
# workflow-server preview; unset on main for production.
|
|
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}
|
|
|
|
- name: Capture runtime logs on failure
|
|
if: failure()
|
|
env:
|
|
APP_NAME: "nextjs-turbopack"
|
|
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
|
|
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
|
|
WORKFLOW_VERCEL_PROJECT: "prj_yjkM7UdHliv8bfxZ1sMJQf1pMpdi"
|
|
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
|
|
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id }}
|
|
run: node .github/scripts/fetch-e2e-runtime-logs.mjs
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-vercel-multi-region-nextjs-turbopack
|
|
path: |
|
|
e2e-vercel-multi-region-nextjs-turbopack.json
|
|
e2e-metadata-nextjs-turbopack-vercel.json
|
|
e2e-failures-nextjs-turbopack-vercel.json
|
|
e2e-diagnostics-nextjs-turbopack-vercel.json
|
|
e2e-runtime-logs-nextjs-turbopack-vercel.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
getTestMatrix:
|
|
name: Get Test Matrix
|
|
runs-on: ubuntu-latest
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-dependencies: 'false'
|
|
build-packages: 'false'
|
|
cache-pnpm: 'false'
|
|
|
|
- id: set-matrix
|
|
run: |
|
|
MATRIX_JSON="$(node ./scripts/create-test-matrix.mjs | jq -c .)"
|
|
echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT"
|
|
|
|
e2e-local-dev:
|
|
name: E2E Local Dev Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
needs: [ci-scope, getTestMatrix, e2e-package-build]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{fromJson(needs.getTestMatrix.outputs.matrix)}}
|
|
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-dependencies: 'false'
|
|
build-packages: 'false'
|
|
|
|
- name: Setup canary
|
|
if: ${{ matrix.app.canary }}
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
run: |
|
|
cat packages/next/package.json | jq '.dependencies.next|="16.3.0-canary.2"' > packages/next/package.json.new && mv packages/next/package.json.new packages/next/package.json
|
|
cat "workbench/$APP_NAME/package.json" | jq '.dependencies.next|="16.3.0-canary.2"' > "workbench/$APP_NAME/package.json.new" && mv "workbench/$APP_NAME/package.json.new" "workbench/$APP_NAME/package.json"
|
|
pnpm install --no-frozen-lockfile
|
|
|
|
- name: Install Dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Download shared package builds
|
|
if: ${{ !matrix.app.canary }}
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: e2e-package-build-artifacts
|
|
path: packages
|
|
|
|
- name: Run Initial Build for Next.js canary
|
|
if: ${{ matrix.app.canary }}
|
|
run: pnpm turbo run build --filter='!./workbench/*'
|
|
|
|
- name: Prepare workbench path
|
|
id: prepare-workbench
|
|
uses: ./.github/actions/prepare-workbench-path
|
|
with:
|
|
app-name: ${{ matrix.app.name }}
|
|
|
|
- name: Run E2E Tests
|
|
run: |
|
|
export DEV_SERVER_LOG_PATH="$GITHUB_WORKSPACE/dev-server-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.log"
|
|
rm -f "$DEV_SERVER_LOG_PATH"
|
|
(cd "$WORKBENCH_APP_PATH" && pnpm dev 2>&1 | tee "$DEV_SERVER_LOG_PATH") &
|
|
echo "starting tests in 10 seconds" && sleep 10
|
|
pnpm vitest run packages/core/e2e/dev.test.ts; sleep 10
|
|
pnpm run test:e2e --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKBENCH_APP_PATH: ${{ steps.prepare-workbench.outputs.workbench_app_path }}
|
|
DEPLOYMENT_URL: "http://localhost:${{ matrix.app.name == 'sveltekit' && '5173' || (matrix.app.name == 'astro' && '4321' || '3000') }}"
|
|
DEV_TEST_CONFIG: ${{ toJSON(matrix.app) }}
|
|
WORKFLOW_DEV_HMR_LOGS: "1"
|
|
NEXT_CANARY: ${{ matrix.app.canary && '1' || '' }}
|
|
|
|
- name: Generate E2E summary
|
|
if: always()
|
|
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Dev (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
|
|
path: e2e-local-dev-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
e2e-local-prod:
|
|
name: E2E Local Prod Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
needs: [ci-scope, getTestMatrix, e2e-package-build]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{fromJson(needs.getTestMatrix.outputs.matrix)}}
|
|
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-dependencies: 'false'
|
|
build-packages: 'false'
|
|
|
|
- name: Setup canary
|
|
if: ${{ matrix.app.canary }}
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
run: |
|
|
cat packages/next/package.json | jq '.dependencies.next|="16.3.0-canary.2"' > packages/next/package.json.new && mv packages/next/package.json.new packages/next/package.json
|
|
cat "workbench/$APP_NAME/package.json" | jq '.dependencies.next|="16.3.0-canary.2"' > "workbench/$APP_NAME/package.json.new" && mv "workbench/$APP_NAME/package.json.new" "workbench/$APP_NAME/package.json"
|
|
pnpm install --no-frozen-lockfile
|
|
|
|
- name: Install Dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Download shared package builds
|
|
if: ${{ !matrix.app.canary }}
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: e2e-package-build-artifacts
|
|
path: packages
|
|
|
|
- name: Run Initial Build for Next.js canary
|
|
if: ${{ matrix.app.canary }}
|
|
run: pnpm turbo run build --filter='!./workbench/*'
|
|
|
|
- name: Prepare workbench path
|
|
id: prepare-workbench
|
|
uses: ./.github/actions/prepare-workbench-path
|
|
with:
|
|
app-name: ${{ matrix.app.name }}
|
|
|
|
- name: Run Build Tests
|
|
run: pnpm vitest run packages/core/e2e/local-build.test.ts
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKBENCH_APP_PATH: ${{ steps.prepare-workbench.outputs.workbench_app_path }}
|
|
|
|
- name: Run E2E Tests
|
|
run: |
|
|
export PROD_SERVER_LOG_PATH="$GITHUB_WORKSPACE/prod-server-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.log"
|
|
(cd "$WORKBENCH_APP_PATH" && pnpm start 2>&1 | tee "$PROD_SERVER_LOG_PATH") &
|
|
echo "starting tests in 10 seconds" && sleep 10
|
|
pnpm run test:e2e --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKBENCH_APP_PATH: ${{ steps.prepare-workbench.outputs.workbench_app_path }}
|
|
DEPLOYMENT_URL: "http://localhost:${{ matrix.app.name == 'sveltekit' && '4173' || (matrix.app.name == 'astro' && '4321' || '3000') }}"
|
|
NEXT_CANARY: ${{ matrix.app.canary && '1' || '' }}
|
|
|
|
- name: Generate E2E summary
|
|
if: always()
|
|
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Prod (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
|
|
path: e2e-local-prod-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
e2e-local-postgres:
|
|
name: E2E Local Postgres Tests (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
needs: [ci-scope, getTestMatrix, e2e-package-build]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{fromJson(needs.getTestMatrix.outputs.matrix)}}
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:18-alpine
|
|
env:
|
|
POSTGRES_USER: world
|
|
POSTGRES_PASSWORD: world
|
|
POSTGRES_DB: world
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
WORKFLOW_TARGET_WORLD: "@workflow/world-postgres"
|
|
WORKFLOW_POSTGRES_URL: "postgres://world:world@localhost:5432/world"
|
|
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-dependencies: 'false'
|
|
build-packages: 'false'
|
|
|
|
- name: Setup canary
|
|
if: ${{ matrix.app.canary }}
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
run: |
|
|
cat packages/next/package.json | jq '.dependencies.next|="16.3.0-canary.2"' > packages/next/package.json.new && mv packages/next/package.json.new packages/next/package.json
|
|
cat "workbench/$APP_NAME/package.json" | jq '.dependencies.next|="16.3.0-canary.2"' > "workbench/$APP_NAME/package.json.new" && mv "workbench/$APP_NAME/package.json.new" "workbench/$APP_NAME/package.json"
|
|
pnpm install --no-frozen-lockfile
|
|
|
|
- name: Install Dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Download shared package builds
|
|
if: ${{ !matrix.app.canary }}
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: e2e-package-build-artifacts
|
|
path: packages
|
|
|
|
- name: Run Initial Build for Next.js canary
|
|
if: ${{ matrix.app.canary }}
|
|
run: pnpm turbo run build --filter='!./workbench/*'
|
|
|
|
- name: Setup PostgreSQL Database
|
|
run: ./packages/world-postgres/bin/setup.js
|
|
|
|
- name: Prepare workbench path
|
|
id: prepare-workbench
|
|
uses: ./.github/actions/prepare-workbench-path
|
|
with:
|
|
app-name: ${{ matrix.app.name }}
|
|
|
|
- name: Run Build Tests
|
|
run: pnpm vitest run packages/core/e2e/local-build.test.ts
|
|
env:
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKBENCH_APP_PATH: ${{ steps.prepare-workbench.outputs.workbench_app_path }}
|
|
|
|
- name: Run E2E Tests
|
|
run: |
|
|
export PROD_SERVER_LOG_PATH="$GITHUB_WORKSPACE/prod-server-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.log"
|
|
(cd "$WORKBENCH_APP_PATH" && pnpm start 2>&1 | tee "$PROD_SERVER_LOG_PATH") &
|
|
echo "starting tests in 10 seconds" && sleep 10
|
|
pnpm run test:e2e --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
APP_NAME: ${{ matrix.app.name }}
|
|
WORKBENCH_APP_PATH: ${{ steps.prepare-workbench.outputs.workbench_app_path }}
|
|
DEPLOYMENT_URL: "http://localhost:${{ matrix.app.name == 'sveltekit' && '4173' || (matrix.app.name == 'astro' && '4321' || '3000') }}"
|
|
NEXT_CANARY: ${{ matrix.app.canary && '1' || '' }}
|
|
|
|
- name: Generate E2E summary
|
|
if: always()
|
|
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Local Postgres (${{ matrix.app.name }} - ${{ matrix.app.runLabel }})" >> $GITHUB_STEP_SUMMARY || true
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}
|
|
path: e2e-local-postgres-${{ matrix.app.name }}-${{ matrix.app.artifactSuffix }}.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
e2e-windows:
|
|
name: E2E Windows Tests
|
|
runs-on: windows-latest
|
|
timeout-minutes: 30
|
|
needs: ci-scope
|
|
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
env:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
WORKFLOW_PUBLIC_MANIFEST: '1'
|
|
|
|
steps:
|
|
- name: Checkout Repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup Rust
|
|
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1.16.1
|
|
with:
|
|
toolchain: stable
|
|
target: wasm32-unknown-unknown
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
|
|
- name: Setup Node.js 22.x
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22.x
|
|
cache: "pnpm"
|
|
|
|
- name: Install Dependencies
|
|
run: pnpm install --frozen-lockfile --ignore-scripts
|
|
|
|
- name: Run Initial Build
|
|
run: pnpm turbo run build --filter='!./workbench/*' --filter='!./docs'
|
|
|
|
- name: Run E2E Tests (Next.js)
|
|
run: |
|
|
cd workbench/nextjs-turbopack
|
|
$logFile = "$env:GITHUB_WORKSPACE/nextjs-server.log"
|
|
$env:DEV_SERVER_LOG_PATH = $logFile
|
|
$job = Start-Job -ScriptBlock { Set-Location $using:PWD; pnpm dev *>&1 | Tee-Object -FilePath $using:logFile }
|
|
Start-Sleep -Seconds 15
|
|
cd ../..
|
|
|
|
# Fail-fast guards: if the Next.js dev server gets into a corrupted
|
|
# state during HMR (a recurring Turbopack-on-Windows issue where
|
|
# `packages/core/dist/*.js` becomes "MODULE_UNPARSABLE" and every
|
|
# subsequent request returns 500), the e2e suite would otherwise burn
|
|
# the full 30-minute job window polling stuck workflow runs before
|
|
# finally being cancelled. Below we (1) bail out if `dev.test.ts`
|
|
# fails, since that's the first thing to start hitting 500s, and
|
|
# (2) probe the server before the long e2e run to catch any other
|
|
# silent breakage.
|
|
#
|
|
# Get-DevServerStatus returns the HTTP status code of GET /api/chat,
|
|
# or 0 if the request never produced a response. /api/chat is a
|
|
# POST-only endpoint, so a healthy dev server responds with 405
|
|
# Method Not Allowed; we only treat 5xx (and no-response) as
|
|
# unhealthy.
|
|
function Get-DevServerStatus {
|
|
try {
|
|
$resp = Invoke-WebRequest -Uri "http://localhost:3000/api/chat" -UseBasicParsing -TimeoutSec 15 -ErrorAction Stop
|
|
return [int]$resp.StatusCode
|
|
} catch {
|
|
if ($_.Exception.Response) {
|
|
try { return [int]$_.Exception.Response.StatusCode } catch { return 0 }
|
|
}
|
|
return 0
|
|
}
|
|
}
|
|
|
|
$devExit = 0
|
|
pnpm vitest run packages/core/e2e/dev.test.ts
|
|
$devExit = $LASTEXITCODE
|
|
if ($devExit -ne 0) {
|
|
Write-Host "::warning title=dev.test.ts failed::dev.test.ts exited with code $devExit. Skipping the remainder of the e2e suite to avoid waiting for the 30-minute job timeout."
|
|
Stop-Job $job -ErrorAction SilentlyContinue
|
|
exit $devExit
|
|
}
|
|
|
|
# Sanity-check the server before kicking off the long e2e suite. This
|
|
# catches the case where Turbopack quietly went sideways (e.g. lost
|
|
# track of files in `packages/core/dist` after HMR on Windows) and is
|
|
# returning 500 for every request. Without this check the e2e suite
|
|
# would burn the full 30-minute job window polling stuck workflow
|
|
# runs before getting cancelled.
|
|
$status = Get-DevServerStatus
|
|
Write-Host "[health-check:pre-e2e] GET /api/chat -> $status"
|
|
if ($status -eq 0 -or $status -ge 500) {
|
|
Write-Host "::error title=Next.js dev server unhealthy::Dev server returned $status before e2e tests. Aborting to avoid the 30-minute job timeout. See the 'Print Next.js server logs' step for the underlying Turbopack error."
|
|
Stop-Job $job -ErrorAction SilentlyContinue
|
|
exit 1
|
|
}
|
|
|
|
pnpm run test:e2e --reporter=verbose --reporter=json --reporter=./packages/core/e2e/github-reporter.ts --outputFile=e2e-windows-nextjs-turbopack.json
|
|
$e2eExit = $LASTEXITCODE
|
|
Stop-Job $job -ErrorAction SilentlyContinue
|
|
exit $e2eExit
|
|
shell: powershell
|
|
env:
|
|
NODE_OPTIONS: "--enable-source-maps"
|
|
APP_NAME: "nextjs-turbopack"
|
|
DEPLOYMENT_URL: "http://localhost:3000"
|
|
# Use a real workflow file for the Windows HMR test. Most of this
|
|
# workbench's workflows are symlinks into workbench/example, and
|
|
# Windows/Turbopack can rebuild from the symlink path while still
|
|
# serving the previous module contents from the realpath cache.
|
|
DEV_TEST_CONFIG: '{"generatedStepRegistrationPath":"app/.well-known/workflow/v1/flow/__step_registrations.js","generatedWorkflowPath":"app/.well-known/workflow/v1/flow/route.js","apiFilePath":"app/api/chat/route.ts","apiFileImportPath":"../../..","port":3000,"testWorkflowFile":"96_many_steps.ts"}'
|
|
DEV_SERVER_LOG_PATH: "${{ github.workspace }}/nextjs-server.log"
|
|
WORKFLOW_DEV_HMR_LOGS: "1"
|
|
|
|
- name: Print Next.js server logs
|
|
if: always()
|
|
shell: powershell
|
|
run: |
|
|
$logFile = "$env:GITHUB_WORKSPACE/nextjs-server.log"
|
|
if (Test-Path $logFile) {
|
|
Write-Host "=== Next.js Server Logs ===" -ForegroundColor Cyan
|
|
Get-Content $logFile
|
|
Write-Host "=== End of Server Logs ===" -ForegroundColor Cyan
|
|
} else {
|
|
Write-Host "No server log file found at $logFile" -ForegroundColor Yellow
|
|
}
|
|
|
|
- name: Generate E2E summary
|
|
if: always()
|
|
shell: bash
|
|
run: node .github/scripts/aggregate-e2e-results.js . --job-name "E2E Windows (nextjs-turbopack)" >> $GITHUB_STEP_SUMMARY || true
|
|
|
|
- name: Upload E2E results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-results-windows-nextjs-turbopack
|
|
path: e2e-windows-nextjs-turbopack.json
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
- name: Upload Next.js server logs
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nextjs-server-logs-windows
|
|
path: nextjs-server.log
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
# Community World E2E Tests (dynamically generated from worlds-manifest.json)
|
|
# Disabled on main: community worlds target spec v2 and do not yet support the
|
|
# CBOR queue transport used by world-vercel (see #1627 / #1658). They continue
|
|
# to run on `stable`, where spec v2 is still the primary compat target. Once
|
|
# the community worlds (mizzle-dev/workflow-worlds) ship CBOR support we can
|
|
# re-enable these jobs here.
|
|
getCommunityWorldsMatrix:
|
|
name: Get Community Worlds Matrix
|
|
runs-on: ubuntu-latest
|
|
if: false
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Setup environment
|
|
uses: ./.github/actions/setup-workflow-dev
|
|
with:
|
|
install-dependencies: 'false'
|
|
build-packages: 'false'
|
|
cache-pnpm: 'false'
|
|
|
|
- id: set-matrix
|
|
run: |
|
|
MATRIX_JSON="$(node ./scripts/create-community-worlds-matrix.mjs | jq -c .)"
|
|
echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT"
|
|
|
|
e2e-community:
|
|
name: E2E Community World (${{ matrix.world.name }})
|
|
if: false
|
|
needs: getCommunityWorldsMatrix
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJson(needs.getCommunityWorldsMatrix.outputs.matrix) }}
|
|
uses: ./.github/workflows/e2e-community-world.yml
|
|
with:
|
|
world-id: ${{ matrix.world.id }}
|
|
world-name: ${{ matrix.world.name }}
|
|
world-package: ${{ matrix.world.package }}
|
|
package-version: ${{ matrix.world.version }}
|
|
service-type: ${{ matrix.world.service-type }}
|
|
env-vars: ${{ matrix.world.env-vars }}
|
|
services: ${{ matrix.world.services }}
|
|
secrets: inherit
|
|
|
|
# Final job: Aggregate all E2E results and update PR comment
|
|
summary:
|
|
name: E2E Summary
|
|
runs-on: ubuntu-latest
|
|
needs: [ci-scope, e2e-vercel-prod, e2e-local-dev, e2e-local-prod, e2e-local-postgres, e2e-windows]
|
|
if: always() && !cancelled() && needs.ci-scope.outputs.fast-path != 'true'
|
|
timeout-minutes: 10
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Download all E2E artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: e2e-results-*
|
|
path: e2e-results
|
|
merge-multiple: true
|
|
|
|
- name: List downloaded files
|
|
run: find e2e-results -type f -name "*.json" | sort || echo "No files found"
|
|
|
|
- name: Aggregate E2E results
|
|
id: aggregate
|
|
run: |
|
|
node .github/scripts/aggregate-e2e-results.js e2e-results --mode aggregate --run-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | tee e2e-summary.md >> $GITHUB_STEP_SUMMARY
|
|
|
|
- name: Update PR comment with results
|
|
if: github.event_name == 'pull_request'
|
|
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
|
|
with:
|
|
header: e2e-test-results
|
|
path: e2e-summary.md
|
|
|
|
# Final required check: passes only when unit + all E2E jobs succeed.
|
|
# Community worlds are intentionally excluded — they are disabled on main.
|
|
e2e-required-check:
|
|
name: E2E Required Check
|
|
runs-on: ubuntu-latest
|
|
needs: [ci-scope, unit, e2e-package-build, e2e-vercel-prod, e2e-local-dev, e2e-local-prod, e2e-local-postgres, e2e-windows]
|
|
if: always()
|
|
timeout-minutes: 5
|
|
|
|
steps:
|
|
- name: Validate E2E job statuses
|
|
env:
|
|
UNIT_STATUS: ${{ needs.unit.result }}
|
|
BUILD_STATUS: ${{ needs.e2e-package-build.result }}
|
|
VERCEL_STATUS: ${{ needs.e2e-vercel-prod.result }}
|
|
LOCAL_DEV_STATUS: ${{ needs.e2e-local-dev.result }}
|
|
LOCAL_PROD_STATUS: ${{ needs.e2e-local-prod.result }}
|
|
POSTGRES_STATUS: ${{ needs.e2e-local-postgres.result }}
|
|
WINDOWS_STATUS: ${{ needs.e2e-windows.result }}
|
|
FAST_PATH: ${{ needs.ci-scope.outputs.fast-path }}
|
|
VALIDATION_FAST_PATH: ${{ needs.ci-scope.outputs.validation-fast-path }}
|
|
HAS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
|
|
run: |
|
|
FAILED_JOBS=()
|
|
|
|
if [[ "$FAST_PATH" == "true" ]]; then
|
|
if [[ "$VALIDATION_FAST_PATH" != "true" && "$HAS_LABEL" != "true" && "$UNIT_STATUS" != "success" ]]; then
|
|
echo "UI-only fast path still requires unit tests; unit status was $UNIT_STATUS."
|
|
exit 1
|
|
fi
|
|
echo "Docs/UI-only change detected - no runtime E2E lanes are required."
|
|
exit 0
|
|
fi
|
|
|
|
# When workflow-server-test label is present, only check vercel-prod (others should be skipped)
|
|
# Otherwise, all jobs must succeed
|
|
if [[ "$HAS_LABEL" == "true" ]]; then
|
|
echo "workflow-server-test label detected - only checking required jobs"
|
|
[[ "$VERCEL_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-vercel-prod ($VERCEL_STATUS)")
|
|
|
|
# Verify other jobs were actually skipped
|
|
[[ "$UNIT_STATUS" == "skipped" ]] || echo "Warning: unit was not skipped ($UNIT_STATUS)"
|
|
[[ "$LOCAL_DEV_STATUS" == "skipped" ]] || echo "Warning: e2e-local-dev was not skipped ($LOCAL_DEV_STATUS)"
|
|
[[ "$LOCAL_PROD_STATUS" == "skipped" ]] || echo "Warning: e2e-local-prod was not skipped ($LOCAL_PROD_STATUS)"
|
|
[[ "$POSTGRES_STATUS" == "skipped" ]] || echo "Warning: e2e-local-postgres was not skipped ($POSTGRES_STATUS)"
|
|
[[ "$WINDOWS_STATUS" == "skipped" ]] || echo "Warning: e2e-windows was not skipped ($WINDOWS_STATUS)"
|
|
else
|
|
echo "Standard PR - checking all jobs"
|
|
[[ "$UNIT_STATUS" == "success" ]] || FAILED_JOBS+=("unit ($UNIT_STATUS)")
|
|
[[ "$BUILD_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-package-build ($BUILD_STATUS)")
|
|
[[ "$VERCEL_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-vercel-prod ($VERCEL_STATUS)")
|
|
[[ "$LOCAL_DEV_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-local-dev ($LOCAL_DEV_STATUS)")
|
|
[[ "$LOCAL_PROD_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-local-prod ($LOCAL_PROD_STATUS)")
|
|
[[ "$POSTGRES_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-local-postgres ($POSTGRES_STATUS)")
|
|
[[ "$WINDOWS_STATUS" == "success" ]] || FAILED_JOBS+=("e2e-windows ($WINDOWS_STATUS)")
|
|
fi
|
|
|
|
if [[ ${#FAILED_JOBS[@]} -gt 0 ]]; then
|
|
echo "The following E2E jobs did not succeed:"
|
|
printf '%s\n' "${FAILED_JOBS[@]}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "All required E2E jobs succeeded."
|
|
|
|
# Publish E2E results to GitHub Pages (main branch only)
|
|
publish-results:
|
|
name: Publish E2E Results
|
|
runs-on: ubuntu-latest
|
|
needs: [summary]
|
|
# Use always() because summary uses always() - without it this job gets skipped when any E2E test fails
|
|
if: always() && !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
timeout-minutes: 5
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
|
|
- name: Download all E2E artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: e2e-results-*
|
|
path: e2e-results
|
|
merge-multiple: true
|
|
|
|
- name: Generate docs data
|
|
run: |
|
|
mkdir -p docs-data
|
|
node .github/scripts/generate-docs-data.js \
|
|
--type e2e \
|
|
--results-dir e2e-results \
|
|
--output docs-data/e2e-results.json \
|
|
--commit "${{ github.sha }}" \
|
|
--branch "${{ github.ref_name }}"
|
|
|
|
- name: Deploy to GitHub Pages
|
|
uses: ./.github/actions/publish-to-gh-pages
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
source-dir: ./docs-data
|
|
destination-dir: ci
|