You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Add option to overwrite branch name for deployments (#776)
* Initial plan
* feat: add branch input to override deployment branch name
Add optional branch input to allow users to override the automatically detected branch name for Cloudflare Pages deployments. This is useful for workflow_run deployments where fork PRs based on main would otherwise overwrite the production deployment.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Agent-Logs-Url: https://github.com/andykenward/github-actions-cloudflare-pages/sessions/9a8b2519-3a11-4339-9046-06aab99972a1
Co-authored-by: andykenward <4893048+andykenward@users.noreply.github.com>
* Create ripe-yaks-argue.md
Signed-off-by: Andy Kenward <4893048+andykenward@users.noreply.github.com>
* docs: improve github-environment docs
* chore: minor update
* docs: improve custom branch name
* docs: AGENTS.md update
* fix: remove peerDependencies wrangler
---------
Signed-off-by: Andy Kenward <4893048+andykenward@users.noreply.github.com>
Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com>
Co-authored-by: andykenward <4893048+andykenward@users.noreply.github.com>
Copy file name to clipboardExpand all lines: AGENTS.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ Non-negotiable. Violating these breaks the build or the type system.
30
30
31
31
**GraphQL type safety**: Inline ``graphql(/* GraphQL */ `...`)`` operations in `src/**` and `bin/**` are typed via [@graphql-codegen/client-preset](graphql.config.ts). The custom client [src/common/github/api/client.ts](src/common/github/api/client.ts) wraps fetch with `TypedDocumentString` for compile-time validation. Preview features come from [schema/github/schema.graphql](schema/github/schema.graphql).
32
32
33
-
**Cloudflare**: Runs `wrangler pages deploy` via `execAsync()` ([src/common/cloudflare/deployment/create.ts](src/common/cloudflare/deployment/create.ts#L49-L54)). Wrangler is an external (peer) dependency, not bundled. Deployment status polling and deletion use Cloudflare's REST API.
33
+
**Cloudflare**: Runs `wrangler pages deploy` via `execAsync()` ([src/common/cloudflare/deployment/create.ts](src/common/cloudflare/deployment/create.ts#L49-L54)). Wrangler is external to the bundle (esbuild `external`, [esbuild.config.js](esbuild.config.js)) and installed at runtime via `npx wrangler@<version>` — the version comes from the `wrangler-version` input or, failing that, the default in [src/common/inputs.ts](src/common/inputs.ts), which [bin/sync-versions.ts](bin/sync-versions.ts) keeps in lockstep with `devDependencies.wrangler` (the single source of truth; tests read it too). Deployment status polling and deletion use Cloudflare's REST API.
34
34
35
35
## Commands
36
36
@@ -65,8 +65,8 @@ Non-negotiable. Violating these breaks the build or the type system.
65
65
66
66
1. Add the input to [action.yml](action.yml) or [delete/action.yml](delete/action.yml).
67
67
2. Add `INPUT_KEY_*` in [input-keys.ts](input-keys.ts) (and `INPUT_KEYS_REQUIRED` if mandatory).
68
-
3. Handle it in `inputs.ts`.
69
-
4.Stub it in [`__tests__/helpers/inputs.ts`](__tests__/helpers/inputs.ts).
68
+
3. Handle it in `inputs.ts`. Optional inputs: normalise empty-string to `undefined` (`getInput(KEY, {required: false}) || undefined`) so the `Inputs` field is truly optional.
69
+
4.Tests: `stubRequiredInputEnv()` only stubs `INPUT_KEYS_REQUIRED`, so a **required** input is covered automatically. An **optional** input is not — stub it per-test with `stubInputEnv(INPUT_KEY_X, value)` and assert the `undefined` default case too (see [`__tests__/deploy/inputs.test.ts`](__tests__/deploy/inputs.test.ts)).
70
70
5. Document it in the Inputs table of [README.md](README.md) (or [delete/README.md](delete/README.md) for the delete action).
71
71
72
72
**Cloudflare API change**: update types in [src/common/cloudflare/types.ts](src/common/cloudflare/types.ts) → add fixtures to [`__generated__/responses/`](__generated__/responses/).
@@ -125,6 +125,7 @@ Formatting, linting, and type-checking are automated via [prek](https://prek.j17
- The deployment payload embeds Cloudflare metadata so the delete workflow can find deployments ([src/common/github/deployment/types.ts](src/common/github/deployment/types.ts)).
128
+
-**`workflow_run` + fork PRs**: `github.event.workflow_run.pull_requests` is **empty for pull requests from forks** ([community #25220](https://github.com/orgs/community/discussions/25220)). Never derive `pr-number` or `branch` from `pull_requests[0].number` in docs/examples — it silently resolves to empty for the exact fork case those examples target. Instead save the number in the triggering `pull_request` workflow and read it from an artifact (`upload-artifact` → `download-artifact` with `run-id: ${{ github.event.workflow_run.id }}` + `github-token`). See the "Custom branch name" example in [README.md](README.md).
The `github-environment` expression deploys the `main` branch to `production` and every other branch to `preview`.
54
+
The `github-environment` expression deploys the `main` branch to `production` and every other branch to `preview`. For a line-by-line breakdown of this expression — and how it relates to the Cloudflare `branch` input — see [GitHub Environments](#2-github-environments-required).
55
55
56
56
## Setup
57
57
@@ -74,6 +74,25 @@ Create each environment you reference (for example `production` and `preview`),
GitHub Actions has no `condition ? a : b` ternary, so this uses the `&&`/`||` idiom to get the same result. Read it as **"if on `main`, use `production`, otherwise use `preview`"**:
78
+
79
+
- `github.ref`is the full ref of the branch that triggered the run, e.g. `refs/heads/main` or `refs/heads/my-feature`.
80
+
- `github.ref == 'refs/heads/main'`is `true` only on the `main` branch.
81
+
- `A && B`returns `B` when `A` is true, so on `main` the expression so far is `'production'`; on any other branch it is `false`.
82
+
- `X || 'preview'`returns `X` unless `X` is falsy, so a `false` left side falls through to `'preview'`.
83
+
84
+
To map more branches to environments, extend the same pattern — for example, send `main` to `production`, `staging` to `staging`, and everything else to `preview`:
> `github-environment` only sets the **GitHub** Environment the deployment is recorded against. Whether Cloudflare treats the upload as a production or preview deployment is decided separately, by the **branch name** — Cloudflare promotes the deployment to production only when the branch matches your Pages project's production branch. By default the branch is detected from the GitHub context; use the [`branch`](#custom-branch-name) input to override it. The two inputs are independent, so make sure your branch logic and `github-environment` logic agree on what counts as "production".
95
+
77
96
### 3. Permissions
78
97
79
98
When using the workflow's built-in [`GITHUB_TOKEN`] for the `github-token` input, grant these [permissions]:
| `cloudflare-api-token` | yes | Cloudflare API Token |
113
+
| `cloudflare-account-id` | yes | Cloudflare Account ID |
114
+
| `cloudflare-project-name` | yes | Cloudflare Pages project to upload to |
115
+
| `directory` | yes | Directory of static files to upload |
116
+
| `github-token` | yes | Github API key, make sure to add the required permissions for this action. |
117
+
| `github-environment` | yes | GitHub environment to deploy to. You need to manually create this for the github repo |
118
+
| `pr-number` | no | GitHub pull request number to comment on. If not set, the action auto-detects from the event payload. |
119
+
| `working-directory` | no | Directory to run wrangler cli from |
120
+
| `wrangler-version` | no | Wrangler version to use. Otherwise a default version from the action will be used. |
121
+
| `branch` | no | Branch name to use for Cloudflare Pages deployment. If not set, the branch is automatically detected from the GitHub context. |
102
122
103
123
## Outputs
104
124
@@ -156,6 +176,64 @@ jobs:
156
176
157
177
The action supports the `workflow_run` event and uses its head commit SHA and branch for the deployment metadata.
158
178
179
+
### Custom branch name
180
+
181
+
You can override the automatically detected branch name with the `branch` input. This is useful with `workflow_run`: a fork pull request opened from the fork's `main` branch would otherwise deploy to your project's production branch and overwrite the production deployment. Giving each pull request its own branch name (for example `pr-123`) keeps it on a separate Cloudflare Pages preview.
182
+
183
+
**Do not** build the branch name from `github.event.workflow_run.pull_requests[0].number` — that array is empty for pull requests from forks ([community discussion #25220](https://github.com/orgs/community/discussions/25220)), which is the exact case this is meant to cover. Instead, save the PR number in the triggering `pull_request` workflow and read it back from an artifact in the `workflow_run` workflow.
184
+
185
+
In the `pull_request` workflow (the one named in `workflows:` of the `workflow_run` trigger), save the PR number alongside your build output:
This creates a Cloudflare Pages preview deployment with a branch name like `pr-123`, so each pull request — including those from forks — gets its own preview environment instead of overwriting production.
0 commit comments