Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/skip-changeset-release-deploys.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
---
---

Stop deploying the `changeset-release/main` branch, and run that PR's Vercel e2e lanes against main's production deployment instead.
9 changes: 9 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ jobs:
needs: ci-scope
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 5
Expand DownExpand Up@@ -103,7 +104,14 @@ jobs:
name: Benchmark (${{ matrix.target.world }}, ${{ matrix.target.app }})
runs-on: ubuntu-latest
needs: ci-scope
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is nothing to wait
# for below. Benchmarking them would also be meaningless: the code is
# main's, so it would only compare main's baseline against itself.
if: >-
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
(needs.ci-scope.outputs.fast-path != 'true' ||
github.event_name == 'workflow_dispatch')
Expand DownExpand Up@@ -185,6 +193,7 @@ jobs:
if: >-
always() && !cancelled() &&
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'changeset-release/') &&
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
needs.ci-scope.outputs.fast-path != 'true'
timeout-minutes: 10
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/docs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,13 @@ jobs:
docs-preview-smoke:
name: Docs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. Their docs content is identical to main's, which this job
# already checked against production on the push that produced the bump.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 5
permissions:
id-token: write
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/tarballs-checks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,13 @@ jobs:
tarballs-preview-smoke:
name: Tarballs Preview Smoke Checks
runs-on: ubuntu-latest
# `changeset-release/*` PRs are not deployed (every project's vercel.json
# sets `git.deploymentEnabled` false for that branch, because the branch is
# force-pushed to main's HEAD SHA and a same-SHA preview deployment
# clobbers the per-SHA Vercel commit status), so there is no preview to
# smoke-test. The version-bumped tarballs get this same check on the push
# to main that follows the version PR merge.
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
75 changes: 62 additions & 13 deletions .github/workflows/tests.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,15 +379,43 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# `changeset-release/*` PRs (the changesets "Version Packages" PR) are
# deliberately not deployed: the branch is force-pushed and can point at
# main's HEAD SHA, and Vercel keeps one commit status per project per
# SHA, so a same-SHA preview deployment overwrites the production one
# that the step below reads the deployment ID from. Every project's
# vercel.json therefore sets `git.deploymentEnabled` false for that
# branch, which leaves these PRs with no deployment of their own to wait
# for. Their content is main plus a version-bump commit, so they run
# against the production deployment main already produced instead.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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' }}

# The base SHA, not the PR head: that is the main commit whose
# production deployment carries the code under test. Waiting on it also
# means a production build still in flight is waited out instead of
# testing whatever happens to be aliased to production. The commit-status
# ID this action reads is unambiguous for main SHAs once this repo stops
# deploying `changeset-release/main` (see above) — that branch was the
# only one that ever deployed a commit main also deployed.
- name: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: ${{ matrix.app.project-slug }}
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- name: Record E2E start time
id: e2eStart
run: echo "ms=$(($(date +%s) * 1000))" >> "$GITHUB_OUTPUT"
Expand All@@ -396,10 +424,12 @@ jobs:
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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: ${{ matrix.app.name }}
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: ${{ matrix.app.project-id }}
Expand All@@ -413,8 +443,11 @@ jobs:
# 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 || '' }}
# so production runs hit the public vercel-workflow.com URL. Also
# unset for changeset-release PRs: they test a production deployment
# that is wired to the production workflow-server, and the harness
# has to read run state from the same server the app writes it to.
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -423,8 +456,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
E2E_START_MS: ${{ steps.e2eStart.outputs.ms }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

Expand DownExpand Up@@ -485,30 +518,46 @@ jobs:
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'

# See the note on e2e-vercel-prod: `changeset-release/*` PRs have no
# deployment of their own and test main's production deployment.
- name: Waiting for the Vercel deployment
id: waitForDeployment
if: ${{ !startsWith(github.head_ref, 'changeset-release/') }}
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: Waiting for the Vercel deployment (changeset-release PR)
id: prodDeployment
if: ${{ startsWith(github.head_ref, 'changeset-release/') }}
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: "example-nextjs-workflow-turbopack"
timeout: 1000
check-interval: 15
environment: production
sha: ${{ github.event.pull_request.base.sha }}

- 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 }}
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url || steps.prodDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
APP_NAME: "nextjs-turbopack"
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
# changeset-release PRs test main's production deployment, so they
# must be treated as a production run everywhere downstream.
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && '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 || '' }}
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'changeset-release/') && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}

- name: Capture runtime logs on failure
if: failure()
Expand All@@ -517,8 +566,8 @@ jobs:
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 }}
WORKFLOW_VERCEL_ENV: ${{ (github.ref == 'refs/heads/main' || startsWith(github.head_ref, 'changeset-release/')) && 'production' || 'preview' }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id || steps.prodDeployment.outputs.deployment-id }}
run: node .github/scripts/fetch-e2e-runtime-logs.mjs

- name: Upload E2E results
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -225,6 +225,14 @@ Both branches trigger the release workflow (`.github/workflows/release.yml`) on

When backporting changes to `stable`, any conflicts involving docs app files (outside of `docs/content/`) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main`). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.

#### The `changeset-release/main` branch is never deployed

Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json`. **When you add a new Vercel project, add that key to its `vercel.json` too.**

The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit — and `vercel/wait-for-deployment-action`, which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.

Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way — `environment: production` with `sha` pinned to the PR's base SHA — so they test main's production deployment and run as `production`. (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main`, the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml`, `tarballs-checks.yml`, and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.

### Changesets

- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy — they always have the same version number
Expand Down
8 changes: 8 additions & 0 deletions docs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
8 changes: 8 additions & 0 deletions packages/web/vercel.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
}
}
5 changes: 5 additions & 0 deletions tarballs/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"buildCommand": "pnpm turbo build --filter=tarballs",
"installCommand": "pnpm install --frozen-lockfile",
"outputDirectory": "dist",
Expand Down
5 changes: 5 additions & 0 deletions workbench/astro/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/example/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"rewrites": [
{
"source": "/api/webhook/:webhookId",
Expand Down
5 changes: 5 additions & 0 deletions workbench/express/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/fastify/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/hono/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nest/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-turbopack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
},
Expand Down
5 changes: 5 additions & 0 deletions workbench/nextjs-webpack/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v2/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nitro-v3/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/nuxt/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/sveltekit/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/swc-playground/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
5 changes: 5 additions & 0 deletions workbench/tanstack-start/vercel.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
{
"git": {
"deploymentEnabled": {
"changeset-release/main": false
}
},
"env": {
"WORKFLOW_PUBLIC_MANIFEST": "1"
}
Expand Down
Loading
Loading