chore: import upstream snapshot with attribution
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# GitHub Actions
|
||||
|
||||
See below for a summary of this repo's Actions
|
||||
|
||||
- _Actions marked with "⚠️" are expected to sometimes fail._
|
||||
|
||||
## Security auditing
|
||||
|
||||
We use [`zizmor`](https://docs.zizmor.sh/) to audit GitHub Actions workflow definitions and keep CI workflows as safe as possible. When changing files in this directory, run:
|
||||
|
||||
```sh
|
||||
zizmor .github/workflows/*.yml
|
||||
```
|
||||
|
||||
Workflow changes should avoid unsuppressed `zizmor` findings. In particular:
|
||||
|
||||
- Pin external actions to immutable commit SHAs, not tags.
|
||||
- Use `actions/checkout` v6 or newer so persisted credentials are stored under `$RUNNER_TEMP`; set `persist-credentials: false` when a job does not need follow-up authenticated Git operations.
|
||||
- Pass GitHub expression values into shell steps through `env` instead of expanding `${{ ... }}` directly inside `run` blocks.
|
||||
- Treat privileged triggers such as `pull_request_target` and `workflow_run` as security-sensitive. If a privileged trigger is required, document the safety model and add a targeted `zizmor` ignore with a reason.
|
||||
|
||||
## PR related actions
|
||||
|
||||
### Tests + Checks (test-and-check.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs.
|
||||
- PRs in the merge queue.
|
||||
- Actions
|
||||
- Builds all the packages.
|
||||
- Runs formatting, linting and type checks.
|
||||
- Runs fixture tests, Wrangler unit tests, C3 unit tests, Miniflare unit tests, and ESLint + Prettier checks.
|
||||
- Adds the PR to a GitHub project
|
||||
- Makes sure that Wrangler's warning for old Node.js versions works.
|
||||
|
||||
### Wrangler E2E tests (e2e-wrangler.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs on the Cloudflare fork.
|
||||
- PRs in the merge queue.
|
||||
- Actions
|
||||
- Runs the E2E tests for Wrangler.
|
||||
- Cloudflare API credentials are only passed on Version Packages PRs (`changeset-release/main`), in the merge queue, or when the `ci:run-remote-tests` label is applied. Other PRs run the E2E suite without remote tests.
|
||||
|
||||
### Vite Plugin E2E tests (e2e-vite.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs on the Cloudflare fork.
|
||||
- PRs in the merge queue.
|
||||
- Actions
|
||||
- Runs the E2E tests for the Vite plugin.
|
||||
- Cloudflare API credentials are only passed on Version Packages PRs (`changeset-release/main`), in the merge queue, or when the `ci:run-remote-tests` label is applied. Other PRs run the E2E suite without remote tests.
|
||||
|
||||
## Deploy Pages Previews (deploy-pages-preview.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs that have one of the `preview:...` labels.
|
||||
- Actions
|
||||
- Deploy a preview of the matching Pages project to Cloudflare.
|
||||
|
||||
## Deploy (to testing) and Test Playground Preview Worker (worker-playground-preview-testing-env-deploy-and-test.yml)
|
||||
|
||||
- Triggers
|
||||
- Commits merged to the `main` branch, on the Cloudflare fork, which touch files in the `packages/playground-preview-worker` directory.
|
||||
- Updates to PRs, on the Cloudflare fork, with the `playground-worker` label applied.
|
||||
- Actions
|
||||
- Runs integrations tests to ensure the behaviour of the Worker powering the Workers Playground.
|
||||
|
||||
## Create Pull Request Prerelease (prerelease.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs.
|
||||
- Actions
|
||||
- Creates an installable pre-release of any package containing `{ "workers-sdk": { "prerelease": true } }` in its `package.json` (e.g. Wrangler, C3, and Miniflare) on every PR.
|
||||
- Adds a comment to the PR with links to the pre-releases.
|
||||
|
||||
## Housekeeping actions
|
||||
|
||||
### Add issues to DevProd project (issues.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to issues.
|
||||
- Actions
|
||||
- Add the issue to a GitHub project.
|
||||
|
||||
### Triage Issue (triage-issue.yml)
|
||||
|
||||
- Triggers
|
||||
- A new issue is opened (skips PRs and bot-authored issues).
|
||||
- A new comment is created on an issue — re-triages with the latest context. Skips PRs, bot comments, and the triage bot's own sticky comment (matched by the sticky-comment marker) to avoid re-triage loops.
|
||||
- Manual `workflow_dispatch` with an `issue-number` input.
|
||||
- Actions
|
||||
- Runs an OpenCode agent with the `.github/skills/issue-review.md` skill against the pre-fetched issue data (including existing comments) to produce a markdown triage report (`report.md`) and a structured JSON summary (`summary.json`).
|
||||
- Uploads the report to the triage dashboard.
|
||||
- Posts the report and structured summary as a maintainer-facing sticky comment on the issue and applies the suggested labels (validated against existing repo labels). Because the comment is sticky, re-triage updates the existing comment rather than posting a duplicate. Comments and labels are attributed to the workers-devprod bot via `GH_ACCESS_TOKEN`.
|
||||
- The AI agent itself runs sandboxed (no shell or network access); all GitHub writes happen in workflow steps from the generated files.
|
||||
|
||||
### Generate changesets for dependabot PRs (c3-dependabot-versioning-prs.yml and miniflare-dependabot-versioning-prs.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs, by the dependabot user, which update one of:
|
||||
- frameworks dependencies in C3,
|
||||
- miniflare.
|
||||
- Actions
|
||||
- Generates changesets for the affected package.
|
||||
|
||||
### E2E Project Cleanup (e2e-project-cleanup.yml)
|
||||
|
||||
- Triggers
|
||||
- Scheduled to run at 3am each day.
|
||||
- Actions
|
||||
- Deletes any Workers and Pages projects that were not properly cleaned up by the E2E tests.
|
||||
|
||||
## Main branch actions
|
||||
|
||||
### Handle Changesets (changesets.yml)
|
||||
|
||||
- Triggers
|
||||
- Commits merged to the `main` branch, on the Cloudflare fork.
|
||||
- Actions
|
||||
- If there are changeset in the working directory, create or update a "Version Packages" PR to prep for a release.
|
||||
- If there are no changesets, release any packages that have a bump to their version in this change.
|
||||
- Public packages are deployed to npm
|
||||
- Private packages will run their `deploy` script, if they have one.
|
||||
|
||||
## C3 related actions
|
||||
|
||||
### C3 E2E Tests (c3-e2e.yml)
|
||||
|
||||
- Triggers
|
||||
- Updates to PRs.
|
||||
- Actions
|
||||
- Runs the E2E tests for C3.
|
||||
- Cloudflare API credentials are only passed on Version Packages PRs (`changeset-release/main`), in the merge queue, or when the `ci:run-remote-tests` label is applied. Other PRs run the E2E suite without remote tests.
|
||||
|
||||
### Rerun Code Owners (rerun-codeowners.yml + rerun-codeowners-privileged.yml)
|
||||
|
||||
- Triggers
|
||||
- A review is submitted or dismissed on a PR.
|
||||
- Actions
|
||||
- Re-runs the "Run Codeowners Plus" check so it re-evaluates approval status after the review change.
|
||||
- Uses the `workflow_run` pattern: the trigger workflow exists solely to fire a `workflow_run` event; the privileged companion workflow (which has full permissions) reads the PR head SHA from `github.event.workflow_run.head_sha` and performs the re-run. This is necessary because `pull_request_review` gives a read-only token for fork PRs and has no `_target` variant.
|
||||
|
||||
### Rerun Remote Tests (rerun-remote-tests.yml)
|
||||
|
||||
- Triggers
|
||||
- The `ci:run-remote-tests` or `run-c3-frameworks-tests` label is added to or removed from a PR.
|
||||
- Actions
|
||||
- Re-runs the E2E workflows for the PR so they pick up the label change and pass (or withhold) API credentials to the test steps.
|
||||
- `ci:run-remote-tests` re-runs Wrangler, Vite, and C3 E2E workflows; `run-c3-frameworks-tests` re-runs only C3 E2E.
|
||||
- Uses `pull_request_target` to get a privileged token even for fork PRs (safe because no untrusted code is checked out).
|
||||
@@ -0,0 +1,69 @@
|
||||
name: New PR Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
review:
|
||||
# Skip Version Packages PRs (auto-generated by the changesets action) since they don't need a Bonk review
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name &&
|
||||
!(github.event.pull_request.base.repo.owner.login == 'cloudflare' && github.event.pull_request.head.ref == 'changeset-release/main')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: false
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check if PR author is Cloudflare org member
|
||||
run: |
|
||||
STATUS=$(gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/orgs/cloudflare/members/${PR_AUTHOR}" \
|
||||
--silent -i 2>/dev/null | head -1 | awk '{print $2}') || true
|
||||
if [ "$STATUS" != "204" ]; then
|
||||
echo "User ${PR_AUTHOR} is not a member of the Cloudflare organization"
|
||||
exit 1
|
||||
fi
|
||||
echo "User ${PR_AUTHOR} is a Cloudflare org member"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.READ_ONLY_ORG_GITHUB_TOKEN }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 30
|
||||
persist-credentials: false
|
||||
|
||||
- name: Load review prompt
|
||||
id: prompt
|
||||
run: |
|
||||
{
|
||||
echo 'value<<EOF'
|
||||
echo "You are reviewing PR #${{ github.event.pull_request.number }} on ${{ github.repository }}."
|
||||
echo ""
|
||||
cat .github/bonk_reviewer.md
|
||||
echo EOF
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Run Bonk
|
||||
uses: ask-bonk/ask-bonk/github@24832587005550860c8ad13fd96519e731ca632a # main
|
||||
env:
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
|
||||
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
|
||||
with:
|
||||
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-8"
|
||||
variant: "high"
|
||||
forks: "false"
|
||||
permissions: write
|
||||
opencode_version: 1.15.13 # pin to this version as certain ones cause ProviderInitError issues
|
||||
prompt: ${{ steps.prompt.outputs.value }}
|
||||
@@ -0,0 +1,80 @@
|
||||
name: Bonk
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number || github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
bonk:
|
||||
if: github.event.sender.type != 'Bot' && (contains(github.event.comment.body, '/bonk') || contains(github.event.comment.body, '@ask-bonk'))
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check if comment author is Cloudflare org member
|
||||
run: |
|
||||
STATUS=$(gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/orgs/cloudflare/members/${COMMENT_AUTHOR}" \
|
||||
--silent -i 2>/dev/null | head -1 | awk '{print $2}') || true
|
||||
if [ "$STATUS" != "204" ]; then
|
||||
echo "User ${COMMENT_AUTHOR} is not a member of the Cloudflare organization"
|
||||
exit 1
|
||||
fi
|
||||
echo "User ${COMMENT_AUTHOR} is a Cloudflare org member"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.READ_ONLY_ORG_GITHUB_TOKEN }}
|
||||
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build prompt with triggering comment
|
||||
id: prompt
|
||||
run: |
|
||||
{
|
||||
DELIMITER=$(openssl rand -hex 16)
|
||||
echo "value<<$DELIMITER"
|
||||
echo "You were invoked by @${COMMENT_AUTHOR} on ${COMMENT_URL}"
|
||||
echo ""
|
||||
echo "Their comment:"
|
||||
echo '```'
|
||||
echo "$COMMENT_BODY"
|
||||
echo '```'
|
||||
echo ""
|
||||
echo "This is your task. Read it carefully and act on it."
|
||||
echo "$DELIMITER"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
COMMENT_URL: ${{ github.event.comment.html_url }}
|
||||
|
||||
- name: Run Bonk
|
||||
uses: ask-bonk/ask-bonk/github@c39e982defd0114385df54e72012a3fc4333c4d4
|
||||
env:
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
|
||||
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
|
||||
with:
|
||||
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-8"
|
||||
variant: "high"
|
||||
mentions: "/bonk,@ask-bonk"
|
||||
permissions: write
|
||||
agent: bonk
|
||||
opencode_version: 1.15.13 # pin to this version as certain ones cause ProviderInitError issues
|
||||
prompt: ${{ steps.prompt.outputs.value }}
|
||||
@@ -0,0 +1,39 @@
|
||||
name: "C3 - Generate changesets for dependabot PRs"
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] dependabot-only job requires write access to push generated changesets; checkout v6 persists credentials under RUNNER_TEMP
|
||||
paths:
|
||||
- "packages/create-cloudflare/src/frameworks/package.json"
|
||||
|
||||
permissions:
|
||||
# content:write permission needed to update add changesets to dependabot PRs
|
||||
# (see tools/dependabot/generate-dependabot-pr-changesets.ts)
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
generate-changeset:
|
||||
runs-on: ubuntu-slim
|
||||
if: |
|
||||
github.event.pull_request.user.login == 'dependabot[bot]' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: true
|
||||
ref: ${{ github.head_ref }}
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.email wrangler@cloudflare.com
|
||||
git config --global user.name 'Wrangler automated PR updater'
|
||||
|
||||
- name: Generate C3 changesets
|
||||
# Keep the final param (the changeset prefix: `c3-frameworks-update`) in sync with the filter in the `.github/workflows/c3-e2e-dependabot.yml` workflow.
|
||||
run: node -r esbuild-register tools/dependabot/generate-dependabot-pr-changesets.ts "$PR_NUMBER" create-cloudflare packages/create-cloudflare/src/frameworks/package.json c3-frameworks-update
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
@@ -0,0 +1,311 @@
|
||||
name: C3 E2E
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# pnpm 11-specific settings - recognised by pnpm 11+ and
|
||||
# silently ignored by pnpm 10.
|
||||
#
|
||||
# - pmOnFail=ignore: pnpm 11's default `download` would silently re-exec as
|
||||
# the monorepo's pinned pnpm 10.33.0, defeating the matrix override.
|
||||
# - verifyDepsBeforeRun=false: pnpm 11's default `install` would re-run
|
||||
# `pnpm install` at the monorepo root before invoking the script, which
|
||||
# then trips on engines.pnpm.
|
||||
env:
|
||||
pnpm_config_pm_on_fail: ignore
|
||||
pnpm_config_verify_deps_before_run: "false"
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
# Runs the non-frameworks C3 E2E tests on all supported operating systems
|
||||
# and package managers.
|
||||
timeout-minutes: 45
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os.name }}-${{ matrix.pm.name }}-${{ matrix.pm.version }}${{ matrix.experimental && '-experimental' || '' }}-${{ matrix.filter }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
# `matrix.pm.label` is the display name in job/artifact names. Default
|
||||
# pm entries use the plain name (e.g. `pnpm`) to keep historical required-
|
||||
# check names stable; non-default entries (e.g. pnpm 11) suffix the version.
|
||||
name: ${{ format('C3 E2E ({0}, {1}{2}) - {3}', matrix.pm.label, matrix.os.description, matrix.experimental && ', experimental' || '', matrix.filter) }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
experimental: [false]
|
||||
filter: ["cli", "workers"]
|
||||
os: [{ name: ubuntu-latest, description: Linux }]
|
||||
pm:
|
||||
- { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
- { name: pnpm, version: "11.5.1", label: "pnpm@11.5.1" }
|
||||
- { name: npm, version: "0.0.0", label: "npm" }
|
||||
# The yarn tests keep failing on Linux with out of space errors, with no clear reason why. Disabling for now.
|
||||
# - { name: yarn, version: "1.0.0", label: "yarn" }
|
||||
include:
|
||||
# Windows and experimental entries stay on the default pnpm to
|
||||
# preserve historical required-check names. pnpm 11 coverage comes
|
||||
# from the Linux base entries above.
|
||||
- os: { name: windows-latest, description: Windows }
|
||||
pm: { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
filter: "cli"
|
||||
- os: { name: windows-latest, description: Windows }
|
||||
pm: { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
filter: "workers"
|
||||
- os: { name: ubuntu-latest, description: Linux }
|
||||
pm: { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
experimental: true
|
||||
filter: "cli"
|
||||
- os: { name: ubuntu-latest, description: Linux }
|
||||
pm: { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
experimental: true
|
||||
filter: "workers"
|
||||
runs-on: ${{ matrix.os.name }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: Install Python uv
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-python-uv
|
||||
|
||||
# Needed because gatsby requires git
|
||||
- name: Configure Git
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global user.email wrangler@cloudflare.com
|
||||
git config --global user.name 'Wrangler Tester'
|
||||
|
||||
# Put the matrix pnpm version on PATH so scaffolded-project installs
|
||||
# run it (not the monorepo's pinned pnpm 10.33.0). Without this, the
|
||||
# matrix only relabels C3's `npm_config_user_agent` and pnpm 11
|
||||
# regressions go undetected.
|
||||
#
|
||||
# `pnpm/action-setup` refuses when both `version` input and the root
|
||||
# `package.json#packageManager` are set, so we point it at a stub
|
||||
# `package.json`. We also loosen `engines.pnpm` to avoid pnpm 11
|
||||
# bailing with ERR_PNPM_UNSUPPORTED_ENGINE at the monorepo root.
|
||||
- name: Prepare workspace for matrix pnpm install
|
||||
if: matrix.pm.name == 'pnpm' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p .ci-pnpm-setup-stub
|
||||
printf '{"name":"ci-stub","private":true}\n' > .ci-pnpm-setup-stub/package.json
|
||||
node -e "
|
||||
const fs = require('node:fs');
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
|
||||
if (pkg.engines && pkg.engines.pnpm) pkg.engines.pnpm = '*';
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, '\t') + '\n');
|
||||
"
|
||||
- name: Install matrix pnpm version for scaffolded installs
|
||||
if: matrix.pm.name == 'pnpm' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||||
with:
|
||||
version: ${{ matrix.pm.version }}
|
||||
package_json_file: .ci-pnpm-setup-stub/package.json
|
||||
# Distinct dest so `addPath` prepends ahead of the monorepo's
|
||||
# pinned pnpm 10.x from the earlier `~/setup-pnpm`.
|
||||
dest: ~/matrix-pnpm
|
||||
- name: Verify pnpm on PATH matches matrix version
|
||||
if: matrix.pm.name == 'pnpm' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
got="$(pnpm --version)"
|
||||
want="${{ matrix.pm.version }}"
|
||||
echo "pnpm on PATH: $got (expected $want)"
|
||||
[ "$got" = "$want" ] || { echo "ERROR: PATH pnpm is $got, not $want — scaffolded installs would silently run the wrong version."; exit 1; }
|
||||
|
||||
- id: run-e2e
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: pnpm run test:e2e:c3
|
||||
env:
|
||||
NODE_VERSION: ${{ env.NODE_VERSION }}
|
||||
E2E_EXPERIMENTAL: ${{ matrix.experimental }}
|
||||
E2E_TEST_PM: ${{ matrix.pm.name }}
|
||||
E2E_TEST_PM_VERSION: ${{ matrix.pm.version }}
|
||||
E2E_TEST_FILTER: ${{ matrix.filter }}
|
||||
CI_OS: ${{ runner.os }}
|
||||
GITHUB_TOKEN: ${{ github.token }} # Needed for begit to clone the repo in the e2e tests for solid-start
|
||||
|
||||
- name: Upload Logs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ !cancelled() && steps.changes.outputs.everything_but_markdown == 'true' }}
|
||||
with:
|
||||
name: ${{ format('e2e-logs-{0}-{1}-{2}-{3}', matrix.pm.label, matrix.os.description, matrix.experimental && 'experimental' || 'normal', matrix.filter) }}
|
||||
path: packages/create-cloudflare/.e2e-logs${{matrix.experimental == 'true' && '-experimental' || ''}}/${{ matrix.pm.name }}/${{ matrix.filter }}
|
||||
include-hidden-files: true
|
||||
|
||||
- name: Upload Turbo Summary
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ !cancelled() && steps.changes.outputs.everything_but_markdown == 'true' }}
|
||||
with:
|
||||
name: ${{ format('turbo-runs-{0}-{1}-{2}-{3}', matrix.pm.label, matrix.os.description, matrix.experimental && 'experimental' || 'normal', matrix.filter) }}
|
||||
path: .turbo/runs
|
||||
include-hidden-files: true
|
||||
|
||||
frameworks-e2e:
|
||||
# Runs the C3 frameworks E2E tests only in the merge queue, on the release branch, if create-cloudflare has changed, or when explicitly requested via label.
|
||||
#
|
||||
# Frameworks that delegate install to their own generator (e.g. `hono`)
|
||||
# don't route through C3's `ERR_PNPM_IGNORED_BUILDS` recovery path; those
|
||||
# tests opt out of pnpm 11 via `unsupportedPmRanges` in the test config.
|
||||
timeout-minutes: 45
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-frameworks${{ matrix.experimental && '-experimental' || '' }}-${{ github.ref }}-${{ matrix.os.name }}-${{ matrix.pm.name }}-${{ matrix.pm.version }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
name: ${{ format('C3 E2E ({0}, {1}{2}) - frameworks', matrix.pm.label, matrix.os.description, matrix.experimental && ', experimental' || '') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
experimental: [false]
|
||||
os:
|
||||
- { name: ubuntu-latest, description: Linux }
|
||||
pm:
|
||||
- { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
- { name: pnpm, version: "11.5.1", label: "pnpm@11.5.1" }
|
||||
- { name: npm, version: "0.0.0", label: "npm" }
|
||||
include:
|
||||
# Experimental stays on the default pnpm to preserve historical
|
||||
# required-check names; pnpm 11 coverage comes from the base entry.
|
||||
- os: { name: ubuntu-latest, description: Linux }
|
||||
pm: { name: pnpm, version: "10.33.0", label: "pnpm" }
|
||||
experimental: true
|
||||
runs-on: ${{ matrix.os.name }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
framework_deps:
|
||||
- 'packages/create-cloudflare/**'
|
||||
|
||||
- name: Check if frameworks tests should run
|
||||
id: check-frameworks
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
FRAMEWORK_DEPS_CHANGED: ${{ steps.changes.outputs.framework_deps }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" = "merge_group" ] || \
|
||||
[ "$HEAD_REF" = "changeset-release/main" ] || \
|
||||
[ "$FRAMEWORK_DEPS_CHANGED" = "true" ]; then
|
||||
echo "run_frameworks=true" >> "$GITHUB_OUTPUT"
|
||||
elif [ "$EVENT_NAME" = "pull_request" ]; then
|
||||
HAS_LABEL=$(gh pr view "$PR_NUMBER" \
|
||||
--repo "$REPO" --json labels \
|
||||
--jq '[.labels[].name] | any(. == "run-c3-frameworks-tests")')
|
||||
echo "run_frameworks=${HAS_LABEL}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "run_frameworks=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: Install Python uv
|
||||
if: steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-python-uv
|
||||
|
||||
- name: Configure Git
|
||||
if: steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global user.email wrangler@cloudflare.com
|
||||
git config --global user.name 'Wrangler Tester'
|
||||
|
||||
# See the equivalent step in the `e2e` job above for context.
|
||||
- name: Prepare workspace for matrix pnpm install
|
||||
if: matrix.pm.name == 'pnpm' && steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p .ci-pnpm-setup-stub
|
||||
printf '{"name":"ci-stub","private":true}\n' > .ci-pnpm-setup-stub/package.json
|
||||
node -e "
|
||||
const fs = require('node:fs');
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
|
||||
if (pkg.engines && pkg.engines.pnpm) pkg.engines.pnpm = '*';
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, '\t') + '\n');
|
||||
"
|
||||
- name: Install matrix pnpm version for scaffolded installs
|
||||
if: matrix.pm.name == 'pnpm' && steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||||
with:
|
||||
version: ${{ matrix.pm.version }}
|
||||
package_json_file: .ci-pnpm-setup-stub/package.json
|
||||
dest: ~/matrix-pnpm
|
||||
- name: Verify pnpm on PATH matches matrix version
|
||||
if: matrix.pm.name == 'pnpm' && steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
got="$(pnpm --version)"
|
||||
want="${{ matrix.pm.version }}"
|
||||
echo "pnpm on PATH: $got (expected $want)"
|
||||
[ "$got" = "$want" ] || { echo "ERROR: PATH pnpm is $got, not $want — scaffolded installs would silently run the wrong version."; exit 1; }
|
||||
|
||||
- id: run-e2e
|
||||
if: steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true'
|
||||
shell: bash
|
||||
run: pnpm run test:e2e:c3
|
||||
env:
|
||||
NODE_VERSION: ${{ env.NODE_VERSION }}
|
||||
E2E_EXPERIMENTAL: ${{ matrix.experimental }}
|
||||
E2E_TEST_PM: ${{ matrix.pm.name }}
|
||||
E2E_TEST_PM_VERSION: ${{ matrix.pm.version }}
|
||||
E2E_TEST_FILTER: frameworks
|
||||
CI_OS: ${{ runner.os }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Upload Logs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ !cancelled() && steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true' }}
|
||||
with:
|
||||
name: ${{ format('e2e-logs-{0}-{1}-{2}-frameworks', matrix.pm.label, matrix.os.description, matrix.experimental && 'experimental' || 'normal') }}
|
||||
path: packages/create-cloudflare/.e2e-logs${{matrix.experimental == 'true' && '-experimental' || ''}}/${{ matrix.pm.name }}/frameworks
|
||||
include-hidden-files: true
|
||||
|
||||
- name: Upload Turbo Summary
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ !cancelled() && steps.check-frameworks.outputs.run_frameworks == 'true' && steps.changes.outputs.everything_but_markdown == 'true' }}
|
||||
with:
|
||||
name: ${{ format('turbo-runs-{0}-{1}-{2}-frameworks', matrix.pm.label, matrix.os.description, matrix.experimental && 'experimental' || 'normal') }}
|
||||
path: .turbo/runs
|
||||
include-hidden-files: true
|
||||
@@ -0,0 +1,92 @@
|
||||
name: Changeset Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".changeset/*.md"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
review-changesets:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- name: Checkout changesets
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.changeset
|
||||
.github/opencode.json
|
||||
|
||||
- name: Install OpenCode
|
||||
# pin OpenCode to 1.4.6 version as newer versions are causing ProviderInitError issues
|
||||
run: |
|
||||
npm install -g opencode-ai@1.4.6
|
||||
cp .github/opencode.json ./opencode.json
|
||||
|
||||
- name: Get changed changeset files
|
||||
id: changed-changesets
|
||||
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
|
||||
with:
|
||||
files: |
|
||||
.changeset/*.md
|
||||
files_ignore: |
|
||||
.changeset/README.md
|
||||
# Recover deleted files so the AI can read them (needed for Version Packages PRs)
|
||||
recover_deleted_files: ${{ github.event.pull_request.title == 'Version Packages' }}
|
||||
|
||||
- name: Review Changesets with OpenCode
|
||||
id: opencode-review
|
||||
# Run for Version Packages PRs (which delete changesets) or regular PRs with new changesets
|
||||
if: github.event.pull_request.title == 'Version Packages' || steps.changed-changesets.outputs.added_files_count > 0
|
||||
env:
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
|
||||
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
|
||||
DELETED_FILES: ${{ steps.changed-changesets.outputs.deleted_files }}
|
||||
ADDED_FILES: ${{ steps.changed-changesets.outputs.added_files }}
|
||||
run: |
|
||||
opencode --model "cloudflare-ai-gateway/workers-ai/@cf/moonshotai/kimi-k2.6" run --print-logs \
|
||||
"Review the changeset files in this PR.
|
||||
|
||||
For \"Version Packages\" PRs, review: ${DELETED_FILES}
|
||||
For regular PRs, review: ${ADDED_FILES}
|
||||
|
||||
Read \`.changeset/README.md\` for guidelines, then validate:
|
||||
1. **Version Type**: Accept the author's choice of patch/minor unless clearly incorrect
|
||||
2. **Changelog Quality**: Meaningful descriptions (examples encouraged but not required for features)
|
||||
3. **Markdown Headers**: No h1/h2/h3 headers (breaks changelog formatting)
|
||||
4. **Analytics**: If the change collects more analytics, it should be a minor even though there is no user-visible change
|
||||
5. **Dependabot**: Do not validate dependency update changesets for create-cloudflare
|
||||
6. **Experimental features**: Changesets for experimental features should include note on how users can opt in.
|
||||
|
||||
If all changesets pass, just output \"✅ All changesets look good\" - no need for a detailed checklist.
|
||||
|
||||
Do not review other files, only the changesets. This is specifically a changeset review action.
|
||||
|
||||
If there are issues, output \"⚠️ Issues found\" followed by the specific problems.
|
||||
|
||||
Write your review to changeset-review.md."
|
||||
|
||||
- name: Post review comment
|
||||
if: steps.opencode-review.outcome == 'success'
|
||||
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff # v3.0.3
|
||||
with:
|
||||
header: changeset-review
|
||||
path: changeset-review.md
|
||||
|
||||
- name: Skip notice
|
||||
if: github.event.pull_request.title != 'Version Packages' && steps.changed-changesets.outputs.added_files_count == 0
|
||||
run: |
|
||||
echo "No new changesets to review (only minor edits to pre-existing changesets detected)"
|
||||
@@ -0,0 +1,108 @@
|
||||
name: Handle Changesets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
# note: no write permissions are needed since the workflow uses GH_ACCESS_TOKEN instead of GITHUB_TOKEN
|
||||
|
||||
env:
|
||||
# This workflow only builds and publishes — it never runs Playwright tests.
|
||||
# Skip the browser download to avoid the postinstall script hanging in CI.
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: ${{ github.repository_owner == 'cloudflare' }}
|
||||
name: Handle Changesets
|
||||
runs-on: macos-latest-large
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
# See https://github.com/changesets/action/issues/187
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
persist-credentials: true
|
||||
# Pull in more history to cover the changeset commits
|
||||
fetch-depth: 500
|
||||
|
||||
- name: Install Dependencies
|
||||
# Defense in depth: do not pass Turbo remote cache credentials and
|
||||
# disable the pnpm store cache so release builds always resolve
|
||||
# packages from the registry and rebuild every task from source,
|
||||
# rather than restoring from a (potentially poisoned) cache.
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
# Pinned to 24.18.0 (rather than floating `24`) until it's safe to
|
||||
# float back: Node 24.17.0 regressed node-fetch@2 keep-alive responses
|
||||
# with ERR_STREAM_PREMATURE_CLOSE (nodejs/node#63989, fixed in 24.18.0).
|
||||
node-version: 24.18.0
|
||||
disable-cache: "true"
|
||||
|
||||
- name: Check npm version
|
||||
run: node -r esbuild-register tools/deployments/check-npm-version.ts
|
||||
|
||||
- name: Check the changesets
|
||||
run: node -r esbuild-register tools/deployments/validate-changesets.ts
|
||||
|
||||
- name: Build all packages
|
||||
run: pnpm run build
|
||||
env:
|
||||
CI_OS: ${{ runner.os }}
|
||||
SOURCEMAPS: "false"
|
||||
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
|
||||
ALGOLIA_PUBLIC_KEY: ${{ secrets.ALGOLIA_PUBLIC_KEY }}
|
||||
SENTRY_DSN: "https://9edbb8417b284aa2bbead9b4c318918b@sentry10.cfdata.org/583"
|
||||
NODE_ENV: "production"
|
||||
# This is the "production" key for sparrow analytics.
|
||||
# Include this here because this step will rebuild Wrangler and needs to have this available
|
||||
SPARROW_SOURCE_KEY: "50598e014ed44c739ec8074fdc16057c"
|
||||
|
||||
- name: Create Version PR or Publish to NPM
|
||||
id: changesets
|
||||
uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
|
||||
with:
|
||||
version: node .github/changeset-version.js
|
||||
publish: pnpm exec changeset publish
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
# Switch to Node 22 for non-npm package deployments because quick-edit
|
||||
# builds native modules (tree-sitter) that are not compatible with
|
||||
# Node 24's C++20 requirement for V8 headers.
|
||||
- name: Switch to Node 22 for non-npm package deployments
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
# Pinned to 22.23.1 (rather than floating `22`) until it's safe to
|
||||
# float back: Node 22.23.0 regressed node-fetch@2 keep-alive responses
|
||||
# with ERR_STREAM_PREMATURE_CLOSE (nodejs/node#63989, fixed in 22.23.1).
|
||||
node-version: 22.23.1
|
||||
|
||||
- name: Deploy non-NPM Packages
|
||||
id: deploy
|
||||
run: |
|
||||
node -r esbuild-register tools/deployments/deploy-non-npm-packages.ts
|
||||
echo "status=$(cat deployment-status.json)" >> $GITHUB_OUTPUT;
|
||||
env:
|
||||
PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
WORKERS_NEW_CLOUDFLARE_ACCOUNT_ID: ${{ secrets.WORKERS_NEW_CLOUDFLARE_ACCOUNT_ID }}
|
||||
WORKERS_NEW_CLOUDFLARE_API_TOKEN: ${{ secrets.WORKERS_NEW_CLOUDFLARE_API_TOKEN }}
|
||||
WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN: ${{ secrets.WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN }}
|
||||
WORKERS_SHARED_SENTRY_ACCESS_ID: ${{ secrets.WORKERS_SHARED_SENTRY_ACCESS_ID }}
|
||||
WORKERS_SHARED_SENTRY_ACCESS_SECRET: ${{ secrets.WORKERS_SHARED_SENTRY_ACCESS_SECRET }}
|
||||
WORKERS_SHARED_SENTRY_AUTH_TOKEN: ${{ secrets.WORKERS_SHARED_SENTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: Send Alert
|
||||
if: always()
|
||||
run: node -r esbuild-register tools/deployments/alert-on-error.ts
|
||||
env:
|
||||
PUBLISH_STATUS: ${{ steps.changesets.outcome }}
|
||||
HAS_CHANGESETS: ${{ steps.changesets.outputs.hasChangesets }}
|
||||
DEPLOYMENT_STATUS: ${{ steps.deploy.outputs.status }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
TOKEN: ${{ secrets.STATUS_BOT_SECRET }}
|
||||
@@ -0,0 +1,54 @@
|
||||
name: "Code Owners"
|
||||
|
||||
# Re-evaluate when PRs are opened/updated.
|
||||
# When reviews are submitted/dismissed, the separate rerun-codeowners.yml workflow
|
||||
# re-runs this check (rather than creating a second check context).
|
||||
# Using pull_request_target (not pull_request) so the workflow has access to secrets
|
||||
# for fork PRs. This is safe because:
|
||||
# - The checkout is the BASE branch (ownership rules come from the protected branch)
|
||||
# - PR head commits are fetched as git objects only (never checked out or executed)
|
||||
# - The action only reads config files and calls the GitHub API
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] checks base branch ownership rules and fetches PR head for diff computation without executing PR code
|
||||
types: [opened, reopened, synchronize, ready_for_review, labeled, unlabeled]
|
||||
|
||||
concurrency:
|
||||
group: codeowners-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
codeowners:
|
||||
name: "Run Codeowners Plus"
|
||||
runs-on: ubuntu-latest
|
||||
# Each step is skipped when:
|
||||
# - the PR head is the changeset-release branch (auto-generated changeset PRs), or
|
||||
# - the PR base is not `main` (PRs against feature branches don't need formal review).
|
||||
# Note: if we ever introduce a maintenance branch (e.g. a long-lived release branch),
|
||||
# it would need to be added to the base branch allowlist below.
|
||||
steps:
|
||||
- name: "Checkout Base Branch"
|
||||
if: github.event.pull_request.head.ref != 'changeset-release/main' && github.event.pull_request.base.ref == 'main'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Fetch PR Head (for diff computation)"
|
||||
if: github.event.pull_request.head.ref != 'changeset-release/main' && github.event.pull_request.base.ref == 'main'
|
||||
run: git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.CODEOWNERS_GITHUB_PAT }}"
|
||||
|
||||
- name: "Codeowners Plus"
|
||||
if: github.event.pull_request.head.ref != 'changeset-release/main' && github.event.pull_request.base.ref == 'main'
|
||||
uses: multimediallc/codeowners-plus@ff02aa993a92e8efe01642916d0877beb9439e9f # v1.9.0
|
||||
with:
|
||||
github-token: "${{ secrets.CODEOWNERS_GITHUB_PAT }}"
|
||||
pr: "${{ github.event.pull_request.number }}"
|
||||
verbose: true
|
||||
quiet: ${{ github.event.pull_request.draft }}
|
||||
@@ -0,0 +1,141 @@
|
||||
name: "Dependabot - auto-merge workerd updates"
|
||||
|
||||
# workerd ships a release every weekday, so the workerd-and-workers-types
|
||||
# Dependabot group produces a steady stream of mechanical PRs that bump
|
||||
# `workerd`, `@cloudflare/workers-types`, and miniflare's pinned version in
|
||||
# lockstep (see .github/dependabot.yml). When CI is green these PRs require
|
||||
# no human review, so we enable GitHub auto-merge on them — required status
|
||||
# checks remain the gate, and a failing build still parks the PR for a human.
|
||||
#
|
||||
# Security model: this workflow effectively bypasses the human-review
|
||||
# requirement on PRs whose head branch matches the Dependabot naming pattern,
|
||||
# so we have to be paranoid about exactly what we're auto-merging. Before
|
||||
# enabling auto-merge we verify that the PR contains exactly the two commits
|
||||
# we expect (one from Dependabot, one from `miniflare-dependabot-versioning-prs.yml`)
|
||||
# and that nothing outside the expected fileset has been touched. If any
|
||||
# subsequent push violates those invariants we actively *disable* auto-merge,
|
||||
# so a maintainer pushing a follow-up commit cancels rather than rides the
|
||||
# auto-merge.
|
||||
#
|
||||
# DO NOT add `actions/checkout` to this workflow — `pull_request_target`
|
||||
# grants write-scoped tokens, and checking out PR-controlled code with
|
||||
# those tokens is the standard pwn vector.
|
||||
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] intentionally privileged metadata-only workflow; it never checks out or executes PR code
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
enable-auto-merge:
|
||||
if: github.event.pull_request.user.login == 'dependabot[bot]'
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Fetch Dependabot metadata
|
||||
id: meta
|
||||
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Verify PR matches expected workerd-bump shape
|
||||
id: verify
|
||||
if: steps.meta.outputs.dependency-group == 'workerd-and-workers-types'
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Pull commits and changed files via the GitHub API. `--repo` is
|
||||
# required because this workflow runs without `actions/checkout`,
|
||||
# so `gh` has no git remote to infer the repo from.
|
||||
commits_json=$(gh pr view --repo "$REPO" "$PR_NUMBER" --json commits)
|
||||
files_json=$(gh pr view --repo "$REPO" "$PR_NUMBER" --json files)
|
||||
|
||||
fail() {
|
||||
echo "verified=false" >> "$GITHUB_OUTPUT"
|
||||
echo "reason=$1" >> "$GITHUB_OUTPUT"
|
||||
echo "::warning::Refusing to enable auto-merge: $1"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- Commit shape ---------------------------------------------------
|
||||
# Expected: exactly two commits.
|
||||
# 1. dependabot[bot] author, with a verified GitHub signature.
|
||||
# 2. The changeset commit pushed by miniflare-dependabot-versioning-prs.yml,
|
||||
# authored as `Wrangler automated PR updater <wrangler@cloudflare.com>`.
|
||||
#
|
||||
# We can't require a signature on the second commit (it's pushed via
|
||||
# GH_ACCESS_TOKEN, which doesn't sign), so we lean on path/content
|
||||
# checks below to constrain what that commit can do.
|
||||
|
||||
commit_count=$(echo "$commits_json" | jq '.commits | length')
|
||||
if [ "$commit_count" -ne 2 ]; then
|
||||
fail "expected exactly 2 commits, found $commit_count"
|
||||
fi
|
||||
|
||||
first_author=$(echo "$commits_json" | jq -r '.commits[0].authors[0].login')
|
||||
first_oid=$(echo "$commits_json" | jq -r '.commits[0].oid')
|
||||
if [ "$first_author" != "dependabot[bot]" ]; then
|
||||
fail "first commit author is '$first_author', expected 'dependabot[bot]'"
|
||||
fi
|
||||
|
||||
# `gh pr view --json commits` doesn't expose signature info, so look
|
||||
# it up via the REST commit endpoint.
|
||||
first_verified=$(gh api "repos/$REPO/commits/$first_oid" --jq '.commit.verification.verified')
|
||||
if [ "$first_verified" != "true" ]; then
|
||||
fail "first commit (Dependabot) does not have a verified signature"
|
||||
fi
|
||||
|
||||
second_email=$(echo "$commits_json" | jq -r '.commits[1].authors[0].email // ""')
|
||||
second_message=$(echo "$commits_json" | jq -r '.commits[1].messageHeadline // ""')
|
||||
if [ "$second_email" != "wrangler@cloudflare.com" ]; then
|
||||
fail "second commit author email is '$second_email', expected 'wrangler@cloudflare.com'"
|
||||
fi
|
||||
if ! echo "$second_message" | grep -qE '^Update dependencies of '; then
|
||||
fail "second commit message '$second_message' does not match expected changeset commit shape"
|
||||
fi
|
||||
|
||||
# --- Changed files allowlist ---------------------------------------
|
||||
# The only paths a workerd bump should touch:
|
||||
# - .changeset/dependabot-update-*.md (added by the changeset job)
|
||||
# - packages/*/package.json (workerd, workers-types pins)
|
||||
# - pnpm-lock.yaml
|
||||
# - pnpm-workspace.yaml (catalog entries)
|
||||
allowed='^(\.changeset/dependabot-update-.*\.md|packages/[^/]+/package\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml)$'
|
||||
|
||||
unexpected=$(echo "$files_json" | jq -r '.files[].path' | grep -vE "$allowed" || true)
|
||||
if [ -n "$unexpected" ]; then
|
||||
fail "PR touches unexpected files:$(echo "$unexpected" | sed 's/^/ /' | tr '\n' ',')"
|
||||
fi
|
||||
|
||||
# Make sure the changeset is actually present — the changeset job
|
||||
# may not have run yet, in which case we bail and wait for the
|
||||
# `synchronize` event from its push.
|
||||
if ! echo "$files_json" | jq -e '.files[] | select(.path | startswith(".changeset/dependabot-update-"))' > /dev/null; then
|
||||
fail "changeset file not yet present; waiting for changeset job to push it"
|
||||
fi
|
||||
|
||||
echo "verified=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Enable auto-merge
|
||||
if: steps.meta.outputs.dependency-group == 'workerd-and-workers-types' && steps.verify.outputs.verified == 'true'
|
||||
run: gh pr merge --auto --squash "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Disable auto-merge if verification failed
|
||||
# If a previous run enabled auto-merge but a later push broke the
|
||||
# invariants, actively cancel auto-merge so the bad commit can't ride.
|
||||
# `gh pr merge --disable-auto` is a no-op (and exits 0) if auto-merge
|
||||
# was never enabled, so this is safe to always run on the failure path.
|
||||
if: always() && steps.meta.outputs.dependency-group == 'workerd-and-workers-types' && steps.verify.outputs.verified != 'true'
|
||||
run: gh pr merge --disable-auto "$PR_URL" || true
|
||||
env:
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,90 @@
|
||||
name: Deploy Previews
|
||||
|
||||
# This workflow is designed to deploy a "preview" version of a project based on PR labels.
|
||||
|
||||
# Triggers:
|
||||
# - update to a PR that has one of the `preview:...` labels
|
||||
#
|
||||
# Actions:
|
||||
# - deploy the matching project to Cloudflare.
|
||||
#
|
||||
# PR Label | Project
|
||||
# ---------------------------------------------------------
|
||||
# preview:chrome-devtools-patches | packages/chrome-devtools-patches
|
||||
# preview:quick-edit | packages/quick-edit
|
||||
#
|
||||
# Note: this workflow does not run tests against these packages, only deploys previews.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# pull-request:write permission needed so that the workflow can comment on PRs
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
deploy-projects:
|
||||
# Only run this on PRs that are for the "cloudflare" org and not "from" `main`
|
||||
# - non-Cloudflare PRs will not have the secrets needed
|
||||
# - PRs "from" main would accidentally do a production deployment
|
||||
if: github.repository_owner == 'cloudflare' && github.head_ref != 'main' && (contains(github.event.*.labels.*.name, 'preview:chrome-devtools-patches') || contains(github.event.*.labels.*.name, 'preview:quick-edit'))
|
||||
timeout-minutes: 60
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-app-previews
|
||||
runs-on: macos-latest-large
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Build tools and libraries
|
||||
run: pnpm run build
|
||||
env:
|
||||
NODE_ENV: "production"
|
||||
CI_OS: ${{ runner.os }}
|
||||
|
||||
- name: Deploy Wrangler DevTools preview
|
||||
if: contains(github.event.*.labels.*.name, 'preview:chrome-devtools-patches')
|
||||
run: |
|
||||
output=$(pnpm --filter @cloudflare/chrome-devtools-patches run deploy:preview)
|
||||
echo "Command output: $output"
|
||||
echo "Extracting deployed URL from command output"
|
||||
url=$(echo "$output" | sed -nE "s/.*Version Preview URL: ([^[:space:]]+).*/\1/p")
|
||||
echo "Extracted URL: $url"
|
||||
echo "VITE_DEVTOOLS_PREVIEW_URL=$url" >> $GITHUB_ENV
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
- name: Build and Deploy Quick Edit preview
|
||||
if: contains(github.event.*.labels.*.name, 'preview:quick-edit')
|
||||
run: pnpm --filter quick-edit run preview
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
NODE_OPTIONS: "--max_old_space_size=30000"
|
||||
|
||||
- name: "Comment on PR with Devtools Link"
|
||||
if: contains(github.event.*.labels.*.name, 'preview:chrome-devtools-patches')
|
||||
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff # v3.0.3
|
||||
with:
|
||||
header: chrome-devtools-preview
|
||||
message: |
|
||||
The Wrangler DevTools preview is now live. You can access it directly at: ${{ env.VITE_DEVTOOLS_PREVIEW_URL }}/js_app
|
||||
|
||||
In order to test the DevTools preview in `wrangler`:
|
||||
|
||||
1. `npx wrangler dev`.
|
||||
2. Hit `d` to open the DevTools in a fresh browser window.
|
||||
3. Paste the DevTools preview URL into the address bar (keeping all existing query parameters), e.g:
|
||||
|
||||
```
|
||||
- https://devtools.devprod.cloudflare.dev/js_app?theme=systemPreferred&ws=127.0.0.1%3A9229%2Fws&domain=tester&debugger=true
|
||||
+ ${{ env.VITE_DEVTOOLS_PREVIEW_URL }}/js_app?theme=systemPreferred&ws=127.0.0.1%3A9229%2Fws&domain=tester&debugger=true
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
name: Local Explorer UI E2E
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# We run `playwright install` manually instead
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Local Explorer UI E2E
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
relevant:
|
||||
- 'packages/local-explorer-ui/**'
|
||||
- 'packages/miniflare/src/workers/local-explorer/**'
|
||||
- 'fixtures/worker-with-resources/**'
|
||||
- 'fixtures/shared/**'
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
|
||||
- name: Install Playwright
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
run: pnpm --filter @cloudflare/local-explorer-ui playwright:install
|
||||
|
||||
- name: Build wrangler
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
run: pnpm turbo build --filter wrangler
|
||||
|
||||
- name: Run Local Explorer UI E2E tests
|
||||
if: steps.changes.outputs.relevant == 'true'
|
||||
run: pnpm test:e2e -F @cloudflare/local-explorer-ui --log-order=stream
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
CI_OS: Linux
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
|
||||
- name: Upload turbo logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: turbo-runs
|
||||
path: .turbo/runs
|
||||
@@ -0,0 +1,33 @@
|
||||
# This workflow cleans up any leftover projects created by e2e runs.
|
||||
|
||||
name: E2E Project Cleanup
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 */2 * * *" # Run every 2 hours
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
timeout-minutes: 30
|
||||
name: "Cleanup Test Projects"
|
||||
if: ${{ github.repository_owner == 'cloudflare' }}
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Cleanup E2E test projects
|
||||
run: node -r esbuild-register tools/e2e/e2eCleanup.ts
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.TEST_CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.TEST_CLOUDFLARE_ACCOUNT_ID }}
|
||||
@@ -0,0 +1,73 @@
|
||||
name: Vite Plugin E2E
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
e2e-vite-plugin-test:
|
||||
name: ${{ format('Vite Plugin E2E ({0})', matrix.description) }}
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-latest
|
||||
description: macOS
|
||||
- os: windows-latest
|
||||
description: Windows
|
||||
- os: ubuntu-latest
|
||||
description: Linux
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Check if remote tests should run
|
||||
id: check-remote
|
||||
uses: ./.github/actions/check-remote-tests
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: Run Vite plugin E2E tests
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
run: pnpm test:e2e -F @cloudflare/vite-plugin --log-order=stream
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
NODE_DEBUG: "vite-plugin:test"
|
||||
# The remote-binding tests need to connect to Cloudflare
|
||||
CLOUDFLARE_API_TOKEN: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_API_TOKEN || '' }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_ACCOUNT_ID || '' }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
CI_OS: ${{ matrix.os }}
|
||||
|
||||
- name: Upload turbo logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: turbo-runs-${{ matrix.os }}
|
||||
path: .turbo/runs
|
||||
@@ -0,0 +1,88 @@
|
||||
name: Wrangler E2E
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
e2e-wrangler-test:
|
||||
name: ${{ format('Wrangler E2E ({0}, shard {1}/4)', matrix.description, matrix.shard) }}
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.shard }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
shard: [1, 2, 3, 4]
|
||||
include:
|
||||
- os: macos-latest
|
||||
description: macOS
|
||||
- os: windows-latest
|
||||
description: Windows
|
||||
- os: ubuntu-latest
|
||||
description: Linux
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Check if remote tests should run
|
||||
id: check-remote
|
||||
uses: ./.github/actions/check-remote-tests
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: Run Wrangler E2E tests
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
run: pnpm run test:e2e:wrangler
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_API_TOKEN || '' }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_ACCOUNT_ID || '' }}
|
||||
HYPERDRIVE_DATABASE_URL: ${{ secrets.TEST_HYPERDRIVE_DATABASE_URL}}
|
||||
HYPERDRIVE_MYSQL_DATABASE_URL: ${{ secrets.TEST_HYPERDRIVE_MYSQL_DATABASE_URL}}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/index.html
|
||||
CI_OS: ${{ matrix.os }}
|
||||
E2E_SHARD: ${{ matrix.shard }}
|
||||
E2E_SHARD_COUNT: "4"
|
||||
|
||||
- name: Run getPlatformProxy() remote-bindings e2e tests
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.shard == 1
|
||||
run: pnpm run test:e2e -F @fixture/get-platform-proxy-remote-bindings
|
||||
env:
|
||||
TEST_CLOUDFLARE_API_TOKEN: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_API_TOKEN || '' }}
|
||||
TEST_CLOUDFLARE_ACCOUNT_ID: ${{ steps.check-remote.outputs.run-remote == 'true' && secrets.TEST_CLOUDFLARE_ACCOUNT_ID || '' }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
CI_OS: ${{ matrix.os }}
|
||||
|
||||
- name: Upload turbo logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: turbo-runs-${{ matrix.os }}-shard-${{ matrix.shard }}
|
||||
path: .turbo/runs
|
||||
@@ -0,0 +1,82 @@
|
||||
name: Release a hotfix
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr-number:
|
||||
description: "Which PR should be released?"
|
||||
required: true
|
||||
confirm:
|
||||
description: "Confirm that the PR is up to date with the last published release, with the specific additional changes that should be released as part of this hotfix and the relevant package patch versions bumped"
|
||||
type: boolean
|
||||
required: true
|
||||
label:
|
||||
description: "Which dist-tag should this release have?"
|
||||
type: string
|
||||
default: hotfix
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
hotfix-release:
|
||||
name: Hotfix Release
|
||||
if: ${{ inputs.confirm == true }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check user for team affiliation
|
||||
uses: tspascoal/get-user-teams-membership@ba78054988f58bea69b7c6136d563236f8ed2fc0 # v2
|
||||
id: teamAffiliation
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.READ_ONLY_ORG_GITHUB_TOKEN }}
|
||||
username: ${{ github.actor }}
|
||||
team: wrangler
|
||||
|
||||
- name: Stop workflow if user is not a wrangler team member
|
||||
if: ${{ steps.teamAffiliation.outputs.isTeamMember == false }}
|
||||
run: |
|
||||
echo "You must be on the "wrangler" team to trigger this job."
|
||||
exit 1
|
||||
|
||||
- name: "Checkout PR"
|
||||
run: |
|
||||
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
|
||||
echo "::error::PR number must be numeric"
|
||||
exit 1
|
||||
fi
|
||||
gh pr checkout "$PR_NUMBER"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
PR_NUMBER: ${{ inputs.pr-number }}
|
||||
|
||||
- name: Install Dependencies
|
||||
# Defense in depth: do not pass Turbo remote cache credentials and
|
||||
# disable the pnpm store cache so release builds always resolve
|
||||
# packages from the registry and rebuild every task from source,
|
||||
# rather than restoring from a (potentially poisoned) cache.
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
disable-cache: "true"
|
||||
|
||||
- name: Build all packages
|
||||
run: pnpm run build
|
||||
env:
|
||||
CI_OS: ${{ runner.os }}
|
||||
|
||||
- name: Publish packages
|
||||
run: |
|
||||
if ! [[ "$NPM_TAG" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
||||
echo "::error::npm dist-tag contains unsupported characters"
|
||||
exit 1
|
||||
fi
|
||||
pnpm publish -r --tag "$NPM_TAG" --filter wrangler --filter miniflare --filter create-cloudflare
|
||||
env:
|
||||
NPM_TAG: ${{ inputs.label }}
|
||||
@@ -0,0 +1,41 @@
|
||||
name: Add issues to DevProd project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, transferred]
|
||||
|
||||
permissions:
|
||||
# issues:write permission needed so that the workflow can manage issues
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/cloudflare/projects/1
|
||||
github-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
labeled: bug, enhancement
|
||||
label-operator: OR
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/cloudflare/projects/2
|
||||
github-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
labeled: product:pages
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/cloudflare/projects/6
|
||||
github-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
labeled: product:d1
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/cloudflare/projects/12
|
||||
github-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
labeled: product:c3
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/cloudflare/projects/8
|
||||
github-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
labeled: product:queues
|
||||
@@ -0,0 +1,51 @@
|
||||
name: "Miniflare - Generate changesets for dependabot PRs"
|
||||
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] dependabot-only job requires write access to push generated changesets; checkout v6 persists credentials under RUNNER_TEMP
|
||||
paths:
|
||||
- "packages/miniflare/package.json"
|
||||
- "pnpm-workspace.yaml"
|
||||
|
||||
permissions:
|
||||
# content:write permission needed to update add changesets to dependabot PRs
|
||||
# (see tools/dependabot/generate-dependabot-pr-changesets.ts)
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
generate-changeset:
|
||||
runs-on: ubuntu-slim
|
||||
if: |
|
||||
github.actor == 'dependabot[bot]' &&
|
||||
github.event.pull_request.user.login == 'dependabot[bot]' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: true
|
||||
ref: ${{ github.head_ref }}
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.email wrangler@cloudflare.com
|
||||
git config --global user.name 'Wrangler automated PR updater'
|
||||
|
||||
- name: Generate Miniflare changesets
|
||||
# The paremeters to the script are:
|
||||
# - PR: The number of the current Dependabot PR
|
||||
# - Packages: Coma-separated names of the workers-sdk packages whose dependencies are being updated
|
||||
# - PackageJSON: The path to the package JSON being updated by Dependabot
|
||||
# - Changeset prefix: The prefix to go on the front of the filename of the generated changeset
|
||||
run: >-
|
||||
node -r esbuild-register tools/dependabot/generate-dependabot-pr-changesets.ts
|
||||
"$PR_NUMBER"
|
||||
miniflare,wrangler
|
||||
packages/miniflare/package.json
|
||||
dependabot-update
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
@@ -0,0 +1,19 @@
|
||||
name: OpenCode Issue Solver
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue-number:
|
||||
description: "Issue number to attempt to fix"
|
||||
required: true
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
assess-issue:
|
||||
runs-on: ubuntu-latest
|
||||
permissions: {}
|
||||
|
||||
steps:
|
||||
- name: Exit
|
||||
run: |
|
||||
exit 1
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Prerelease
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- d1
|
||||
- workflows
|
||||
- next
|
||||
- v3-maintenance
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ github.repository_owner == 'cloudflare' }}
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
# Defense in depth: do not pass Turbo remote cache credentials and
|
||||
# disable the pnpm store cache so release builds always resolve
|
||||
# packages from the registry and rebuild every task from source,
|
||||
# rather than restoring from a (potentially poisoned) cache.
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
disable-cache: "true"
|
||||
|
||||
- name: Build
|
||||
run: pnpm build --filter="./packages/*"
|
||||
env:
|
||||
NODE_ENV: "production"
|
||||
CI_OS: ${{ runner.os }}
|
||||
# this is the "test/staging" key for sparrow analytics
|
||||
SPARROW_SOURCE_KEY: "5adf183f94b3436ba78d67f506965998"
|
||||
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
|
||||
SENTRY_DSN: "https://9edbb8417b284aa2bbead9b4c318918b@sentry10.cfdata.org/583"
|
||||
ALGOLIA_PUBLIC_KEY: ${{ secrets.ALGOLIA_PUBLIC_KEY }}
|
||||
WRANGLER_PRERELEASE_LABEL: ${{ github.head_ref || github.ref_name }}
|
||||
|
||||
- name: Upload packages
|
||||
run: node -r esbuild-register .github/prereleases/upload.mjs
|
||||
@@ -0,0 +1,67 @@
|
||||
name: "Rerun Code Owners (Privileged)"
|
||||
|
||||
# Privileged companion to rerun-codeowners.yml.
|
||||
#
|
||||
# Runs after the "Rerun Code Owners" trigger workflow completes. The
|
||||
# workflow_run event always executes from the default branch with full
|
||||
# permissions — this is what allows us to call the Actions API even when the
|
||||
# original event (pull_request_review) came from a fork PR, where the
|
||||
# GITHUB_TOKEN would otherwise be read-only.
|
||||
#
|
||||
# The PR head SHA is read from github.event.workflow_run.head_sha — this is
|
||||
# GitHub-provided metadata and cannot be manipulated by fork code (unlike
|
||||
# the previous artifact-based approach).
|
||||
#
|
||||
# Strategy: CHECK-NAME LOOKUP
|
||||
# ----------------------------
|
||||
# The codeowners.yml workflow uses pull_request_target, which means its
|
||||
# workflow runs are indexed by the BASE branch SHA (e.g. main), NOT the PR
|
||||
# head SHA. So we cannot find the run via:
|
||||
#
|
||||
# GET /actions/workflows/codeowners.yml/runs?head_sha=<PR_HEAD>
|
||||
#
|
||||
# That query returns nothing because the run's head_sha is main's HEAD.
|
||||
#
|
||||
# However, the codeowners-plus action creates its CHECK RUN on the PR head
|
||||
# commit (so the status appears on the PR). The check-runs API lets us look
|
||||
# up by check name + commit SHA:
|
||||
#
|
||||
# GET /commits/<PR_HEAD>/check-runs?check_name=Run+Codeowners+Plus
|
||||
#
|
||||
# From the check run's details_url we extract the Actions job ID, then
|
||||
# re-run that specific job.
|
||||
on:
|
||||
workflow_run: # zizmor: ignore[dangerous-triggers] privileged companion reruns a fixed default-branch workflow using GitHub-provided workflow_run metadata only
|
||||
workflows: ["Rerun Code Owners"]
|
||||
types: [completed]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
rerun-codeowners:
|
||||
name: "Rerun Codeowners Plus"
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
permissions:
|
||||
actions: write
|
||||
checks: read
|
||||
steps:
|
||||
- name: Re-run Codeowners check
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
# Find the "Run Codeowners Plus" check run on the PR head commit
|
||||
# and extract the Actions job ID from the check run's details URL
|
||||
# (the last path segment before any query string).
|
||||
job_id=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs?check_name=Run+Codeowners+Plus" \
|
||||
--jq '(.check_runs[0].details_url // "") | split("/") | last | split("?") | first' || true)
|
||||
|
||||
if [ -n "$job_id" ]; then
|
||||
gh api "repos/${REPO}/actions/jobs/${job_id}/rerun" --method POST \
|
||||
|| echo "::warning::Job ${job_id} may already be running"
|
||||
echo "Re-triggered 'Run Codeowners Plus' (job ${job_id})"
|
||||
else
|
||||
echo "::warning::Check 'Run Codeowners Plus' not found for SHA ${HEAD_SHA}"
|
||||
fi
|
||||
@@ -0,0 +1,35 @@
|
||||
name: "Rerun Code Owners"
|
||||
|
||||
# Trigger: a review is submitted or dismissed on a pull request.
|
||||
#
|
||||
# Goal: re-run the "Run Codeowners Plus" check from the main codeowners.yml
|
||||
# workflow (which is triggered by pull_request_target) so it re-evaluates
|
||||
# approval status after the review change.
|
||||
#
|
||||
# Why a two-workflow design?
|
||||
# -------------------------
|
||||
# For fork PRs, pull_request_review gives a read-only GITHUB_TOKEN and no
|
||||
# access to secrets. Unlike labeled/unlabeled events there is no
|
||||
# pull_request_review variant of pull_request_target, so we cannot get a
|
||||
# privileged token in a single workflow. Instead this workflow simply needs
|
||||
# to *exist and succeed* — the companion workflow
|
||||
# (rerun-codeowners-privileged.yml) is triggered by the workflow_run event
|
||||
# when THIS workflow completes. workflow_run always runs from the default
|
||||
# branch with full permissions, and it reads the PR head SHA directly from
|
||||
# github.event.workflow_run.head_sha (GitHub-provided metadata, not
|
||||
# controllable by fork code).
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [submitted, dismissed]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
name: "Trigger Privileged Rerun"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Log trigger
|
||||
run: echo "Review event on ${PR_URL}, privileged rerun will follow."
|
||||
env:
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
@@ -0,0 +1,86 @@
|
||||
name: "Rerun Remote Tests"
|
||||
|
||||
# Trigger: the "run-remote-tests" or "run-c3-frameworks-tests" label is added
|
||||
# to or removed from a pull request.
|
||||
#
|
||||
# Goal: re-run the E2E workflows (e2e-wrangler.yml, e2e-vite.yml, c3-e2e.yml)
|
||||
# so they pick up the label change and either pass or withhold the Cloudflare
|
||||
# API token to the test steps. This avoids adding "labeled" as a trigger type
|
||||
# to every E2E workflow (which would cause wasteful re-runs on unrelated label
|
||||
# changes).
|
||||
#
|
||||
# Using pull_request_target (not pull_request) so the workflow has access to a
|
||||
# privileged GITHUB_TOKEN even for fork PRs. This is safe because the workflow
|
||||
# runs code from the default branch — fork authors cannot modify it — and only
|
||||
# calls the Actions API (no checkout of untrusted code).
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] label-driven rerun workflow needs actions:write and does not check out or execute PR code
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
rerun-e2e:
|
||||
name: "Rerun E2E Tests"
|
||||
if: github.event.label.name == 'ci:run-remote-tests' || github.event.label.name == 'run-c3-frameworks-tests'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: "Re-run E2E workflows"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
LABEL_NAME: ${{ github.event.label.name }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
# Determine which workflows to re-run based on the label.
|
||||
if [ "$LABEL_NAME" = "ci:run-remote-tests" ]; then
|
||||
WORKFLOWS="e2e-wrangler.yml e2e-vite.yml c3-e2e.yml"
|
||||
else
|
||||
WORKFLOWS="c3-e2e.yml"
|
||||
fi
|
||||
|
||||
for workflow in ${WORKFLOWS}; do
|
||||
# Find the most recent run of this workflow at the PR head SHA.
|
||||
run_info=$(gh api "repos/${REPO}/actions/workflows/${workflow}/runs?head_sha=${HEAD_SHA}&per_page=1" \
|
||||
--jq '.workflow_runs[0] | "\(.id) \(.status)"' || true)
|
||||
|
||||
run_id=$(echo "$run_info" | awk '{print $1}')
|
||||
status=$(echo "$run_info" | awk '{print $2}')
|
||||
|
||||
if [ -z "$run_id" ] || [ "$run_id" = "null" ]; then
|
||||
echo "::warning::No run found for ${workflow} at SHA ${HEAD_SHA}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Runs that haven't started yet will see the newly-added label
|
||||
# when they begin — no need to cancel and re-run them.
|
||||
if [ "$status" != "completed" ] && [ "$status" != "in_progress" ]; then
|
||||
echo "${workflow} run ${run_id} is ${status} — not yet started, skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
# If the run is actively executing, the label check has already
|
||||
# evaluated (likely to the old value). Cancel it first — the
|
||||
# rerun endpoint only works on completed runs.
|
||||
if [ "$status" = "in_progress" ]; then
|
||||
echo "Cancelling in-progress ${workflow} run ${run_id}..."
|
||||
gh api "repos/${REPO}/actions/runs/${run_id}/cancel" --method POST || true
|
||||
|
||||
# Cancellation is async; poll until the run reaches "completed".
|
||||
for i in $(seq 1 30); do
|
||||
current=$(gh api "repos/${REPO}/actions/runs/${run_id}" --jq '.status')
|
||||
if [ "$current" = "completed" ]; then
|
||||
echo "Run ${run_id} is now completed (cancelled)."
|
||||
break
|
||||
fi
|
||||
echo " Waiting for cancellation to finish (${i}/30, status: ${current})..."
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
|
||||
gh api "repos/${REPO}/actions/runs/${run_id}/rerun" --method POST \
|
||||
&& echo "Re-triggered ${workflow} (run ${run_id})" \
|
||||
|| echo "::warning::Failed to re-run ${workflow} (run ${run_id})"
|
||||
done
|
||||
@@ -0,0 +1,100 @@
|
||||
name: Run CI on behalf of External Forks
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr-number:
|
||||
description: "The PR number to run CI on behalf of"
|
||||
required: true
|
||||
commit-sha:
|
||||
description: "The specific commit SHA from the PR branch to run CI on"
|
||||
required: true
|
||||
reviewed:
|
||||
description: "Confirm that the PR has been reviewed for use/leakage of secrets"
|
||||
type: boolean
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read # no write permissions are needed since the workflow uses GH_ACCESS_TOKEN instead of GITHUB_TOKEN
|
||||
pull-requests: write # Required for creating or updating the draft PR on behalf of the user
|
||||
|
||||
jobs:
|
||||
create-draft-pr:
|
||||
name: Create or Update Draft PR
|
||||
if: ${{ inputs.reviewed == true }}
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
- name: Check user for team affiliation
|
||||
uses: tspascoal/get-user-teams-membership@ba78054988f58bea69b7c6136d563236f8ed2fc0
|
||||
id: teamAffiliation
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.READ_ONLY_ORG_GITHUB_TOKEN }}
|
||||
username: ${{ github.actor }}
|
||||
team: wrangler
|
||||
|
||||
- name: Stop workflow if user is not a team member
|
||||
if: ${{ steps.teamAffiliation.outputs.isTeamMember != 'true' }}
|
||||
run: |
|
||||
echo "You must be on the \"wrangler\" team to trigger this job."
|
||||
exit 1
|
||||
|
||||
- name: "Checkout PR"
|
||||
run: |
|
||||
gh pr checkout "$PR_NUM" --branch "run-ci-on-behalf-of-$PR_NUM"
|
||||
git reset --hard "$COMMIT_SHA"
|
||||
env:
|
||||
# We need a PAT to checkout the fork
|
||||
GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
PR_NUM: ${{ inputs.pr-number }}
|
||||
COMMIT_SHA: ${{ inputs.commit-sha }}
|
||||
|
||||
- name: Push Branch
|
||||
run: |
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "github-actions[bot]"
|
||||
git push origin HEAD --force
|
||||
|
||||
- name: "Create or Update Draft PR"
|
||||
run: |
|
||||
existing_pr=$(gh pr list \
|
||||
--head "run-ci-on-behalf-of-$PR_NUM" \
|
||||
--state open \
|
||||
--json number \
|
||||
--jq 'first(.[].number) // ""')
|
||||
|
||||
if [ -n "$existing_pr" ]; then
|
||||
gh pr edit "$existing_pr" \
|
||||
--add-label "ci:e2e" \
|
||||
--add-label "ci:run-remote-tests" \
|
||||
--title "$TITLE" \
|
||||
--body "$BODY"
|
||||
else
|
||||
gh pr create \
|
||||
--head "run-ci-on-behalf-of-$PR_NUM" \
|
||||
--draft \
|
||||
--label "ci:e2e" \
|
||||
--label "ci:run-remote-tests" \
|
||||
--title "$TITLE" \
|
||||
--body "$BODY"
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
PR_NUM: ${{ inputs.pr-number }}
|
||||
TITLE: "Run CI on behalf of #${{ inputs.pr-number }} @${{ inputs.commit-sha }}"
|
||||
BODY: "This PR runs CI on behalf of #${{ inputs.pr-number }} at commit ${{ inputs.commit-sha }}. It can be closed after the CI run is complete."
|
||||
|
||||
- name: "Trigger CI"
|
||||
run: |
|
||||
# Push an empty commit to trigger CI workflows
|
||||
# This ensures CI runs because the PR already exists when this push happens
|
||||
git commit --allow-empty -m "Trigger CI for #$PR_NUM"
|
||||
git push origin HEAD
|
||||
env:
|
||||
PR_NUM: ${{ inputs.pr-number }}
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Semgrep OSS scan
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch: {}
|
||||
schedule:
|
||||
- cron: "0 0 15 * *"
|
||||
concurrency:
|
||||
group: semgrep-${{ github.event_name }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
semgrep:
|
||||
name: semgrep-oss
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
- id: cache-semgrep
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: ~/.local
|
||||
key: semgrep-1.160.0-${{ runner.os }}
|
||||
- if: steps.cache-semgrep.outputs.cache-hit != 'true'
|
||||
run: pip install --user semgrep==1.160.0
|
||||
- run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
- run: semgrep scan --config=auto || true
|
||||
@@ -0,0 +1,118 @@
|
||||
name: CI (Other Node Versions)
|
||||
description: Run primary tests on other supported Node.js versions
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test-other-node-versions:
|
||||
timeout-minutes: 45
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.node_version }}-test-other-node-versions
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
name: ${{ format('Tests ({0})', matrix.description) }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# expected_to_fail: if true, tests may fail on this Node version.
|
||||
# These versions are skipped on normal PRs but run on Version Packages PRs
|
||||
# (changeset-release/main) or when the 'ci:test-all-node-versions' label is added.
|
||||
#
|
||||
# Node 24 is pinned to 24.18.0 (rather than floating `24`): Node 24.17.0
|
||||
# regressed node-fetch@2 keep-alive responses with ERR_STREAM_PREMATURE_CLOSE
|
||||
# (nodejs/node#63989, fixed in 24.18.0). `description` stays "Node 24" to
|
||||
# keep the job/check name stable.
|
||||
include:
|
||||
- {
|
||||
node_version: 24.18.0,
|
||||
description: "Node 24",
|
||||
expected_to_fail: true,
|
||||
}
|
||||
- { node_version: 25, description: "Node 25", expected_to_fail: true }
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Filter changed paths
|
||||
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Check if should run tests
|
||||
id: should_run
|
||||
env:
|
||||
CHANGES_EVERYTHING_BUT_MARKDOWN: ${{ steps.changes.outputs.everything_but_markdown }}
|
||||
EXPECTED_TO_FAIL: ${{ matrix.expected_to_fail }}
|
||||
HAS_TEST_ALL_NODE_VERSIONS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'ci:test-all-node-versions') }}
|
||||
HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
if [[ "$CHANGES_EVERYTHING_BUT_MARKDOWN" == "true" ]] && \
|
||||
[[ "$EXPECTED_TO_FAIL" != "true" || \
|
||||
"$HEAD_REF" == "changeset-release/main" || \
|
||||
"$HAS_TEST_ALL_NODE_VERSIONS_LABEL" == "true" ]]; then
|
||||
echo "result=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "result=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.should_run.outputs.result == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
# The miniflare browser-rendering tests download Chrome (~150 MB) via
|
||||
# @puppeteer/browsers at runtime. Caching the binary avoids repeat
|
||||
# downloads and reduces the chance of tests hanging while waiting for
|
||||
# the download to finish within their timeout window.
|
||||
- name: Restore Chrome browser cache (Browser Run)
|
||||
if: steps.should_run.outputs.result == 'true'
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
key: chrome-${{ runner.os }}-${{ hashFiles('packages/miniflare/src/plugins/browser-rendering/browser-version.ts') }}
|
||||
path: |
|
||||
~/.cache/.wrangler/chrome
|
||||
|
||||
- name: Run tests (packages)
|
||||
# We are running the package tests first be able to get early feedback on changes.
|
||||
# There is no point in running the fixtures if a package is broken.
|
||||
if: steps.should_run.outputs.result == 'true'
|
||||
run: pnpm run test:ci --log-order=stream --concurrency=1 --filter="./packages/*"
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/packages/index.html
|
||||
CI_OS: ${{ matrix.description }}
|
||||
|
||||
- name: Run e2e tests (unenv-preset)
|
||||
if: steps.should_run.outputs.result == 'true'
|
||||
run: pnpm test:e2e --filter wrangler -- unenv-preset
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
CI_OS: ${{ matrix.description }}
|
||||
|
||||
- name: Run tests (vite-plugin)
|
||||
if: steps.should_run.outputs.result == 'true'
|
||||
run: pnpm test:ci --filter @cloudflare/vite-plugin
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
CI_OS: ${{ matrix.description }}
|
||||
@@ -0,0 +1,202 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# We run `playwright install` manually instead
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
if: github.head_ref != 'changeset-release/main'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-add-pr
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 30
|
||||
name: Add PR to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: curl -X POST https://devprod-status-bot.devprod.workers.dev/pr-project/workers-sdk/${{ github.event.number }}
|
||||
|
||||
check:
|
||||
timeout-minutes: 30
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-checks
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
name: "Checks"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: Check the changesets
|
||||
run: node -r esbuild-register tools/deployments/validate-changesets.ts
|
||||
|
||||
- name: Check for errors
|
||||
run: pnpm run check --summarize
|
||||
env:
|
||||
CI_OS: ${{ runner.os }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
|
||||
- name: Filter changed paths
|
||||
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
miniflare_openapi:
|
||||
- 'packages/miniflare/src/workers/local-explorer/openapi.local.json'
|
||||
- 'packages/miniflare/src/workers/local-explorer/generated/**'
|
||||
- 'packages/miniflare/scripts/openapi-filter-config.ts'
|
||||
- 'packages/miniflare/scripts/filter-openapi.ts'
|
||||
- 'packages/miniflare/scripts/check-generate-api.ts'
|
||||
- 'packages/miniflare/openapi-ts.config.ts'
|
||||
|
||||
- name: Check generated OpenAPI types are up to date
|
||||
if: steps.changes.outputs.miniflare_openapi == 'true'
|
||||
run: pnpm -F miniflare check:generate-api
|
||||
|
||||
# Check for old Node.js version warnings and errors
|
||||
- name: Use Node.js v20
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Check for error message on Node.js < v22
|
||||
run: node packages/wrangler/src/__tests__/test-old-node-version.js error
|
||||
|
||||
test:
|
||||
timeout-minutes: 30
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.suite }}-test
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
name: ${{ format('Tests ({0}, {1})', matrix.description, matrix.suite) }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
suite:
|
||||
- packages-and-tools
|
||||
- fixtures
|
||||
include:
|
||||
- os: macos-latest
|
||||
description: macOS
|
||||
- os: ubuntu-latest
|
||||
description: Linux
|
||||
- os: windows-latest
|
||||
description: Windows
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Filter changed paths
|
||||
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
# Browser Run tests in `packages/miniflare/test/plugins/browser/index.spec.ts`
|
||||
# and the `fixtures/browser-run` fixture use `@puppeteer/browsers` to
|
||||
# download Chrome into the global Wrangler cache. Caching that binary
|
||||
# across CI runs avoids ~150 MB of repeat downloads per run and reduces
|
||||
# the surface area for the intermittent partial-extraction race that
|
||||
# surfaces as `The browser folder (...) exists but the executable (...)
|
||||
# is missing` (see #13971, #13980).
|
||||
#
|
||||
# The Browser Run fixture is skipped on Ubuntu (AppArmor), but the
|
||||
# miniflare browser spec runs everywhere, so the cache is needed on all
|
||||
# three OSes for `packages-and-tools` and on Windows + macOS for
|
||||
# `fixtures`.
|
||||
- name: Restore Chrome browser cache (Browser Run)
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && (matrix.suite == 'packages-and-tools' || (matrix.suite == 'fixtures' && matrix.os != 'ubuntu-latest'))
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
# The Chrome version lives in
|
||||
# `packages/miniflare/src/plugins/browser-rendering/browser-version.ts`.
|
||||
# Bumping that constant invalidates this cache automatically via
|
||||
# `hashFiles()` — a cache miss only triggers a fresh download, no
|
||||
# functional impact.
|
||||
key: chrome-${{ runner.os }}-${{ hashFiles('packages/miniflare/src/plugins/browser-rendering/browser-version.ts') }}
|
||||
path: |
|
||||
~/.cache/.wrangler/chrome
|
||||
~/Library/Caches/.wrangler/chrome
|
||||
~/AppData/Local/xdg.cache/.wrangler/chrome
|
||||
|
||||
- name: Run tests (tools only)
|
||||
# tools _only_ needs to be tested on Linux because they're only intended to run in CI
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.suite == 'packages-and-tools' && matrix.os == 'ubuntu-latest'
|
||||
run: pnpm run test:ci --log-order=stream --filter="@cloudflare/tools"
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/tools/index.html
|
||||
CI_OS: ${{ matrix.description }}
|
||||
|
||||
- name: Run tests (packages)
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.suite == 'packages-and-tools'
|
||||
# We skip @cloudflare/vitest-pool-workers tests in CI on Windows because they're very flaky. We still run the vitest-pool-workers-examples fixture, which is a comprehensive set of example tests and gives us a lot of confidence.
|
||||
# The @cloudflare/vitest-pool-workers tests skipped are things like watch mode, which constantly times out probably due to the github runners in use.
|
||||
# Package tests are well-isolated (separate processes, temp dirs, random ports, MSW mocks) and can safely run in parallel.
|
||||
# Concurrency is capped at 3 to avoid CPU starvation on 4-vCPU CI runners when heavyweight suites
|
||||
# (wrangler/forks, miniflare/workerd, vitest-pool-workers/Verdaccio) overlap.
|
||||
run: pnpm run test:ci --log-order=stream --concurrency=3 --filter="./packages/*" ${{ matrix.os == 'windows-latest' && '--filter="!./packages/vitest-pool-workers"' || '' }}
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/packages/index.html
|
||||
CI_OS: ${{ matrix.description }}
|
||||
|
||||
- name: Run tests (fixtures)
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.suite == 'fixtures'
|
||||
# Browser Run fixture is disabled on Ubuntu because of https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu
|
||||
# Since the dev registry is now file-based (not network-based), fixture tests can safely run in parallel.
|
||||
# Concurrency is capped at 2 to avoid CPU starvation on CI runners when multiple fixtures
|
||||
# spawn workerd processes simultaneously (Windows runners are especially slow under load).
|
||||
run: pnpm run test:ci --concurrency=2 --log-order=stream --filter="./fixtures/*" ${{ matrix.os == 'ubuntu-latest' && '--filter="!./fixtures/browser-run"' || '' }}
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/index.html
|
||||
CI_OS: ${{ matrix.description }}
|
||||
|
||||
- name: Upload turbo logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: turbo-runs-${{ matrix.os }}-${{ matrix.suite }}
|
||||
path: .turbo/runs
|
||||
@@ -0,0 +1,235 @@
|
||||
name: Triage Issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue-number:
|
||||
description: "Issue number to triage"
|
||||
required: true
|
||||
type: number
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# Writes (comment + labels) are performed with GH_ACCESS_TOKEN (the
|
||||
# workers-devprod bot) so they are attributed to that identity, not
|
||||
# github-actions[bot]. Only read access is needed from the default token.
|
||||
issues: read
|
||||
|
||||
# Cancel in-progress runs for the same issue
|
||||
concurrency:
|
||||
group: triage-${{ github.event.issue.number || inputs.issue-number }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
# Always run for manual dispatch. For issue events, skip PRs and
|
||||
# bot-created issues. For comment events, skip PRs, bot comments, and the
|
||||
# triage bot's own sticky comment (identified by the marocchino marker) to
|
||||
# avoid infinite re-triage loops.
|
||||
if: >-
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'issues' &&
|
||||
!github.event.issue.pull_request &&
|
||||
github.event.issue.user.type != 'Bot') ||
|
||||
(github.event_name == 'issue_comment' &&
|
||||
!github.event.issue.pull_request &&
|
||||
github.event.comment.user.type != 'Bot' &&
|
||||
!contains(github.event.comment.body, '<!-- Sticky Pull Request Comment'))
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Resolve issue number
|
||||
id: issue
|
||||
env:
|
||||
EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
INPUT_ISSUE_NUMBER: ${{ inputs.issue-number }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
echo "number=${INPUT_ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "number=${EVENT_ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Checkout (sparse — just the skill and opencode config)
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.github/skills
|
||||
.github/opencode.json
|
||||
|
||||
- name: Install OpenCode
|
||||
run: |
|
||||
npm install -g opencode-ai
|
||||
cp .github/opencode.json ./opencode.json
|
||||
|
||||
- name: Fetch issue data
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
ISSUE: ${{ steps.issue.outputs.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
mkdir -p "data/${ISSUE}"
|
||||
|
||||
gh issue view "$ISSUE" \
|
||||
--repo "$REPO" \
|
||||
--json number,title,body,comments,createdAt,updatedAt,labels,state,author \
|
||||
> "data/${ISSUE}/context.json"
|
||||
|
||||
- name: Analyze issue with OpenCode
|
||||
env:
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
|
||||
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
|
||||
ISSUE: ${{ steps.issue.outputs.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
opencode run \
|
||||
--print-logs \
|
||||
"Analyze GitHub issue ${REPO}#${ISSUE} using the skill at .github/skills/issue-review.md.
|
||||
|
||||
The issue data has been pre-fetched to data/${ISSUE}/context.json.
|
||||
Read it with the read tool and follow the triage process.
|
||||
|
||||
Create:
|
||||
- data/${ISSUE}/report.md (full markdown report)
|
||||
- data/${ISSUE}/summary.json (structured JSON summary)
|
||||
"
|
||||
|
||||
- name: Upload report to dashboard
|
||||
env:
|
||||
CF_ACCESS_CLIENT_ID: ${{ secrets.CF1_ACCESS_CLIENT_ID }}
|
||||
CF_ACCESS_CLIENT_SECRET: ${{ secrets.CF1_ACCESS_CLIENT_SECRET }}
|
||||
DASHBOARD_URL: ${{ secrets.REPORTS_DASHBOARD_URL }}
|
||||
ISSUE: ${{ steps.issue.outputs.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
# Check files were created
|
||||
if [ ! -f "data/${ISSUE}/report.md" ]; then
|
||||
echo "::error::report.md was not generated"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "data/${ISSUE}/summary.json" ]; then
|
||||
echo "::error::summary.json was not generated"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate the summary is parseable JSON before doing anything with it.
|
||||
if ! jq empty "data/${ISSUE}/summary.json" 2>/dev/null; then
|
||||
echo "::error::summary.json is not valid JSON"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the dashboard payload from the structured summary + markdown report.
|
||||
# suggestedComment is kept as a "Yes"/"No" string for dashboard compatibility.
|
||||
PAYLOAD=$(jq \
|
||||
--arg githubUrl "https://github.com/${REPO}/issues/${ISSUE}" \
|
||||
--rawfile reportMarkdown "data/${ISSUE}/report.md" \
|
||||
'{
|
||||
title: .title,
|
||||
githubUrl: $githubUrl,
|
||||
recommendation: .recommendation,
|
||||
difficulty: .difficulty,
|
||||
reasoning: .reasoning,
|
||||
suggestedAction: .suggestedAction,
|
||||
suggestedComment: (if .hasSuggestedComment then "Yes" else "No" end),
|
||||
reportMarkdown: $reportMarkdown
|
||||
}' "data/${ISSUE}/summary.json")
|
||||
|
||||
# POST to dashboard API
|
||||
HTTP_STATUS=$(curl -L --post302 -s -o response.json -w "%{http_code}" \
|
||||
-X POST "${DASHBOARD_URL}/api/report/${ISSUE}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}" \
|
||||
-H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}" \
|
||||
-d "$PAYLOAD")
|
||||
|
||||
echo "Dashboard API response: HTTP ${HTTP_STATUS}"
|
||||
cat response.json
|
||||
|
||||
if [ "$HTTP_STATUS" != "200" ]; then
|
||||
echo "::error::Failed to upload report (HTTP ${HTTP_STATUS})"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Report uploaded for issue #${ISSUE}"
|
||||
|
||||
- name: Build triage comment
|
||||
env:
|
||||
ISSUE: ${{ steps.issue.outputs.number }}
|
||||
run: |
|
||||
{
|
||||
echo "> [!NOTE]"
|
||||
echo "> This is an automated, advisory triage report generated by workers-devprod. It is not an official maintainer response — a maintainer will follow up."
|
||||
echo ""
|
||||
echo "<details>"
|
||||
echo "<summary>🤖 Automated triage report</summary>"
|
||||
echo ""
|
||||
cat "data/${ISSUE}/report.md"
|
||||
echo ""
|
||||
echo "</details>"
|
||||
echo ""
|
||||
echo "<details>"
|
||||
echo "<summary>Structured summary (JSON)</summary>"
|
||||
echo ""
|
||||
echo '```json'
|
||||
cat "data/${ISSUE}/summary.json"
|
||||
echo ""
|
||||
echo '```'
|
||||
echo ""
|
||||
echo "</details>"
|
||||
} > "data/${ISSUE}/comment.md"
|
||||
|
||||
- name: Post triage comment
|
||||
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff # v3.0.3
|
||||
with:
|
||||
header: triage-report
|
||||
number: ${{ steps.issue.outputs.number }}
|
||||
path: data/${{ steps.issue.outputs.number }}/comment.md
|
||||
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
- name: Apply suggested labels
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
ISSUE: ${{ steps.issue.outputs.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
SUMMARY_PATH="data/${ISSUE}/summary.json"
|
||||
if [ ! -f "$SUMMARY_PATH" ]; then
|
||||
echo "No summary.json; skipping label application"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# suggestedLabels is a JSON array; emit one label per line.
|
||||
jq -r '.suggestedLabels // [] | .[]' "$SUMMARY_PATH" > suggested-labels.txt
|
||||
if [ ! -s suggested-labels.txt ]; then
|
||||
echo "No suggested labels"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Only apply labels that actually exist in the repo.
|
||||
gh label list --repo "$REPO" --limit 500 --json name --jq '.[].name' > repo-labels.txt
|
||||
|
||||
ARGS=()
|
||||
while IFS= read -r label; do
|
||||
if [ -z "$label" ]; then
|
||||
continue
|
||||
fi
|
||||
if grep -Fxq "$label" repo-labels.txt; then
|
||||
ARGS+=(--add-label "$label")
|
||||
else
|
||||
echo "Skipping unknown label: ${label}"
|
||||
fi
|
||||
done < suggested-labels.txt
|
||||
|
||||
if [ ${#ARGS[@]} -eq 0 ]; then
|
||||
echo "No valid labels to apply"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
gh issue edit "$ISSUE" --repo "$REPO" "${ARGS[@]}"
|
||||
@@ -0,0 +1,68 @@
|
||||
name: Validate PR Description
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types:
|
||||
[
|
||||
opened,
|
||||
synchronize,
|
||||
reopened,
|
||||
labeled,
|
||||
unlabeled,
|
||||
edited,
|
||||
ready_for_review,
|
||||
converted_to_draft,
|
||||
]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
# Don't check the Version Packages PR or merge queue jobs
|
||||
if: github.event_name != 'merge_group' && github.head_ref != 'changeset-release/main'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-add-pr
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
timeout-minutes: 30
|
||||
name: Check
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
|
||||
- name: List changed files
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
id: files
|
||||
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
|
||||
with:
|
||||
format: "json"
|
||||
|
||||
- run: node -r esbuild-register tools/deployments/validate-pr-description.ts
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
env:
|
||||
TITLE: ${{ github.event.pull_request.title }}
|
||||
BODY: ${{ github.event.pull_request.body }}
|
||||
LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
|
||||
FILES: ${{ steps.files.outputs.all }}
|
||||
DRAFT: ${{ github.event.pull_request.draft }}
|
||||
@@ -0,0 +1,100 @@
|
||||
name: Vite plugin playgrounds
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
|
||||
|
||||
env:
|
||||
# We run `playwright install` manually instead
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 30
|
||||
name: ${{ format('Vite Plugin Playground ({0}, {1})', matrix.os, matrix.vite) }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
vite: ["vite-8"]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
vite: "vite-6"
|
||||
- os: ubuntu-latest
|
||||
vite: "vite-7"
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Filter changed paths
|
||||
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
everything_but_markdown:
|
||||
- '!**/*.md'
|
||||
- name: Install Dependencies
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
turbo-api: ${{ secrets.TURBO_API }}
|
||||
turbo-team: ${{ secrets.TURBO_TEAM }}
|
||||
turbo-token: ${{ secrets.TURBO_TOKEN }}
|
||||
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
|
||||
- name: Install playwright
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
run: |
|
||||
pnpm --filter @vite-plugin-cloudflare/playground playwright:install
|
||||
- name: Build plugin with initial Vite version
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
run: |
|
||||
pnpm dotenv -- pnpm turbo build --filter @cloudflare/vite-plugin
|
||||
- name: Downgrade to Vite 6
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.vite == 'vite-6'
|
||||
run: |
|
||||
pnpm update -r --no-save vite@^6.1.0
|
||||
- name: Downgrade to Vite 7
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true' && matrix.vite == 'vite-7'
|
||||
run: |
|
||||
pnpm update -r --no-save vite@^7.0.0
|
||||
- name: Run dev playground tests
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
# We use `--only` to prevent TurboRepo from rebuilding dependencies
|
||||
# This ensures the Vite plugin is not rebuilt using a different Vite version
|
||||
run: |
|
||||
pnpm dotenv -- pnpm turbo test:ci:serve --filter @vite-plugin-cloudflare/playground --only
|
||||
env:
|
||||
VITE_VERSION: ${{ matrix.vite }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/index.html
|
||||
NODE_DEBUG: "@cloudflare:vite-plugin"
|
||||
CI_OS: ${{ matrix.os }}
|
||||
- name: Run build/preview playground tests
|
||||
if: steps.changes.outputs.everything_but_markdown == 'true'
|
||||
# We use `--only` to prevent TurboRepo from rebuilding dependencies
|
||||
# This ensures the Vite plugin is not rebuilt using a different Vite version
|
||||
run: |
|
||||
pnpm dotenv -- pnpm turbo test:ci:build --filter @vite-plugin-cloudflare/playground --only
|
||||
env:
|
||||
VITE_VERSION: ${{ matrix.vite }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/
|
||||
TEST_REPORT_PATH: ${{ runner.temp }}/test-report/index.html
|
||||
NODE_DEBUG: "@cloudflare:vite-plugin"
|
||||
CI_OS: ${{ matrix.os }}
|
||||
- name: Upload turbo logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: turbo-runs-${{ matrix.os }}-${{ matrix.vite }}
|
||||
path: .turbo/runs
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Deploy (to testing) and Test Playground Preview Worker
|
||||
|
||||
# This workflow is designed to deploy a "testing" version of the Playground Preview Worker
|
||||
# and test it via integration tests.
|
||||
|
||||
# Triggers:
|
||||
# - push to `main`, on Cloudflare, where there are changes to the files in this worker's package
|
||||
# - update to a PR, on Cloudflare, labelled as `playground-worker`
|
||||
#
|
||||
# Actions:
|
||||
# - deploy to testing environment
|
||||
# - run the end-to-end tests against testing deployment
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "packages/playground-preview-worker/**"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
e2e-test:
|
||||
if: github.repository_owner == 'cloudflare' && (github.event_name != 'pull_request' || contains(github.event.*.labels.*.name, 'feature:playground-worker'))
|
||||
name: "Deploy Playground Preview Worker (testing)"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Build tools and libraries
|
||||
run: pnpm run build
|
||||
env:
|
||||
NODE_ENV: "production"
|
||||
CI_OS: ${{ runner.os }}
|
||||
|
||||
- name: Build & deploy Worker
|
||||
run: pnpm run deploy:testing
|
||||
env:
|
||||
NODE_ENV: "production"
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
working-directory: packages/playground-preview-worker
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm run test:e2e
|
||||
env:
|
||||
TMP_CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
TMP_CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
working-directory: packages/playground-preview-worker
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Deploy Workers Shared Production
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy-workers:
|
||||
name: Deploy Workers Shared Production
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Deploy
|
||||
run: pnpm run deploy
|
||||
working-directory: packages/workers-shared
|
||||
env:
|
||||
WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN: ${{ secrets.WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN }}
|
||||
WORKERS_SHARED_SENTRY_ACCESS_ID: ${{ secrets.WORKERS_SHARED_SENTRY_ACCESS_ID }}
|
||||
WORKERS_SHARED_SENTRY_ACCESS_SECRET: ${{ secrets.WORKERS_SHARED_SENTRY_ACCESS_SECRET }}
|
||||
WORKERS_SHARED_SENTRY_AUTH_TOKEN: ${{ secrets.WORKERS_SHARED_SENTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: Publish deployment summary
|
||||
run: echo -e "# Deployment summary\n\n| Service | Version | Release link |\n| --- | --- | --- |\n| Asset Worker | \`aw-$(node -r esbuild-register ./scripts/get-version-tag.ts)\` | https://cflare.co/release-asset-worker |\n| Router Worker | \`rw-$(node -r esbuild-register ./scripts/get-version-tag.ts)\` | https://cflare.co/release-router-worker |\n" >> $GITHUB_STEP_SUMMARY
|
||||
working-directory: packages/workers-shared
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Deploy Workers Shared Staging
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "packages/workers-shared/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy-workers:
|
||||
name: "Deploy Workers Shared Staging"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
|
||||
- name: Deploy
|
||||
run: pnpm deploy:staging
|
||||
working-directory: packages/workers-shared
|
||||
env:
|
||||
WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN: ${{ secrets.WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN }}
|
||||
Reference in New Issue
Block a user