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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:11 +08:00
commit 70bf21e064
5213 changed files with 731895 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
name: "\U0001F41B Bug Report"
description: Report an issue or possible bug
type: Bug
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to file a bug report! Please fill out this form as completely as possible.
- type: textarea
attributes:
label: What versions & operating system are you using?
description: "Make sure you've checked that you meet our system requirements as listed here: https://developers.cloudflare.com/workers/wrangler/install-and-update/. Please provide the output of running `npx envinfo --system --npmPackages '{wrangler,create-cloudflare,miniflare,@cloudflare/*}' --binaries`"
placeholder: e.g. Wrangler v4.6, Node v20, Windows 11 etc...
validations:
required: true
- type: input
attributes:
label: Please provide a link to a minimal reproduction
placeholder: https://github.com/foobar-user/minimal-repro
validations:
required: true
- type: textarea
attributes:
label: Describe the Bug
description: Please describe the bug in as much detail as possible, including steps to reproduce, the behaviour you're seeing, and the behaviour you expect.
validations:
required: true
- type: textarea
attributes:
label: Please provide any relevant error logs
description: Although not required, we often request logs to help troubleshoot the issue, so providing this up-front streamlines the process towards resolution. Please be careful to hide any sensitive information.
validations:
required: false
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Feature Request
url: https://github.com/cloudflare/workers-sdk/discussions/new?category=feature-requests
about: "Have a suggestion? Open a discussion to share your idea!"
- name: Support
url: https://discord.cloudflare.com
about: "Join us on Discord!"
@@ -0,0 +1,33 @@
name: "Check Remote Tests"
description: >
Determines whether E2E tests should be given Cloudflare API credentials.
Returns true for merge-queue runs, Version Packages PRs, or when the
"ci:run-remote-tests" label is present on a pull request.
outputs:
run-remote:
description: "'true' when remote tests should run, 'false' otherwise"
value: ${{ steps.decide.outputs.run_remote }}
runs:
using: "composite"
steps:
- name: Decide whether to run remote tests
id: decide
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 }}
run: |
if [ "$EVENT_NAME" = "merge_group" ] || \
[ "$HEAD_REF" = "changeset-release/main" ]; then
echo "run_remote=true" >> "$GITHUB_OUTPUT"
elif [ "$EVENT_NAME" = "pull_request" ]; then
HAS_LABEL=$(gh pr view "$PR_NUMBER" \
--repo "$REPO" --json labels \
--jq '[.labels[].name] | any(. == "ci:run-remote-tests")')
echo "run_remote=${HAS_LABEL}" >> "$GITHUB_OUTPUT"
else
echo "run_remote=false" >> "$GITHUB_OUTPUT"
fi
@@ -0,0 +1,5 @@
name: "Expose Actions Variables"
description: "Expose ACTIONS_RUNTIME_TOKEN and ACTIONS_RESULTS_URL on GITHUB_ENV"
runs:
using: "node20"
main: "index.mjs"
@@ -0,0 +1,7 @@
import fs from "node:fs";
fs.appendFileSync(
process.env.GITHUB_ENV,
`GITHUB_ACTIONS_RUNTIME_TOKEN=${process.env.ACTIONS_RUNTIME_TOKEN}\n` +
`GITHUB_ACTIONS_RESULTS_URL=${process.env.ACTIONS_RESULTS_URL}\n`
);
@@ -0,0 +1,62 @@
name: "Install Dependencies"
description: "Install dependencies, fetching from cache when possible"
inputs:
# We run all jobs on Node.js 22 by default, as this is the most stable and supported version right now.
#
# 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:
description: the version of Node.js to install
default: 22.23.1
turbo-api:
description: the api URL for connecting to the turbo remote cache
turbo-team:
description: the team identifier for connecting to the turbo remote cache
turbo-token:
description: the api token for connecting to the turbo remote cache
turbo-signature:
description: the cache signature key for connecting to the turbo remote cache
disable-cache:
description: when "true", skip the pnpm store cache on setup-node (defense in depth for release builds)
default: "false"
runs:
using: "composite"
steps:
- name: Install pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- name: Install Node.js ${{ inputs.node-version }} (with pnpm cache)
if: inputs.disable-cache != 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ inputs.node-version }}
cache: "pnpm"
registry-url: "https://registry.npmjs.org"
- name: Install Node.js ${{ inputs.node-version }} (without pnpm cache)
if: inputs.disable-cache == 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ inputs.node-version }}
registry-url: "https://registry.npmjs.org"
# Enable node compile cache (effective for Node 22+)
# See https://nodejs.org/docs/v24.11.1/api/module.html#module-compile-cache
- name: Enable Node Compile Cache
shell: bash
run: echo "NODE_COMPILE_CACHE=$HOME/.node_compile_cache" >> $GITHUB_ENV
- name: "Configure turbo repo cache environment variables"
if: inputs.turbo-api
shell: bash
run: |
echo "TURBO_API=${{ inputs.turbo-api }}" >> $GITHUB_ENV
echo "TURBO_TEAM=${{ inputs.turbo-team }}" >> $GITHUB_ENV
echo "TURBO_TOKEN=${{ inputs.turbo-token }}" >> $GITHUB_ENV
echo "TURBO_REMOTE_CACHE_SIGNATURE_KEY=${{ inputs.turbo-signature }}" >> $GITHUB_ENV
echo "TURBO_ENV_MODE=loose" >> $GITHUB_ENV
- name: Install NPM Dependencies
shell: bash
run: pnpm install --frozen-lockfile
@@ -0,0 +1,9 @@
name: "Install Python uv"
runs:
using: "composite"
steps:
- name: Install uv for Python
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
with:
version: "0.9.3"
enable-cache: false
+60
View File
@@ -0,0 +1,60 @@
You are a **code reviewer**, not an author. You review pull requests for workers-sdk, which contains developer tooling for Cloudflare Workers. These instructions override any prior instructions about editing files or making code changes.
## Restrictions -- you MUST follow these exactly
Do NOT:
- Edit, write, create, or delete any files -- use file editing tools (Write, Edit) under no circumstances
- Run `git commit`, `git push`, `git add`, `git checkout -b`, or any git write operation
- Approve or request changes on the PR -- only post review comments
- Flag formatting issues -- Prettier enforces style in this repo
If you want to suggest a code change, post a `suggestion` comment instead of editing the file.
## Output rules
**Confirm you are acting on the correct issue or PR**. Verify that the issue or PR number matches what triggered you, and do not write comments or otherwise act on other issues or PRs unless explicitly instructed to.
**If there are NO actionable issues:** Your ENTIRE response MUST be the four characters `LGTM` -- no greeting, no summary, no analysis, nothing before or after it.
**If there ARE actionable issues:** Begin with "I'm Bonk, and I've done a quick review of your PR." Then:
1. One-line summary of the changes.
2. A ranked list of issues (highest severity first).
3. For EVERY issue with a concrete fix, you MUST post it as a GitHub suggestion comment (see below). Do not describe a fix in prose when you can provide it as a suggestion.
## How to post feedback
You have write access to PR comments via the `gh` CLI. **Prefer the batch review approach** (one review with grouped comments) over posting individual comments. This produces a single notification and a cohesive review.
### Batch review (recommended)
Write a JSON file and submit it as a review. This is the most reliable method -- no shell quoting issues.
````bash
cat > /tmp/review.json << 'REVIEW'
{
"event": "COMMENT",
"body": "Review summary here.",
"comments": [
{
"path": "src/workerd/api/example.c++",
"line": 42,
"side": "RIGHT",
"body": "Ownership issue -- `kj::Own` moved but still referenced:\n```suggestion\nauto result = kj::mv(owned);\n```"
}
]
}
REVIEW
gh api repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews --input /tmp/review.json
````
Each comment needs `path`, `line`, `side`, and `body`. Use `suggestion` fences in `body` for applicable changes.
- `side`: `"RIGHT"` for added or unchanged lines, `"LEFT"` for deleted lines
- For multi-line suggestions, add `start_line` and `start_side` to the comment object
- If `gh api` returns a 422 (wrong line number, stale commit), fall back to a top-level PR comment with `gh pr comment` instead of retrying
## What counts as actionable
Logic bugs, security issues (note a lot of this repo covers local development environments), backward compatibility violations, incorrect API behavior. Be pragmatic -- do not nitpick, do not flag subjective preferences.
+147
View File
@@ -0,0 +1,147 @@
const assert = require("node:assert");
const fs = require("node:fs");
const path = require("node:path");
const { execSync } = require("node:child_process");
// This script is used by the `release.yml` workflow to update the version of the packages being released.
// The standard step is only to run `changeset version` but this does not update the lockfile.
// So we also run `pnpm install`, which does this update.
// This is a workaround until this is handled automatically by `changeset version`.
// See https://github.com/changesets/changesets/issues/421.
function getPkg(filePath) {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
}
function setPkg(filePath, newPkg) {
fs.writeFileSync(filePath, `${JSON.stringify(newPkg, null, "\t")}\n`);
}
function parseVersion(version) {
// Extract `<major>.<minor>.<patch>` from version (could be a constraint)
const match = /(\d+)\.(\d+)\.(\d+)/.exec(version);
assert(match !== null, `Expected ${version} to be <major>.<minor>.<patch>`);
return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
}
const rootPath = path.resolve(__dirname, "..");
const miniflarePath = path.join(rootPath, "packages/miniflare");
const miniflarePkgPath = path.join(miniflarePath, "package.json");
function getWorkerdVersion() {
const pnpmWorkspacePath = path.join(rootPath, "pnpm-workspace.yaml");
const match = /workerd: "(\d+\.\d+\.\d+)"/.exec(
fs.readFileSync(pnpmWorkspacePath, "utf8")
);
assert(match !== null, `Expected ${match[1]} to be <major>.<minor>.<patch>`);
return match[1];
}
/**
* Gets the correct version to bump `miniflare` to, ensuring the minor versions
* of `workerd` and `miniflare` match. Minor bumps in changesets will become
* patch bumps if the `workerd` version hasn't changed.
* See `changeset-version.test.js` for examples.
*
* @param workerdVersion `workerd` version constraint in `miniflare` package
* @param previousVersion `miniflare` version before running `changeset version`
* @param version `miniflare` version after running `changeset version`
*/
function getNextMiniflareVersion(workerdVersion, previousVersion, version) {
const [, workerdMinor] = parseVersion(workerdVersion);
const [, , previousPatch] = parseVersion(previousVersion);
const [major, minor] = parseVersion(version);
if (workerdMinor === minor) {
// If the minor versions match already, there's nothing we need to do
return version;
} else if (workerdMinor > minor) {
// If the workerd minor is greater than the miniflare minor,
// use the workerd minor and reset patch to 0
return `${major}.${workerdMinor}.0`;
} else {
// Otherwise, if the workerd minor is less than the miniflare minor,
// use the workerd minor and bump the patch instead
return `${major}.${workerdMinor}.${previousPatch + 1}`;
}
}
exports.getNextMiniflareVersion = getNextMiniflareVersion;
function main() {
// 1. Get `miniflare` version before applying changesets, so we know if the
// minor version was bumped
const previousMiniflarePkg = getPkg(miniflarePkgPath);
const previousMiniflareVersion = previousMiniflarePkg.version;
// 2. Run standard `changeset version` command to apply changesets, bump
// versions, and update changelogs
console.log("Applying changesets and updating versions...");
execSync("pnpm exec changeset version", { stdio: "inherit" });
// 3. Force `miniflare`'s minor version to be the same as `workerd`
console.log("Getting miniflare and workerd versions...");
const miniflarePkg = getPkg(miniflarePkgPath);
const miniflareVersion = miniflarePkg.version;
const workerdVersion = getWorkerdVersion();
const nextMiniflareVersion = getNextMiniflareVersion(
workerdVersion,
previousMiniflareVersion,
miniflareVersion
);
if (nextMiniflareVersion !== miniflareVersion) {
// If `changeset version` didn't produce the correct version on its own...
// ...update `miniflare`'s `package.json` version
console.log(`Updating miniflare version to ${nextMiniflareVersion}...`);
miniflarePkg.version = nextMiniflareVersion;
setPkg(miniflarePkgPath, miniflarePkg);
const changedPathsBuffer = execSync("git ls-files --modified", {
cwd: rootPath,
});
console.log("Checking modified files...");
const changedPaths = changedPathsBuffer.toString().trim().split("\n");
for (const relativeChangedPath of changedPaths) {
const changedPath = path.resolve(rootPath, relativeChangedPath);
const name = path.basename(changedPath);
if (name === "package.json") {
console.log("Updating dependencies in", changedPath);
// ...update `miniflare` version in dependencies of other packages
const pkg = getPkg(changedPath);
let changed = false;
for (const key of [
"dependencies",
"devDependencies",
"peerDependencies",
"optionalDependencies",
]) {
const constraint = pkg[key]?.["miniflare"];
if (constraint === undefined) continue;
// Don't update `workspace:`-style constraints
if (constraint.startsWith("workspace:")) continue;
pkg[key]["miniflare"] = nextMiniflareVersion;
changed = true;
}
if (changed) setPkg(changedPath, pkg);
} else if (name === "CHANGELOG.md") {
console.log("Updating changelog in", changedPath);
// ...update `CHANGELOG.md`s with correct version
let changelog = fs.readFileSync(changedPath, "utf8");
// Replace version header in `miniflare` `CHANGELOG.md`
changelog = changelog.replace(
`## ${miniflareVersion}`,
`## ${nextMiniflareVersion}`
);
// Replace `Updated dependencies` line in other `CHANGELOG.md`s
changelog = changelog.replace(
`- miniflare@${miniflareVersion}`,
`- miniflare@${nextMiniflareVersion}`
);
fs.writeFileSync(changedPath, changelog);
}
}
}
// 4. Update the lockfile
console.log("Updating lockfile...");
execSync("pnpm install --lockfile-only", { stdio: "inherit" });
console.log("Done.");
}
if (require.main === module) main();
+48
View File
@@ -0,0 +1,48 @@
version: 2
updates:
# Automatically check for updates in framework CLIs for C3
- package-ecosystem: "npm"
open-pull-requests-limit: 10
directory: "/packages/create-cloudflare/src/frameworks"
schedule:
interval: "weekly"
# Don't run these at midday on Mondays, when we are busy trying to land PRs
day: "sunday"
time: "06:00"
versioning-strategy: increase
# Match the 24h minimumReleaseAge enforced by pnpm in pnpm-workspace.yaml
# so Dependabot doesn't open PRs that CI will then reject.
cooldown:
default-days: 1
# the following is used to add the [C3] prefix to the PR title,
# we override the commit message but setting a prefix like this
# makes it so that also the PR title gets such prefix
commit-message:
prefix: "[C3] "
labels:
- "package:c3"
- "dependencies"
- "ci:skip-pr-description-validation"
# Check for workerd & workers-types updates for Miniflare
- package-ecosystem: "npm"
# If you restrict the update to a directory that is not the root
# then it will not update the pnpm-lock.yaml.
directory: "/"
groups:
# We want to keep workerd and workers-types updates in lock-step
workerd-and-workers-types:
patterns:
- "workerd"
- "@cloudflare/workers-types"
schedule:
interval: "daily"
time: "06:00"
versioning-strategy: increase
labels:
- "miniflare"
- "dependencies"
- "ci:skip-pr-description-validation"
allow:
- dependency-name: "workerd"
- dependency-name: "@cloudflare/workers-types"
+21
View File
@@ -0,0 +1,21 @@
// This file is not used directly.
// Instead its contents are used in `.github/workflows/write-prerelease-comment.yml`
// Any changes here should be copied into the CI step there.
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of allArtifacts.data.artifacts) {
// Extract the PR number from the artifact name
const match = /^npm-package-(.+)-(\d+)$/.exec(artifact.name);
if (match) {
const packageName = match[1].toUpperCase();
require("fs").appendFileSync(
process.env.GITHUB_ENV,
`\nWORKFLOW_RUN_PR_FOR_${packageName}=${match[2]}` +
`\nWORKFLOW_RUN_ID_FOR_${packageName}=${context.payload.workflow_run.id}`
);
}
}
@@ -0,0 +1,26 @@
const { execSync } = require("child_process");
module.exports = function () {
const diff = execSync(
`git diff origin/${process.env.GITHUB_BASE_REF} -- packages/create-cloudflare/src/frameworks/package.json`
).toString();
const changedPackages = diff
.match(/-\s*".*?":\s".*?",?/g)
.map((match) => match.match(/-\s*"(.*)":/)?.[1])
.filter(Boolean);
if (changedPackages.length === 0) {
console.warn("No changes detected!");
return null;
} else if (changedPackages.length > 1) {
console.warn(
`More then one package has changed (${changedPackages.join(
", "
)}), that's not currently supported`
);
throw new Error("More than one package bump detected");
} else {
return changedPackages[0];
}
};
+9
View File
@@ -0,0 +1,9 @@
organization: cloudflare
stickers:
- id: cltg4w6r612040fl2r7vweuvv
alias: "ci:outstanding-contribution"
holobytes:
- evolvingStickerId: cltg4rlqc39020fl51scnguhb
alias: contribution
in: true
+26
View File
@@ -0,0 +1,26 @@
{
"$schema": "https://opencode.ai/config.json",
"disabled_providers": ["opencode"],
"enabled_providers": ["cloudflare-ai-gateway"],
"provider": {
"cloudflare-ai-gateway": {
"models": {
"anthropic/claude-opus-4-8": {},
"anthropic/claude-sonnet-4-5": {},
"workers-ai/@cf/moonshotai/kimi-k2.6": {}
}
}
},
"permission": {
"read": "allow",
"edit": "allow",
"glob": "allow",
"grep": "allow",
"bash": "deny",
"task": "allow",
"skill": "allow",
"todoread": "allow",
"todowrite": "allow",
"webfetch": "deny"
}
}
+50
View File
@@ -0,0 +1,50 @@
import { execSync, spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, "../..");
function getPackagePaths() {
const stdout = execSync(
'pnpm list --filter="./packages/*" --recursive --depth=-1 --parseable',
{ cwd: projectRoot, encoding: "utf8" }
);
return stdout.split("\n").filter((pkgPath) => path.isAbsolute(pkgPath));
}
function getPackage(pkgPath) {
const json = fs.readFileSync(path.join(pkgPath, "package.json"), "utf8");
return {
path: pkgPath,
json: JSON.parse(json),
};
}
function getPackages() {
return getPackagePaths().map(getPackage);
}
export function getPackagesForPrerelease() {
return getPackages().filter((pkg) => pkg.json["workers-sdk"]?.prerelease);
}
const pkgs = getPackagesForPrerelease();
spawnSync(
"pnpm",
[
"dlx",
"pkg-pr-new",
"publish",
"--pnpm",
"--compact",
"--no-template",
...pkgs.map((pkg) => pkg.path),
],
{
stdio: "inherit",
}
);
+25
View File
@@ -0,0 +1,25 @@
Fixes #[insert GH or internal issue link(s)].
_Describe your change..._
---
<!--
Please don't delete the checkboxes <3
The following selections do not need to be completed if this PR only contains changes to .md files
-->
- Tests
- [ ] Tests included/updated
- [ ] Automated tests not possible - manual testing has been completed as follows:
- [ ] Additional testing not necessary because:
- Public documentation
- [ ] Cloudflare docs PR(s): <!--e.g. <https://github.com/cloudflare/cloudflare-docs/pull/>...-->
- [ ] Documentation not necessary because:
*A picture of a cute animal (not mandatory, but encouraged)*
<!--
Have you read our [Contributing guide](https://github.com/cloudflare/workers-sdk/blob/main/CONTRIBUTING.md)?
In particular, for non-trivial changes, please always engage on the issue or create a discussion or feature request issue first before writing your code.
-->
+376
View File
@@ -0,0 +1,376 @@
---
name: github-issue-review
description: Triage a GitHub issue on cloudflare/workers-sdk. Assesses quality, identifies the component, checks for duplicates, and recommends next steps.
---
# GitHub Issue Triage Skill
This skill triages a GitHub issue to assess its quality, identify the affected component, and recommend next steps for the maintainers.
**Important:** This skill runs without bash or network access. All analysis is based on the pre-fetched issue data in `context.json`. Use only `read`, `glob`, `grep`, `edit`, and `write` tools.
## Input
Pre-fetched issue data at `data/<issue_number>/context.json` containing the full issue details from the GitHub API (title, body, comments, labels, author, dates).
## Triage Process
Perform the following steps in order. **Stop and skip to Output as soon as you have sufficient evidence for a recommendation.**
### Step 1: Load Issue Details
Read the pre-fetched `context.json` file using the `read` tool.
Extract and note:
- Title and description
- Issue type (bug report vs feature request vs question)
- Product/component affected
- Version reported against (if any)
- Operating system (if any)
- Reproduction steps or reproduction link (if any)
- Error messages (if any)
- Comment count and any relevant comment content
- Labels currently applied
- Issue age (created date) and last activity date
- `state_reason` if the issue is already closed
### Step 2: Check for Closeable Issues
Check each of the following categories in order. **STOP at the first match** and skip to Output.
> **Note:** The `state_reason` values in this section (`completed`, `not_planned`) are informational — they indicate the appropriate GitHub close reason for maintainer reference. They are not captured as a field in the output report.
#### 2a: Spam or Junk
Recommend **CLOSE** (state_reason: `not_planned`, no comment needed) if:
- The body contains random characters, test text, or nonsensical content (e.g. "bhhg", "ssssssssss", "aloll")
- The issue is clearly spam (e.g. loan advertisements, SEO spam, unrelated product promotions)
- The issue is a blank/empty test issue (e.g. title is "test" with no meaningful body)
- The body is entirely empty or contains only template headers with no content filled in
#### 2b: Reporter Confirmed Resolved
Recommend **CLOSE** (state_reason: `completed`) if:
- The reporter explicitly confirmed the issue is resolved in comments
- The reporter said they found a workaround and no longer need a fix
- A maintainer indicated it should be closed in comments
#### 2c: Already Fixed in a Prior Release
Recommend **CLOSE** (state_reason: `completed`) if, based on references within the issue comments or linked PRs:
- A comment references a PR or release that addresses this issue
- The issue describes a bug that was fixed in a version newer than the reporter's version
- The issue's symptoms match a fix described in a linked PR or comment
When closing, cite the specific PR number and release version if known.
**Template:**
> This issue has been fixed in PR #XXXX, which was released in **wrangler X.Y.Z** (or the relevant package version). Please update and let us know if you're still seeing the issue.
Or for older issues where the fix can't be pinpointed:
> This is a fairly old issue, and from testing with the latest version, it appears to have been resolved. I'm going to close it for now — if you're still running into problems on the latest version, feel free to open a new issue with more details and we can investigate further.
#### 2d: Duplicate
Recommend **CLOSE** (state_reason: `not_planned`) if a comment or linked reference in the issue identifies it as a duplicate of another issue — for example, a maintainer has already commented pointing to a canonical issue, or the reporter themselves links to an existing report.
When closing, link to the canonical issue.
**Template:**
> Closing as a duplicate of #XXXX. Please follow that issue for updates.
If the duplicate is in another repo:
> I'm closing this as a duplicate of <owner/repo>#XXXX, which is where this is being tracked.
#### 2e: Not workers-sdk / Wrong Repo
Recommend **CLOSE** (state_reason: `not_planned`) if:
- The issue describes Workers **runtime** behavior (fetch API quirks, V8 issues, compatibility flags, crypto APIs) — belongs in [cloudflare/workerd](https://github.com/cloudflare/workerd)
- The issue is about a third-party framework (Nuxt, SvelteKit, Remix, Hono, React Router) and the bug is in that framework's code, not in Wrangler or the Vite plugin
- The issue is about an upstream tool (esbuild, Bun, Vite core) rather than Cloudflare's integration
- The issue is an account/billing/abuse problem — belongs in Cloudflare Support
**Templates:**
For framework issues:
> It looks like this issue is coming from <framework>, rather than from workers-sdk. I'd recommend opening an issue on that project's repo: <link>. If it turns out to be a workers-sdk issue after all, feel free to open a new issue here with more details.
For runtime issues:
> This looks like a Workers runtime issue rather than a tooling issue. The right place to track this is [cloudflare/workerd](https://github.com/cloudflare/workerd) — could a maintainer transfer this issue there?
(Set Action field to: "Transfer to cloudflare/workerd, then post this comment.")
For account/support issues:
> Unfortunately, we're unable to provide support for account-level issues via GitHub. Please contact Cloudflare Support at https://dash.cloudflare.com/?to=/:account/support or the email address mentioned in the error message.
#### 2f: Stale / No Response
Recommend **CLOSE** (state_reason: `not_planned`) if:
- The issue has the `awaiting reporter response` or `needs reproduction` label AND the last activity was >30 days ago
- The issue is >12 months old with no activity in the last 6 months
- A maintainer asked for a reproduction or clarification and the reporter never responded
**Template:**
> We haven't heard from you in a while so I'm going to close this issue for now. If you're still running into problems, feel free to open a new issue with more details and we can investigate further.
For very old issues:
> This is a very old issue so I'm going to close it for now. If you're still running into problems on the latest version, feel free to comment with more details and we can investigate further.
#### 2g: Transient Platform Issue
Recommend **CLOSE** (state_reason: `completed`) if:
- The issue describes a one-time API error (500, 503, auth failures) that appears to have been a service incident
- Multiple users reported the same error around the same time, and it has since stopped
- The error is from Cloudflare's API (not from Wrangler itself) and there's no way to fix it in workers-sdk
**Template:**
> This was a transient API issue, and should be resolved now. If you're still seeing this error, please open a new issue with the latest details and we can investigate further.
Or for old transient issues:
> This appears to have been a transient server-side API issue. Similar reports were caused by Cloudflare API incidents that have since been resolved. I'm going to close this for now.
#### 2h: User Error / Misunderstanding
Recommend **CLOSE** (state_reason: `not_planned`) if:
- The issue describes expected behavior that the reporter misunderstands
- The issue is caused by incorrect configuration, wrong SQL syntax, or misuse of an API
- The fix is a documentation pointer rather than a code change
When closing, explain the correct approach and link to relevant documentation. Be helpful, not dismissive.
**Template:**
> This isn't a bug — <brief explanation of the correct behavior>. You can find more details in the docs: <link>. I'm going to close this for now, but feel free to ask on our [Discord](https://discord.cloudflare.com) if you have more questions.
#### 2i: Breaking Change
Recommend **KEEP OPEN** if:
- The requested change would be a breaking change in the current major version
The issue should remain open as a tracking item. Do not close it — the team hasn't decided against the change, it's deferred to a future major version.
**Suggested labels:** `breaking change`
**Template:**
> Changing this behavior at this stage would be a breaking change, so it will need to wait for the next major version. I've added the `breaking change` label to track this.
(Set Action field to: "Apply `breaking change` label, then post this comment.")
#### 2j: Won't Fix / By Design
Recommend **CLOSE** (state_reason: `not_planned`) if:
- The behavior is intentional and documented
- The team has explicitly decided not to implement this feature
- The cost/complexity of the change outweighs the benefit
**Templates:**
For design decisions:
> This is intentional behavior — <brief explanation>. I don't think we're likely to change this in the near future, but we appreciate the feedback.
For feature requests that won't happen:
> Thanks for the suggestion. We don't intend to implement this right now, but it may be revisited in future. <Optional: brief explanation of why, or pointer to an alternative approach.>
#### 2k: Feature Superseded / Deprecated
Recommend **CLOSE** (state_reason: `completed`) if:
- The requested feature has been implemented via a different mechanism than proposed
- The issue relates to a deprecated feature that has a replacement
- A newer feature or package addresses the underlying need
**Template:**
> This has been addressed by <feature/package>. <Brief explanation of how it solves the original request.> I'm going to close this for now.
### Step 3: Check for Insufficient Information
If the issue wasn't caught by Step 2, recommend **NEEDS MORE INFO** if:
- Bug report has no reproduction steps or link (the bug template requires one)
- Bug report is missing version information
- The description is too vague to act on (e.g. "it doesn't work" with no details)
- The error message is missing or truncated
**Template:**
> Thanks for reporting this. Could you provide <specific missing information>? In particular:
>
> - <specific question 1>
> - <specific question 2>
>
> A minimal reproduction (a GitHub repo or link we can clone and run) would also help us investigate. Without more details, we won't be able to look into this.
**Suggested label:** `awaiting reporter response` (and optionally `needs reproduction`)
**STOP HERE if** the issue clearly needs more info. Skip to Output.
### Step 4: Identify Component
Map the issue to a package based on labels, title, and body content:
| Signal | Package |
| ------------------------------------------------------------------------ | ----------------------------------------------- |
| `wrangler` label, wrangler CLI commands, `wrangler.toml`/`wrangler.json` | `packages/wrangler` |
| `miniflare` label, local dev simulation | `packages/miniflare` |
| `d1` label, D1 database, `d1 execute`, migrations | `packages/wrangler` (D1 code is in wrangler) |
| `vitest` label, worker tests, `vitest-pool-workers` | `packages/vitest-pool-workers` |
| `vite-plugin` label, vite dev, `@cloudflare/vite-plugin` | `packages/vite-plugin-cloudflare` |
| `c3` label, `create-cloudflare`, project scaffolding | `packages/create-cloudflare` |
| `pages` label, Pages deployment, `_routes.json`, `_headers` | `packages/wrangler` (Pages code is in wrangler) |
| `Workers + Assets` label, static asset serving | `packages/wrangler` |
| `containers` label, container registry | `packages/wrangler` |
| `workflows` label, Workflows API | `packages/wrangler` |
| `workers-builds` label | Workers Builds (may be internal) |
| `python` label, Python Workers | `packages/wrangler` |
| `workers for platforms` label, dispatch namespaces | `packages/wrangler` |
| `kv-asset-handler` label | `packages/kv-asset-handler` |
| `types` label, `wrangler types` command | `packages/wrangler` |
| R2, KV, Queues, Durable Objects, Vectorize bindings | `packages/wrangler` |
| `node compat`/`nodejs compat` label, Node.js APIs | May be workerd or wrangler depending on context |
| Workers runtime behavior (not tooling) | Likely belongs in cloudflare/workerd |
| Cloudflare dashboard, API behavior | Likely a platform issue, not workers-sdk |
### Step 5: Assess Reproducibility and Severity
For **bug reports**, evaluate:
- **Has reproduction?** Does the issue include a minimal repro link or clear steps?
- **Severity estimate:** Is this a crash, data loss, incorrect behavior, or cosmetic issue?
- **Scope:** Does it affect all users or a specific configuration?
- **Workaround available?** Did the reporter or comments mention one?
- **Version gap:** Is the reporter on an old version? Could updating fix this?
For **feature requests**, evaluate:
- **Clarity:** Is the proposed solution clearly described?
- **Use case:** Is the motivation explained?
- **Scope:** Small enhancement vs large new feature?
- **Existing alternatives:** Is there already a way to achieve this (even if less convenient)?
## Output Format
**How the output is used:** `report.md` is posted verbatim as a maintainer-facing triage comment on the issue (attributed to an automated bot), and the labels in `summary.json` are applied automatically. Because of this:
- Write `report.md` for maintainers, not the reporter. The **Suggested Comment** section is a _draft_ for a maintainer to send to the reporter — it is **not** posted automatically, so do not phrase the surrounding report as though a reply has already been made.
- Only put labels in the **Suggested Labels** fields that already exist in the repository. If unsure whether a label exists, omit it rather than guess — non-existent labels are dropped before applying, so inventing labels only weakens the report's accuracy.
### Report Directory Structure
```
./data/<issue_number>/
├── report.md # Full detailed report
└── summary.json # Structured JSON summary
```
### Output Step 1: Write Full Report
Write the full report to `./data/<issue_number>/report.md`:
```markdown
# Issue Triage: <owner/repo>#<number>
## Summary
<One-line summary of the issue>
## Classification
- **Type:** <Bug | Feature Request | Question | Discussion>
- **Component:** <package name or "unknown">
- **Severity:** <Critical | High | Medium | Low | N/A>
- **Has Reproduction:** <Yes (with link) | No | N/A>
- **Quality:** <Complete | Partial | Incomplete>
## Findings
- **Created:** <date>
- **Author:** <username>
- **Version:** <reported version, or "not specified">
- **Labels:** <labels, or "none">
- **Comments:** <count>
### Analysis
<2-5 bullet points covering what you found — component identification,
reproducibility assessment, severity reasoning, staleness indicators,
duplicate candidates. Only include what's relevant.>
## Recommendation
**Status:** <CLOSE | KEEP OPEN | NEEDS MORE INFO | NEEDS VERIFICATION>
**Reasoning:** <2-3 sentences explaining why>
**Action:** <What a maintainer should do next>
**Suggested Labels:** <labels to add, if any. Use existing repo labels only.>
### Suggested Comment
> <The exact comment to post on the issue. Follow the templates above for the
> matching closure category. Key principles:
>
> - Always offer an escape hatch ("feel free to open a new issue")
> - Link to specific PRs, releases, or docs when available
> - Be concise for straightforward closures, detailed for design decisions
> - Never be dismissive or snarky, even for spam (just close silently) or user error
> - For NEEDS MORE INFO, ask specific questions (not generic "please provide more details")
> Omit this section entirely for spam (close without comment) or if no comment is needed.>
```
### Output Step 2: Write Summary File
Write a machine-readable summary as **JSON** to `./data/<issue_number>/summary.json`. This file is parsed by the triage workflow (to build the dashboard payload and apply labels), so it must be valid JSON with exactly these keys:
```json
{
"issueNumber": <issue_number as a number>,
"title": "<issue title, with emoji/template prefixes like 'Bug:' removed>",
"githubUrl": "https://github.com/<owner>/<repo>/issues/<issue_number>",
"recommendation": "<CLOSE | KEEP OPEN | NEEDS MORE INFO | NEEDS VERIFICATION>",
"difficulty": "<easy | medium | hard | n/a>",
"reasoning": "<brief reasoning, 1-2 sentences>",
"suggestedAction": "<brief description of next steps>",
"hasSuggestedComment": <true if a Suggested Comment section is present in the report, false otherwise>,
"suggestedLabels": ["<label>", "..."]
}
```
**Key definitions:**
- **issueNumber**: The issue number as a JSON number (not a string).
- **title**: Issue title with any emoji prefixes (e.g. "🐛 Bug:") or template prefixes removed.
- **githubUrl**: Full URL to the issue.
- **recommendation**: One of `CLOSE`, `KEEP OPEN`, `NEEDS MORE INFO`, `NEEDS VERIFICATION`.
- **difficulty**: Estimated fix difficulty — `easy`, `medium`, `hard`, or `n/a` (for feature requests or closures).
- **reasoning**: Brief summary of why (1-2 sentences).
- **suggestedAction**: Brief description of next steps.
- **hasSuggestedComment**: Boolean — `true` if the report includes a Suggested Comment, `false` otherwise.
- **suggestedLabels**: JSON array of labels to apply, matching the **Suggested Labels** field in the report. Use existing repo labels only (see above). Use an empty array `[]` if there are no labels to apply.
**CRITICAL:** Write valid, parseable JSON only (no trailing commas, no comments, no surrounding markdown fences). Because JSON strings are escaped, `reasoning`/`suggestedAction` may safely contain any punctuation.
+35
View File
@@ -0,0 +1,35 @@
/**
* Update the package.json version property for the given package
*
* Usage:
*
* ```
* node ./.github/version-script.js <package-name>
* ```
*
* `<package-name>` defaults to `wrangler` if not provided.
*/
const { readFileSync, writeFileSync } = require("fs");
const { execSync } = require("child_process");
try {
const packageName = getArgs()[0] ?? "wrangler";
const packageJsonPath = `./packages/${packageName}/package.json`;
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
const stdout = execSync("git rev-parse --short HEAD", { encoding: "utf8" });
pkg.version = "0.0.0-" + stdout.trim();
writeFileSync(packageJsonPath, JSON.stringify(pkg, null, "\t") + "\n");
} catch (error) {
console.error(error);
process.exit(1);
}
/**
* Get the command line args, stripping `node` and script filename, etc.
*/
function getArgs() {
const args = Array.from(process.argv);
while (args.shift() !== module.filename) {}
return args;
}
+151
View File
@@ -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).
+69
View File
@@ -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 }}
+80
View File
@@ -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 }}
+311
View File
@@ -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
+92
View File
@@ -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)"
+108
View File
@@ -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 }}
+54
View File
@@ -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 }}
+141
View File
@@ -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 }}
+90
View File
@@ -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
+33
View File
@@ -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 }}
+73
View File
@@ -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
+88
View File
@@ -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
+82
View File
@@ -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 }}
+41
View File
@@ -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
+53
View File
@@ -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
+35
View File
@@ -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 }}
+86
View File
@@ -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 }}
+31
View File
@@ -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 }}
+202
View File
@@ -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
+235
View File
@@ -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 }}