App deploy
app-deploy.yml: validate every PR, deploy a Layer-3 app to Cloudflare on every push to main.
What it does
app-deploy.yml is for an app that deploys and never publishes to npm. It has two jobs, and
everything it runs is a script name you pass in.
| Job | Check name | Runs on | Steps |
|---|---|---|---|
validate | ci / Validate (typecheck · lint · test · build) | every PR and push | typecheck, lint, test, build, worker build |
deploy | ci / Deploy to Cloudflare | a push to main only | build, worker build, migrations, deploy |
On a pull request deploy shows as skipped. A fork or a branch never deploys.
Set it up
The CLI sets up packages only. An app copies the caller.
-
Add a
deployscript. On@moku-labs/webthat isbun scripts/deploy.ts, see Build & deploy. -
Copy the caller. It comes with the package.
copy bun add -d @moku-labs/ci mkdir -p .github/workflows cp node_modules/@moku-labs/ci/examples/app/ci.yml .github/workflows/ci.yml
-
Set the two secrets. Each command asks for the value, so it stays out of your shell history.
secrets gh secret set CLOUDFLARE_API_TOKEN gh secret set CLOUDFLARE_ACCOUNT_ID
-
Trim the caller to what the app has. A static site needs no worker build and no migrations.
This is the caller of this website, moku-labs.com:
name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
ci:
uses: moku-labs/ci/.github/workflows/app-deploy.yml@v1
with:
test_script: test:coverage
deploy_script: deploy
secrets:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}- Safe here, because
app-deploy.ymlsets no group of its own. A newer push cancels the older run. - Reusable workflows do not inherit secrets. Pass each one by name.
With a backend
An app with a Worker and a database passes the two optional scripts.
jobs:
ci:
uses: moku-labs/ci/.github/workflows/app-deploy.yml@v1
with:
test_script: test:coverage
build_worker_script: build:worker
migrate_script: migrate:remote
deploy_script: deploy
secrets:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}- Runs after the client build: the worker's dry run reads
dist/client. - Runs before the deploy, for example
wrangler d1 migrations apply <db> --remote.
Inputs
| Input | Default | Meaning |
|---|---|---|
runs_on | ubuntu-latest | Runner label for both jobs |
bun_version | latest | Passed to setup-bun |
lint_script | lint | Script of the lint step |
typecheck_script | typecheck | Script of the typecheck step |
test_script | test | For example test:coverage |
build_script | build | The client build |
build_worker_script | empty | A second build. Empty skips it. |
migrate_script | empty | Runs before the deploy. Empty skips it. |
deploy_script | deploy | The deploy script |
| Secret | Required | Meaning |
|---|---|---|
CLOUDFLARE_API_TOKEN | yes | A Cloudflare token that may deploy this project |
CLOUDFLARE_ACCOUNT_ID | yes | The Cloudflare account id |
Dependabot
Copy node_modules/@moku-labs/ci/examples/dependabot.yml to .github/dependabot.yml. Leave
auto-merge out: on an app a merge runs the deploy, so a person merges the bump.
deploybuilds again. The jobs share no artifact, so the deploy job installs and builds from the commit itself.- The lockfile must be committed. Both jobs run
bun install --frozen-lockfile. - The package rules do not apply. An app has one
validatejob, sorulesets/main.jsonwould wait for checks that never report. See Rulesets for the app version. - Package previews do not apply. The pkg.pr.new job lives in
package-ci.yml.