Two pipelines, four stages, nothing to operate

Every push runs the same four steps. That's the whole thing.

There is no queue to watch, no service to keep alive, and no second system to learn. A push starts a build; the branch decides which Worker it lands on. Everything below is the same page in one picture.


The whole flow

One push, four stages, two possible destinations.

Both pipelines run the identical build. The only difference is which branch the push came from, and therefore which Worker receives the result. Read this grid once and you have the entire system.

01

Checks

Lint and the whole test suite. Fast, and the same command you run locally.

just check

02

Build

The Worker and its static assets are staged into a deployable tree.

just worker-build

03

Pick a Worker

The branch decides. main is production; anything else goes to staging, if it is the oldest open pull request.

staging_branch.py

04

Deploy

One wrangler deploy, against a config rendered for that environment.

wrangler deploy

Push to main gittrove.com

Merging a pull request is the production deploy. The merge commit becomes the push, the trigger fires, and the live site moves to that commit. There is no approval step in between, and nothing waits for staging to have passed.

Push to any other branch gittrove-staging

The branch reaches staging only if it is the oldest open pull request. Every other branch runs the same build and then deploys nothing — a green build that did no work, with the log naming which pull request holds the slot.


The one rule people forget

Staging belongs to the oldest open pull request.

There is one staging environment and every branch wants it. Rather than let them overwrite each other, exactly one holds it: the lowest pull request number. That is the change waiting longest, which is also the change whose staging environment is worth the most.

What that means when you push

  • You are the oldest open pull request. The gate deploys your branch to staging. This is the only case that deploys anything.
  • Someone else is older. Your build is green and it skips. This is normal — the log names the pull request that holds staging.
  • Your branch has no pull request. Same green skip. A branch alone never takes staging.
  • The gate cannot see GitHub. No token, an unreachable API, an answer it cannot read — the build goes red. A gate that cannot see should be looked at, not left quietly guarding nothing.

Environments

Two Workers, two databases, no shared fate.

Staging and production are separate Workers with separate D1 databases. Nothing staging does can reach a real customer, which is what makes it safe to point at a pull request.

  Production Staging
Worker gittrove gittrove-staging
Reached at gittrove.com, through a zone route its own workers.dev URL only, never the domain
Deployed by a push to main the oldest open pull request
Database its own D1 database its own D1 database
Payments Polar, live organisation Polar sandbox — a checkout there cannot charge anyone
Build identity both stamp GITTROVE_BUILD_SHA, so any deployment can name the commit it came from

What isn't there

Everything this deliberately does not do.

Most of the confusion around a pipeline comes from assuming machinery that was removed. None of the following exists, and nothing here needs it.

No Docker

The build runs on Cloudflare's builders. There is no local container to match, and no image to keep in step.

No hosted control plane

No service of ours sits in the path. Nothing needs restarting, and there is no queue to inspect.

No per-branch previews

Per-branch preview Workers are gone. They produced no stable URL to look at and gated nothing.

No automatic migrations

Deploying code never applies a migration. Schema changes are a separate, deliberate command against one environment.

No promotion gate

A merge deploys. If a change should not reach production, the place to stop it is the pull request.

No npm build

Node exists only because the Pyodide sync drives the interpreter through it. Nothing here runs an npm script.


When it breaks

What to check, in order.

Four stages means four places to look. Start at the top and stop at the first thing that is not what you expected.

The build is green but staging did not change.

This is the expected outcome for every branch that is not the oldest open pull request. Open the build log: it names the pull request that holds staging. If your branch is the oldest and still skipped, the gate reported a reason — read it rather than re-pushing.

The build is red before it deploys anything.

Checks and build are stages 01 and 02, and they are the same commands you can run locally. Run just check and just worker-build and you will see the failure before the builder does.

Production is serving the wrong commit.

Every deployment stamps the commit it came from. Read GITTROVE_BUILD_SHA off the running site and compare it with git rev-parse origin/main. If they differ, the latest push has not finished deploying yet, or its build failed — the Worker still serves the last good version, which is deliberate.

A change needs a database migration.

Migrations never run on their own. Apply them deliberately, against one environment at a time, and remember that code and schema move separately: a merge ships the code immediately while the schema waits for you.

I want to run the whole thing on my machine.

just worker-dev serves the Worker against a local database and applies the committed migrations first, so a fresh checkout serves a working application instead of failing on a missing table.