From 7e8a4815fff7061343935145341881bbb3fe430c Mon Sep 17 00:00:00 2001 From: Dina Kozlov Date: Mon, 20 Jul 2026 18:49:40 -0400 Subject: [PATCH 1/8] [Artifacts] Fix example formatting and copy --- src/components.ts | 2 + .../ArtifactsCIPipelineDiagram.astro | 790 ++++++++++++++++++ .../ArtifactsCIWorkflowDiagram.astro | 597 +++++++++++++ .../guides/build-and-deploy-on-push.mdx | 306 +++++++ 4 files changed, 1695 insertions(+) create mode 100644 src/components/ArtifactsCIPipelineDiagram.astro create mode 100644 src/components/ArtifactsCIWorkflowDiagram.astro create mode 100644 src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx diff --git a/src/components.ts b/src/components.ts index 593f5bea3f8..c0ff0008118 100644 --- a/src/components.ts +++ b/src/components.ts @@ -70,6 +70,8 @@ export { default as AiSearchNamespacesDiagram } from "./components/AiSearchNames export { default as AiSearchOverviewDiagram } from "./components/AiSearchOverviewDiagram.astro"; export { default as AiSearchQueryingDiagram } from "./components/AiSearchQueryingDiagram.astro"; export { default as AiSearchVoiceDiagram } from "./components/AiSearchVoiceDiagram.astro"; +export { default as ArtifactsCIPipelineDiagram } from "./components/ArtifactsCIPipelineDiagram.astro"; +export { default as ArtifactsCIWorkflowDiagram } from "./components/ArtifactsCIWorkflowDiagram.astro"; export { default as AutoconfigDiagram } from "./components/cf/AutoconfigDiagram.astro"; export { default as WorkersArchitectureDiagram } from "./components/cf/WorkersArchitectureDiagram.astro"; export { default as WorkersIsolateDiagram } from "./components/cf/WorkersIsolateDiagram.astro"; diff --git a/src/components/ArtifactsCIPipelineDiagram.astro b/src/components/ArtifactsCIPipelineDiagram.astro new file mode 100644 index 00000000000..91ee46bb623 --- /dev/null +++ b/src/components/ArtifactsCIPipelineDiagram.astro @@ -0,0 +1,790 @@ +--- +interface Props { + autoPlay?: boolean; + loop?: boolean; +} + +const { autoPlay = true, loop = false } = Astro.props; +--- + +
+ +
+ + + + diff --git a/src/components/ArtifactsCIWorkflowDiagram.astro b/src/components/ArtifactsCIWorkflowDiagram.astro new file mode 100644 index 00000000000..6400815fee1 --- /dev/null +++ b/src/components/ArtifactsCIWorkflowDiagram.astro @@ -0,0 +1,597 @@ +--- +import { Icon as AstroIcon } from "astro-icon/components"; + +interface Props { + autoPlay?: boolean; + loop?: boolean; +} + +const { autoPlay = true, loop = true } = Astro.props; +--- + +
+ +
+
+ Artifacts repo changes +
+ + Repository changes +
+
+ + + +
+ CI Workflow + +
+ 1 + + Install & cache dependencies +
+ + + +
+
+ 2 + Run CI steps +
+
+
+ + Build +
+
+ + Lint +
+
+ + Typecheck +
+
+ + Format +
+
+
+
+ + + +
+ Deploy Worker +
+
+ + Preview + Non-main branch +
+
+ + Production + Main branch +
+
+
+
+
+
+ + + + diff --git a/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx b/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx new file mode 100644 index 00000000000..811c6dd7a52 --- /dev/null +++ b/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx @@ -0,0 +1,306 @@ +--- +title: Build and deploy Artifacts repos +description: Build projects stored in Artifacts repos and deploy them as Workers or Workers for Platforms User Workers. +pcx_content_type: how-to +sidebar: + order: 5 +products: + - artifacts +--- + +import { + ArtifactsCIPipelineDiagram, + ArtifactsCIWorkflowDiagram, + DashButton, + PackageManagers, + Tabs, + TabItem, + TypeScriptExample, + WranglerConfig, +} from "~/components"; + +Artifacts events can build and deploy projects stored in Artifacts repos. When a user or agent pushes a commit, the event starts a Workflow. + +Within the Workflow, continuous integration (CI) tooling caches dependencies, runs checks, and builds the project. The pipeline can deploy output as a [Worker](/workers/) or a [Workers for Platforms](/cloudflare-for-platforms/workers-for-platforms/) User Worker. + +This is useful when you need to: + +- Automatically build and deploy application code stored in Artifacts. +- Run linting, type checking, tests, and other checks on every push. +- Reuse dependencies when `package-lock.json` has not changed. +- Stop deployment when a check or build fails. +- Restrict API token access to the deployment step. +- Deploy output as a Worker or User Worker. + +## How it works + + + +1. **Push repo changes** — A `git push` to the Artifacts repo emits an `artifacts.push` event that identifies the pushed repo, branch, and commit. +2. **Run the CI Workflow** — The event starts a Workflow that checks out the commit, installs and caches dependencies, and runs CI steps — build, lint, typecheck, and format — in parallel. A failed step stops the Workflow before deployment. +3. **Build the project** — Once all checks pass, the Workflow builds the project output for deployment. +4. **Deploy the Worker** — The Workflow deploys the built Worker as a preview for non-main branches or to production for the main branch. + +## Start a build when code changes + +When a user or agent pushes a commit to an Artifacts repo, Artifacts emits an event that identifies the repo, branch, and commit that changed. You will use this event to start a Workflow that runs a CI pipeline — checking out the commit, installing dependencies, running checks, building the project, and deploying the Worker. + +This guide defines those CI steps in a Workflow class named `BuildAndDeployWorkflow`. To start this Workflow automatically after each push, add an `artifacts.push` trigger to your Wrangler configuration: + + + +```toml +name = "artifact-ci" +main = "src/index.ts" +compatibility_date = "$today" + +[[workflows]] +name = "build-and-deploy" +binding = "BUILD_AND_DEPLOY" +class_name = "BuildAndDeployWorkflow" + +[[triggers]] +type = "artifacts.push" +class_name = "BuildAndDeployWorkflow" + +[observability] +enabled = true +``` + + + +## Run the build pipeline + +To run the build pipeline, the Workflow first needs the files from the pushed commit. It clones the repo, then uses runners to install dependencies, run checks, build the project, and deploy the Worker. + +### Check out the pushed commit + +Before the Workflow can run build commands, it needs a local copy of the pushed commit. To retrieve the repo's Git remote and create a short-lived read token, expose the repo namespace to the Workflow through an [Artifacts binding](/artifacts/api/workers-binding/). + +Add the binding to your Wrangler configuration. Set `namespace` to the same namespace that emits the push events handled by this Workflow: + + + +```toml +[[artifacts]] +binding = "ARTIFACTS" +namespace = "customer-projects" +``` + + + +The binding is available as `env.ARTIFACTS`. + +Use the repo name from the push event to get its handle, create a short-lived read token, and pass both to a runner that clones the repo and checks out the pushed commit: + + + +```ts +const repo = await this.env.ARTIFACTS.get(push.source.repoName); +const token = await repo.createToken("read", 900); + +const checkout = await step.runner("check out pushed commit", { + exec: + "rm -rf repo && " + + 'git -c "http.extraHeader=Authorization: Bearer $ARTIFACTS_TOKEN" ' + + 'clone "$ARTIFACTS_REMOTE" repo && ' + + 'git -C repo checkout --detach "$COMMIT_SHA"', + env: { + ARTIFACTS_REMOTE: repo.remote, + ARTIFACTS_TOKEN: token.plaintext, + COMMIT_SHA: push.payload.after, + }, +}); +``` + + + +- `env.ARTIFACTS.get()` returns the repo handle for the name in the push event. +- `createToken("read", 900)` creates a read-only token that expires after 15 minutes. The token is passed only to the checkout runner and is never stored in the repo. +- `push.payload.after` identifies the exact commit that triggered this Workflow. A branch can receive another commit before checkout begins, so using the SHA from the event ensures the Workflow builds the intended version. + +### Define the CI steps + +Once the repo is checked out, use the `@cloudflare/ci` SDK to define the CI steps. The SDK provides two tools to help you build the pipeline: + +- **Runners** — each `runner()` call spins up an isolated sandbox and executes a shell command. You use the same commands you already run locally or in another CI system. Each runner captures its own logs, status, and output files. +- **Cache** — `step.cache()` allows you to cache installed dependencies so that later Workflow runs do not reinstall them. Pass the files that determine the dependencies, such as `package-lock.json`, to `step.cache()`. When those files have not changed, the SDK restores the cached result instead of running the command again. + +Each runner passes its output files to the next, so your install step feeds your checks, your checks gate your build, and your build feeds your deployment. Multiple runners can branch from the same cached result — for example, lint, type-check, and test runners can all reuse one cached install. + + + +A failed runner retries automatically. Runners that depend on it do not start until the retry succeeds. If the configured retry limit is reached, the Workflow ends in an `Errored` state. + +Here is an example of how to set up your Workflow to use runners and cache to install dependencies, run checks, build the project, and deploy the Worker: + + + +```ts +// Install dependencies — cached based on package-lock.json so later +// runs skip this step when the lockfile has not changed. +const deps = await checkout + .cache(["repo/package-lock.json"]) + .runner("install dependencies", { + cwd: "repo", + exec: "npm ci", + }); + +// Run checks in parallel — all three must pass before the pipeline continues. +await Promise.all([ + deps.runner("lint", { + cwd: "repo", + exec: "npm run lint --if-present", + }), + deps.runner("typecheck", { + cwd: "repo", + exec: "npm run typecheck --if-present", + }), + deps.runner("test", { + cwd: "repo", + exec: "npm test --if-present", + }), +]); + +// Build the project — produces dist/worker.mjs. +const build = await deps.runner("build", { + cwd: "repo", + exec: "npm run build", +}); + +// Deploy — only this runner receives the CLOUDFLARE_API_TOKEN secret. +await build.runner("deploy Worker", { + cwd: "repo", + exec: "node ./ci/deploy-worker.mjs", + env: { + CLOUDFLARE_ACCOUNT_ID: "", + WORKER_NAME: "my-application", + }, + secrets: ["CLOUDFLARE_API_TOKEN"], +}); +``` + + + +### View build status + +The `[observability]` setting in your Wrangler configuration records the status and logs for each pipeline run. To identify which stage failed, inspect the instance in the Workflows dashboard: + + + +Each runner displays its own logs and status, so you can identify the command that failed. When a runner fails, the Workflow records its output and does not start stages that need its files. + +## Deploy the application + +Once all checks pass and the build completes, the final runner deploys the latest version. It executes a script that calls the Cloudflare API with a deployment token. + +### Store the deployment token + +Worker and User Worker deployments require an API token. To keep the token out of your source code, store it as a secret on the Worker that defines the Workflow: + + + +The `secrets` option injects the token into only the deploy runner's environment. The install, check, and build runners do not receive it, so commands from the project cannot read or use the token. + +### Deploy the Worker + +The deploy runner executes a script that calls the Cloudflare API to deploy the latest version. Choose the deployment target that matches your application: + + + +The deploy runner executes `ci/deploy-worker.mjs`, which calls the Cloudflare API to deploy the latest version of the Worker: + + + +```js +import { readFile } from "node:fs/promises"; +import Cloudflare from "cloudflare"; + +function requireEnvironmentVariable(name) { + const value = process.env[name]; + + if (!value) { + throw new Error(`Missing required environment variable: ${name}`); + } + + return value; +} + +const apiToken = requireEnvironmentVariable("CLOUDFLARE_API_TOKEN"); +const accountId = requireEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID"); +const scriptName = requireEnvironmentVariable("WORKER_NAME"); +const workerSource = await readFile("dist/worker.mjs", "utf8"); + +const scriptFile = new File([workerSource], "worker.mjs", { + type: "application/javascript+module", +}); + +const client = new Cloudflare({ apiToken }); + +await client.workers.scripts.update(scriptName, { + account_id: accountId, + metadata: { + main_module: "worker.mjs", + }, + files: [scriptFile], +}); +``` + + + +This calls `PUT /accounts/{account_id}/workers/scripts/{script_name}`. If the Worker exists, the request replaces its script. + + + +To deploy to a [Workers for Platforms](/cloudflare-for-platforms/workers-for-platforms/) dispatch namespace instead, the deploy runner executes `ci/deploy-user-worker.mjs`, which calls the Cloudflare API to deploy the latest version as a User Worker: + + + +```js +import { readFile } from "node:fs/promises"; +import Cloudflare from "cloudflare"; + +function requireEnvironmentVariable(name) { + const value = process.env[name]; + + if (!value) { + throw new Error(`Missing required environment variable: ${name}`); + } + + return value; +} + +const apiToken = requireEnvironmentVariable("CLOUDFLARE_API_TOKEN"); +const accountId = requireEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID"); +const namespace = requireEnvironmentVariable("DISPATCH_NAMESPACE"); +const userWorkerName = requireEnvironmentVariable("USER_WORKER_NAME"); +const workerSource = await readFile("dist/worker.mjs", "utf8"); + +const scriptFile = new File([workerSource], "worker.mjs", { + type: "application/javascript+module", +}); + +const client = new Cloudflare({ apiToken }); + +await client.workersForPlatforms.dispatch.namespaces.scripts.update( + namespace, + userWorkerName, + { + account_id: accountId, + metadata: { + main_module: "worker.mjs", + }, + files: [scriptFile], + }, +); +``` + + + +This calls `PUT /accounts/{account_id}/workers/dispatch/namespaces/{namespace}/scripts/{script_name}`. If the User Worker exists, the request replaces its script. + + From 1f912b90b0b2dfda7edb5205f6a8447e315afae7 Mon Sep 17 00:00:00 2001 From: mmalden <179233968+mia303@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:42:18 -0400 Subject: [PATCH 2/8] [Artifacts] Update API examples --- .../guides/build-and-deploy-on-push.mdx | 290 +++++------------- 1 file changed, 84 insertions(+), 206 deletions(-) diff --git a/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx b/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx index 811c6dd7a52..bf9bb0bc6e5 100644 --- a/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx +++ b/src/content/docs/artifacts/guides/build-and-deploy-on-push.mdx @@ -19,7 +19,7 @@ import { WranglerConfig, } from "~/components"; -Artifacts events can build and deploy projects stored in Artifacts repos. When a user or agent pushes a commit, the event starts a Workflow. +Artifacts events can build and deploy projects stored in Artifacts repos. When a user or agent pushes a commit, the event triggers a [Workflow instance](/workflows/build/trigger-workflows/). Within the Workflow, continuous integration (CI) tooling caches dependencies, runs checks, and builds the project. The pipeline can deploy output as a [Worker](/workers/) or a [Workers for Platforms](/cloudflare-for-platforms/workers-for-platforms/) User Worker. @@ -27,7 +27,7 @@ This is useful when you need to: - Automatically build and deploy application code stored in Artifacts. - Run linting, type checking, tests, and other checks on every push. -- Reuse dependencies when `package-lock.json` has not changed. +- Reuse dependencies when the lockfile (i.e. `pnpm-lock.yaml`) has not changed. - Stop deployment when a check or build fails. - Restrict API token access to the deployment step. - Deploy output as a Worker or User Worker. @@ -38,141 +38,128 @@ This is useful when you need to: 1. **Push repo changes** — A `git push` to the Artifacts repo emits an `artifacts.push` event that identifies the pushed repo, branch, and commit. 2. **Run the CI Workflow** — The event starts a Workflow that checks out the commit, installs and caches dependencies, and runs CI steps — build, lint, typecheck, and format — in parallel. A failed step stops the Workflow before deployment. -3. **Build the project** — Once all checks pass, the Workflow builds the project output for deployment. -4. **Deploy the Worker** — The Workflow deploys the built Worker as a preview for non-main branches or to production for the main branch. +3. **Deploy the Worker** — The Workflow deploys the built Worker either directly to your account or as a User Worker, if using Workers for Platforms ## Start a build when code changes -When a user or agent pushes a commit to an Artifacts repo, Artifacts emits an event that identifies the repo, branch, and commit that changed. You will use this event to start a Workflow that runs a CI pipeline — checking out the commit, installing dependencies, running checks, building the project, and deploying the Worker. +When a user or agent pushes a commit to an Artifacts repo, Artifacts emits an event that identifies the repo, branch, and commit that changed. You will use this event to start a Workflow that runs a CI pipeline by checking out the commit, installing dependencies, running checks, building the project, and deploying the Worker. -This guide defines those CI steps in a Workflow class named `BuildAndDeployWorkflow`. To start this Workflow automatically after each push, add an `artifacts.push` trigger to your Wrangler configuration: +This guide defines those CI steps in a Workflow class named `CIWorkflow`. To start this Workflow automatically after each push, add an `artifacts.push` trigger to your Wrangler configuration: -```toml -name = "artifact-ci" -main = "src/index.ts" -compatibility_date = "$today" - -[[workflows]] -name = "build-and-deploy" -binding = "BUILD_AND_DEPLOY" -class_name = "BuildAndDeployWorkflow" - -[[triggers]] -type = "artifacts.push" -class_name = "BuildAndDeployWorkflow" - -[observability] -enabled = true +```json +{ + "name": "my-ci-cd-worker", + "main": "src/index.ts", + "compatibility_date": "2026-07-21", + + "workflows": [ + { + "name": "ci-workflow", + "binding": "BUILD_AND_DEPLOY", + "class_name": "CIWorkflow" + } + ], + + "artifacts": [ + { + "binding": "ARTIFACTS", + "namespace": "customer-projects" + } + ], + + "triggers": [ + { + "type": "cf.repo.push", + "filter": { + "repoName": "my-repo", + "namespace": "ARTIFACTS" + }, + "target": { + "type": "workflow", + "workflowName": "ci-workflow" + } + } + ], + + "observability": { + "enabled": true + } +} ``` +:::note +If you are running CI for a User Worker, include `"dispatch_namespace":" in your Trigger target. +::: + ## Run the build pipeline To run the build pipeline, the Workflow first needs the files from the pushed commit. It clones the repo, then uses runners to install dependencies, run checks, build the project, and deploy the Worker. -### Check out the pushed commit - -Before the Workflow can run build commands, it needs a local copy of the pushed commit. To retrieve the repo's Git remote and create a short-lived read token, expose the repo namespace to the Workflow through an [Artifacts binding](/artifacts/api/workers-binding/). - -Add the binding to your Wrangler configuration. Set `namespace` to the same namespace that emits the push events handled by this Workflow: - - - -```toml -[[artifacts]] -binding = "ARTIFACTS" -namespace = "customer-projects" -``` - - - -The binding is available as `env.ARTIFACTS`. - -Use the repo name from the push event to get its handle, create a short-lived read token, and pass both to a runner that clones the repo and checks out the pushed commit: - - - -```ts -const repo = await this.env.ARTIFACTS.get(push.source.repoName); -const token = await repo.createToken("read", 900); - -const checkout = await step.runner("check out pushed commit", { - exec: - "rm -rf repo && " + - 'git -c "http.extraHeader=Authorization: Bearer $ARTIFACTS_TOKEN" ' + - 'clone "$ARTIFACTS_REMOTE" repo && ' + - 'git -C repo checkout --detach "$COMMIT_SHA"', - env: { - ARTIFACTS_REMOTE: repo.remote, - ARTIFACTS_TOKEN: token.plaintext, - COMMIT_SHA: push.payload.after, - }, -}); -``` - - - -- `env.ARTIFACTS.get()` returns the repo handle for the name in the push event. -- `createToken("read", 900)` creates a read-only token that expires after 15 minutes. The token is passed only to the checkout runner and is never stored in the repo. -- `push.payload.after` identifies the exact commit that triggered this Workflow. A branch can receive another commit before checkout begins, so using the SHA from the event ensures the Workflow builds the intended version. - ### Define the CI steps -Once the repo is checked out, use the `@cloudflare/ci` SDK to define the CI steps. The SDK provides two tools to help you build the pipeline: +Use the `@cloudflare/ci` SDK to define the CI steps. The SDK provides two tools to help you build the pipeline: - **Runners** — each `runner()` call spins up an isolated sandbox and executes a shell command. You use the same commands you already run locally or in another CI system. Each runner captures its own logs, status, and output files. -- **Cache** — `step.cache()` allows you to cache installed dependencies so that later Workflow runs do not reinstall them. Pass the files that determine the dependencies, such as `package-lock.json`, to `step.cache()`. When those files have not changed, the SDK restores the cached result instead of running the command again. +- **Cache** — the `cache` option on a runner caches installed dependencies so that later runs do not reinstall them. Pass the files that determine the dependencies, such as `pnpm-lock.yaml`, to `cache.inputs`. When those files have not changed, the SDK restores the cached result instead of running the command again. -Each runner passes its output files to the next, so your install step feeds your checks, your checks gate your build, and your build feeds your deployment. Multiple runners can branch from the same cached result — for example, lint, type-check, and test runners can all reuse one cached install. +A cached runner takes a [snapshot](/sandbox/api/backups/) of its sandbox, which later runners reuse. Multiple runners can branch from the same cached result — for example, lint, type-check, and test runners can all reuse one cached install. -A failed runner retries automatically. Runners that depend on it do not start until the retry succeeds. If the configured retry limit is reached, the Workflow ends in an `Errored` state. +A failed runner retries according to its [step configuration](/workflows/build/sleeping-and-retrying/#retry-steps), where you can define the number of retry attempts, backoff schedule, and timeouts. Runners that depend on a previous step do not start until its retry succeeds. If the configured retry limit is reached, the Workflow terminates in an `Errored` state. Here is an example of how to set up your Workflow to use runners and cache to install dependencies, run checks, build the project, and deploy the Worker: ```ts -// Install dependencies — cached based on package-lock.json so later +// Install dependencies — cached based on pnpm-lock.yaml so later // runs skip this step when the lockfile has not changed. -const deps = await checkout - .cache(["repo/package-lock.json"]) - .runner("install dependencies", { - cwd: "repo", - exec: "npm ci", - }); +const { workspace } = await ci.workspace.runner({ + name: "install dependencies", + command: "pnpm install --frozen-lockfile", + workingDirectory: "repo", + cache: { + inputs: ["repo/pnpm-lock.yaml"], + }, +}); // Run checks in parallel — all three must pass before the pipeline continues. await Promise.all([ - deps.runner("lint", { - cwd: "repo", - exec: "npm run lint --if-present", + workspace.runner({ + name: "lint", + command: "pnpm lint", + workingDirectory: "repo", }), - deps.runner("typecheck", { - cwd: "repo", - exec: "npm run typecheck --if-present", + workspace.runner({ + name: "typecheck", + command: "pnpm typecheck", + workingDirectory: "repo", }), - deps.runner("test", { - cwd: "repo", - exec: "npm test --if-present", + workspace.runner({ + name: "test", + command: "pnpm test", + workingDirectory: "repo", }), ]); // Build the project — produces dist/worker.mjs. -const build = await deps.runner("build", { - cwd: "repo", - exec: "npm run build", +const { workspace: build } = await workspace.runner({ + name: "build", + command: "pnpm build", + workingDirectory: "repo", }); // Deploy — only this runner receives the CLOUDFLARE_API_TOKEN secret. -await build.runner("deploy Worker", { - cwd: "repo", - exec: "node ./ci/deploy-worker.mjs", - env: { +await build.runner({ + name: "deploy Worker", + command: "node ./ci/deploy-worker.mjs", + workingDirectory: "repo", + environment: { CLOUDFLARE_ACCOUNT_ID: "", WORKER_NAME: "my-application", }, @@ -192,115 +179,6 @@ Each runner displays its own logs and status, so you can identify the command th ## Deploy the application -Once all checks pass and the build completes, the final runner deploys the latest version. It executes a script that calls the Cloudflare API with a deployment token. - -### Store the deployment token - -Worker and User Worker deployments require an API token. To keep the token out of your source code, store it as a secret on the Worker that defines the Workflow: - - - -The `secrets` option injects the token into only the deploy runner's environment. The install, check, and build runners do not receive it, so commands from the project cannot read or use the token. - -### Deploy the Worker - -The deploy runner executes a script that calls the Cloudflare API to deploy the latest version. Choose the deployment target that matches your application: - - - -The deploy runner executes `ci/deploy-worker.mjs`, which calls the Cloudflare API to deploy the latest version of the Worker: - - - -```js -import { readFile } from "node:fs/promises"; -import Cloudflare from "cloudflare"; - -function requireEnvironmentVariable(name) { - const value = process.env[name]; - - if (!value) { - throw new Error(`Missing required environment variable: ${name}`); - } - - return value; -} - -const apiToken = requireEnvironmentVariable("CLOUDFLARE_API_TOKEN"); -const accountId = requireEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID"); -const scriptName = requireEnvironmentVariable("WORKER_NAME"); -const workerSource = await readFile("dist/worker.mjs", "utf8"); - -const scriptFile = new File([workerSource], "worker.mjs", { - type: "application/javascript+module", -}); - -const client = new Cloudflare({ apiToken }); - -await client.workers.scripts.update(scriptName, { - account_id: accountId, - metadata: { - main_module: "worker.mjs", - }, - files: [scriptFile], -}); -``` - - - -This calls `PUT /accounts/{account_id}/workers/scripts/{script_name}`. If the Worker exists, the request replaces its script. - - - -To deploy to a [Workers for Platforms](/cloudflare-for-platforms/workers-for-platforms/) dispatch namespace instead, the deploy runner executes `ci/deploy-user-worker.mjs`, which calls the Cloudflare API to deploy the latest version as a User Worker: - - - -```js -import { readFile } from "node:fs/promises"; -import Cloudflare from "cloudflare"; - -function requireEnvironmentVariable(name) { - const value = process.env[name]; - - if (!value) { - throw new Error(`Missing required environment variable: ${name}`); - } - - return value; -} - -const apiToken = requireEnvironmentVariable("CLOUDFLARE_API_TOKEN"); -const accountId = requireEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID"); -const namespace = requireEnvironmentVariable("DISPATCH_NAMESPACE"); -const userWorkerName = requireEnvironmentVariable("USER_WORKER_NAME"); -const workerSource = await readFile("dist/worker.mjs", "utf8"); - -const scriptFile = new File([workerSource], "worker.mjs", { - type: "application/javascript+module", -}); - -const client = new Cloudflare({ apiToken }); - -await client.workersForPlatforms.dispatch.namespaces.scripts.update( - namespace, - userWorkerName, - { - account_id: accountId, - metadata: { - main_module: "worker.mjs", - }, - files: [scriptFile], - }, -); -``` - - - -This calls `PUT /accounts/{account_id}/workers/dispatch/namespaces/{namespace}/scripts/{script_name}`. If the User Worker exists, the request replaces its script. +To deploy a Worker, pass `wrangler deploy` to your final `runner()` step, i.e. `workspace.runner({ name: "deploy", command: "wrangler deploy" })`. - +To deploy a User Worker, pass `wrangler deploy --dispatch_namespace ` to your final `runner()` step. From 47ef2f699617bc718b086b92453668b897cb4655 Mon Sep 17 00:00:00 2001 From: mmalden <179233968+mia303@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:19:03 -0400 Subject: [PATCH 3/8] [Artifacts] Update diagram for deploy step --- .../ArtifactsCIWorkflowDiagram.astro | 136 +++--------------- .../guides/build-and-deploy-on-push.mdx | 2 +- 2 files changed, 20 insertions(+), 118 deletions(-) diff --git a/src/components/ArtifactsCIWorkflowDiagram.astro b/src/components/ArtifactsCIWorkflowDiagram.astro index 6400815fee1..42a652f1a84 100644 --- a/src/components/ArtifactsCIWorkflowDiagram.astro +++ b/src/components/ArtifactsCIWorkflowDiagram.astro @@ -11,7 +11,7 @@ const { autoPlay = true, loop = true } = Astro.props;
- + -
- Deploy Worker -
-
- - Preview - Non-main branch -
-
- - Production - Main branch -
+
+
+ + Deploy Worker
-
+
@@ -320,28 +286,22 @@ const { autoPlay = true, loop = true } = Astro.props; stroke: var(--diagram-accent); } - .workflow-group, - .deployment-group { + .workflow-group { position: relative; background: var(--diagram-group); border: 1px dashed var(--diagram-line); border-radius: 0.75rem; transition: border-color 0.3s ease; - } - - .workflow-group { padding: 2.25rem 1rem 1rem; } - .workflow-group > .group-label, - .deployment-group > .group-label { + .workflow-group > .group-label { position: absolute; top: 0.625rem; left: 0.75rem; } - .workflow-group.is-active, - .deployment-group.is-active { + .workflow-group.is-active { border-color: var(--diagram-accent); } @@ -423,71 +383,18 @@ const { autoPlay = true, loop = true } = Astro.props; height: 1rem; } - .branch-split { - position: relative; - height: 94px; - margin-bottom: -1px; - } - - .branch-split svg { - display: block; - width: 100%; - height: 100%; - overflow: visible; - } - - .split-path { - fill: none; - stroke: var(--diagram-line); - stroke-width: 2; - vector-effect: non-scaling-stroke; - transition: stroke 0.3s ease; - } - - .split-path.is-active { - stroke: var(--diagram-accent); - } - - .branch-label { - font-size: 0.5625rem; - line-height: 1.25rem; - color: var(--diagram-muted); - text-align: center; - white-space: nowrap; - transition: color 0.3s ease; - } - - .branch-label.is-active { - color: var(--diagram-accent); - } - - .branch-labels { - position: absolute; - top: 41px; - left: 0; - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - width: 100%; - } - - .deployment-group { - padding: 2.25rem 0.75rem 0.75rem; - } - - .deployment-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.5rem; + .deployment-stage { + display: flex; + justify-content: center; } .deployment-card { display: flex; - flex-direction: column; align-items: center; justify-content: center; - gap: 0.25rem; - min-width: 0; - padding: 0.75rem 0.5rem; + gap: 0.625rem; + width: 240px; + padding: 0.625rem 0.875rem; } .deployment-icon { @@ -499,11 +406,6 @@ const { autoPlay = true, loop = true } = Astro.props; font-size: 0.6875rem; } - .deployment-note { - font-size: 0.5625rem; - color: var(--diagram-muted); - } - @media (max-width: 30rem) { .diagram-container { width: 100%; @@ -527,7 +429,7 @@ const { autoPlay = true, loop = true } = Astro.props;