Implementation
Option A end to end: the Cloudflare token, the Bitbucket variables and environments, the
wrangler.tomllayout, and thebitbucket-pipelines.ymlthat carries a change from a feature branch through dev and staging to production.
This is the implementation process for a Bitbucket-hosted Worker. It maps one to one onto the gate sequence in the QA and Deployment SOP. Where the SOP describes the GitHub Actions job, this describes the Bitbucket step that does the same work.
Prerequisites
Section titled “Prerequisites”- A Worker whose source lives in a Bitbucket repository.
- Admin on that Bitbucket repository, to set variables and enable Pipelines.
- Access to the Adventive Cloudflare account to mint a scoped API token and read the account ID.
- Wrangler pinned as a dev dependency in the project (
npm install --save-dev wrangler). Do not rely on a global install in CI.
Part 1: Cloudflare side
Section titled “Part 1: Cloudflare side”1.1 Create a scoped API token
Section titled “1.1 Create a scoped API token”The pipeline authenticates to Cloudflare with an API token, never a global key. Scope it to the minimum the deploy needs.
- In the Cloudflare dashboard, go to My Profile → API Tokens → Create Token.
- Start from the Edit Cloudflare Workers template, or build a custom token with these permissions:
- Account → Workers Scripts → Edit
- Zone → Workers Routes → Edit, scoped to the specific zones the Worker serves (
adventive.dev,adventivestg.com,adventive.comas applicable). Do not grant all zones. - Account → Account Settings → Read (required for Wrangler to resolve the account).
- If the Worker binds KV, R2, or D1, add Workers KV Storage → Edit, Workers R2 Storage → Edit, or D1 → Edit as needed.
- If the Worker binds a secret from Cloudflare Secrets Store (the platform default for runtime secrets), the token also needs Account → Secrets Store → Edit. Binding a secret to a Worker is a write against the secret; a read-only token fails at deploy time with an authorization error.
- Create the token and copy it once. You cannot retrieve it again.
Scope the token to the zones the Worker touches. An account-global token in a repository variable is a standing risk. The QA and Deployment SOP requires
Workers Scripts:Editplus the specific zones, nothing wider.
1.2 Note the account ID
Section titled “1.2 Note the account ID”From the Cloudflare dashboard, Workers & Pages → Account details, copy the Account ID. It is not a secret, but the pipeline needs it as CLOUDFLARE_ACCOUNT_ID.
1.3 Runtime secrets stay in Secrets Store
Section titled “1.3 Runtime secrets stay in Secrets Store”The pipeline does not carry runtime secrets. Worker runtime secrets (for example the New Relic license key) are created once at the account level in Cloudflare Secrets Store and bound by reference in wrangler.toml through [[secrets_store_secrets]] blocks. Never use wrangler secret put in a committed pipeline. The only credentials the pipeline holds are the API token and the account ID.
Part 2: Bitbucket side
Section titled “Part 2: Bitbucket side”2.1 Enable Pipelines
Section titled “2.1 Enable Pipelines”In the repository, go to Repository settings → Pipelines → Settings and toggle Enable Pipelines. This activates the bitbucket-pipelines.yml at the repo root.
2.2 Store credentials as secured variables
Section titled “2.2 Store credentials as secured variables”Cloudflare credentials go in Bitbucket as variables, never in the repository.
For account-wide values, use Repository settings → Repository variables:
CLOUDFLARE_API_TOKEN— mark it Secured so it is masked in logs and not readable after saving.CLOUDFLARE_ACCOUNT_ID— the account ID from step 1.2.
For per-environment separation, prefer Deployment variables (below) so the staging and production tokens differ and a staging build can never deploy to production.
2.3 Define deployment environments
Section titled “2.3 Define deployment environments”Bitbucket Deployments give per-environment tracking, environment-scoped variables, and deployment gating. Go to Repository settings → Deployments and confirm the environment tiers exist: Test, Staging, and Production. Map them to Adventive’s dev, stg, and prd.
Under each environment, set environment-scoped Deployment variables. A production-scoped CLOUDFLARE_API_TOKEN visible only to production steps is the mechanism that stops a staging build from ever holding production credentials.
2.4 Restrict who can deploy to production
Section titled “2.4 Restrict who can deploy to production”In Repository settings → Deployments, restrict the Production environment so only authorized reviewers can trigger a deployment to it. Combined with a manual trigger on the production step (Part 4), this is the Bitbucket equivalent of GitHub environment protection reviewers.
Part 3: Wrangler environments
Section titled “Part 3: Wrangler environments”The pipeline deploys per environment with wrangler deploy --env <name>. The wrangler.toml declares one block per environment, matching the naming standard.
name = "adv-svc-example-prd"main = "src/index.ts"compatibility_date = "2026-07-01"
[env.dev]name = "adv-svc-example-dev"route = { pattern = "example.adventive.dev", zone_name = "adventive.dev" }vars = { OTEL_ENABLED = "false", COMMIT_SHA = "local" }
[env.staging]name = "adv-svc-example-stg"route = { pattern = "example.adventivestg.com", zone_name = "adventivestg.com" }vars = { OTEL_ENABLED = "true", COMMIT_SHA = "ci-placeholder" }
[env.production]name = "adv-svc-example-prd"route = { pattern = "example.adventive.com", zone_name = "adventive.com" }vars = { OTEL_ENABLED = "true", COMMIT_SHA = "ci-placeholder" }COMMIT_SHA is a literal placeholder in the file. The pipeline overrides it at deploy time so the deployed Worker’s health endpoint reports the real commit. Runtime secrets are added as [[secrets_store_secrets]] blocks per environment, not shown here; see the Secrets and Security Policy.
Every custom hostname needs its proxied AAAA record at
100::before the Worker deploys to that route. Pre-create the DNS record, or the first request returns a 1014 error. This is a platform rule, independent of the CI provider.
Part 4: The pipeline
Section titled “Part 4: The pipeline”bitbucket-pipelines.yml at the repo root. Branch and tag mapping:
- Any feature branch and every pull request run the quality gate and a dry-run deploy. Nothing ships.
developdeploys todevafter the gate.maindeploys tostgafter the gate, then smoke-tests staging.- A
v*.*.*tag deploys toprdbehind a manual gate, smoke-tests production, and rolls back automatically on smoke failure.
image: node:20
definitions: caches: npm: ~/.npm steps: - step: &quality name: Quality gate caches: [npm] script: - npm ci - npm run lint - npm run typecheck - npm run test - bash scripts/preflight-secrets.sh - npx wrangler deploy --dry-run --env staging artifacts: - dist/**
pipelines: pull-requests: "**": - step: *quality
branches: develop: - step: *quality - step: name: Deploy dev deployment: test caches: [npm] script: - npm ci - npx wrangler deploy --env dev --var COMMIT_SHA:$BITBUCKET_COMMIT - bash scripts/smoke.sh https://example.adventive.dev $BITBUCKET_COMMIT
main: - step: *quality - step: name: Deploy staging deployment: staging caches: [npm] script: - npm ci - npx wrangler deploy --env staging --var COMMIT_SHA:$BITBUCKET_COMMIT - bash scripts/smoke.sh https://example.adventivestg.com $BITBUCKET_COMMIT
tags: "v*.*.*": - step: *quality - step: name: Deploy production deployment: production trigger: manual caches: [npm] script: - npm ci - npx wrangler deploy --env production --var COMMIT_SHA:$BITBUCKET_COMMIT - bash scripts/smoke.sh https://example.adventive.com $BITBUCKET_COMMITThe &quality YAML anchor defines the gate once and reuses it, so every path runs the identical gate. $BITBUCKET_COMMIT is Bitbucket’s built-in commit SHA. trigger: manual holds the production step until an authorized reviewer clicks deploy, which pairs with the Production environment restriction from step 2.4.
Automatic rollback on smoke failure
Section titled “Automatic rollback on smoke failure”Bitbucket has no direct equivalent of the GitHub if: failure() step, so guard the rollback with shell. Replace the production script with a form that rolls back if the smoke test fails:
script: - npm ci - npx wrangler deploy --env production --var COMMIT_SHA:$BITBUCKET_COMMIT - | if ! bash scripts/smoke.sh https://example.adventive.com $BITBUCKET_COMMIT; then npx wrangler rollback --env production --message "automatic rollback from CI after smoke failure" exit 1 fiRollback is containment, not a fix. After any automatic rollback, follow the rollback procedure in the QA and Deployment SOP: open an incident, confirm metrics returned to baseline, and leave staging on the broken version so the fix is developed against the real failure.
Part 5: The gate sequence, mapped
Section titled “Part 5: The gate sequence, mapped”| SOP step | Bitbucket step | Command |
|---|---|---|
| Install | Quality gate | npm ci |
| Lint | Quality gate | npm run lint |
| Typecheck | Quality gate | npm run typecheck |
| Unit tests | Quality gate | npm run test |
| Secret scan | Quality gate | bash scripts/preflight-secrets.sh |
| Dry-run deploy | Quality gate | npx wrangler deploy --dry-run --env staging |
| Deploy | Deploy dev/staging/production | npx wrangler deploy --env <name> |
| Smoke test | after each real deploy | bash scripts/smoke.sh <url> <sha> |
Steps run in order; an early failure short-circuits the rest. A red gate does not merge or deploy.
Part 6: Environment promotion and soak
Section titled “Part 6: Environment promotion and soak”- dev is the shared development environment, deployed from
develop. Per-engineer local iteration still useswrangler devand does not go through the pipeline. - stg deploys automatically on merge to
main. - prd deploys only from a
v*.*.*tag, behind the manual gate.
Between staging and production, the change observes the staging soak window from the QA and Deployment SOP, sized by change type and Worker tier (15 minutes for config-only up to 24 hours for tier-1 or any D1 schema change). No soak, no promotion. During soak, the owning team watches Workers analytics and Logpush for new error classes.
Part 7: First-run checklist
Section titled “Part 7: First-run checklist”- [ ] Wrangler pinned as a dev dependency- [ ] wrangler.toml has [env.dev], [env.staging], [env.production] with correct routes and zones- [ ] Proxied AAAA record at 100:: exists for every custom hostname- [ ] Runtime secrets created in Cloudflare Secrets Store and bound in wrangler.toml- [ ] Scoped API token created (Workers Scripts:Edit + specific zones + Secrets Store:Edit if bound)- [ ] CLOUDFLARE_API_TOKEN stored Secured; production token scoped to the Production environment- [ ] CLOUDFLARE_ACCOUNT_ID set- [ ] Bitbucket Pipelines enabled- [ ] Deployment environments mapped (Test/Staging/Production to dev/stg/prd)- [ ] Production environment restricted to authorized reviewers- [ ] scripts/preflight-secrets.sh and scripts/smoke.sh present and executable- [ ] bitbucket-pipelines.yml committed- [ ] A test change confirms: gate on PR, deploy on develop/main, gated deploy on tag