Files
lora.vegas/.gitea/workflows/deploy.yml
T
sneak f7e713ee68
check / check (push) Successful in 2m54s
Notify sneak's ntfy topic on every CI deploy (closes #48)
Add a notify job to the deploy workflow that posts an ntfy message on
success or failure, using the topic from secrets.NTFY_TOPIC.

Model: deepseek-v4-pro
2026-11-05 20:22:48 +00:00

151 lines
7.2 KiB
YAML

name: Build and Deploy to Cloudflare Pages
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
container:
# Same digest the Dockerfile pins: one pinned base image and the
# same dependency list (script/bootstrap) for both the check build
# and the deploy build. The one extra thing this job needs on top
# of the Dockerfile is the Actions runner's own prerequisites --
# see the first step.
# alpine 3.21, 2026-02-28
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
defaults:
run:
# The default step shell is bash; this image has only busybox
# sh, so say so explicitly rather than rely on a fallback.
shell: sh
steps:
# This image is bare busybox+musl. act_runner executes JavaScript
# actions (checkout, upload-artifact) with `node` *inside* the job
# container and does not inject one, so node has to exist before
# the first `uses:` step -- script/bootstrap runs too late. git is
# needed for checkout's `submodules: recursive` (without it
# checkout degrades to a tarball download that cannot do
# submodules). An inline `run:` needs only a shell, so this step
# works on the bare image. These apk packages resolve at run time
# and are not hash-pinned; that gap is repo-wide (script/bootstrap
# has it too) and is tracked in #19.
- name: Install runner prerequisites
run: apk add --no-cache nodejs git tar
- name: Checkout
# actions/checkout v4.2.2, 2026-02-28
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
submodules: recursive
- name: Install build dependencies
run: script/bootstrap
- name: Build site
run: script/test
- name: Archive site
run: tar -czf site.tar.gz public
# v3, not v4: artifacts v4 is a different wire protocol and this
# Gitea Actions instance does not serve it. That is what broke the
# deploy in run 25 -- measured by running two otherwise identical
# jobs on a branch, one ending in upload-artifact v4 (failed) and
# one without that step (passed). Tracked in #20. This SHA is the
# exact commit the mutable `@v3` used to resolve to, i.e. the code
# that was already deploying this site, now pinned rather than
# floating.
- name: Upload artifact
# actions/upload-artifact v3.2.1, 2026-08-09
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with:
name: site
path: site.tar.gz
deploy:
runs-on: ubuntu-latest
needs: build
# Publishing guard. This job spends CLOUDFLARE_API_TOKEN and creates a
# real Cloudflare Pages deployment, so it must never run off main --
# not even if a branch is added to the push trigger above, deliberately
# or by accident. Costs one line; the build job stays exercisable from
# a branch without this job touching anything external.
if: github.ref_name == 'main'
container:
# node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps:
# Must match the upload-artifact major above -- v4 artifacts and
# v3 artifacts are different protocols and do not interoperate.
# Like the upload above, this is the exact commit `@v3` used to
# resolve to.
- name: Download artifact
# actions/download-artifact v3.0.2, 2026-08-09
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: site
- name: Extract site
run: tar -xzf site.tar.gz
# 4.86.0, not the 4.120.0 that `latest` points at: wrangler
# 4.120.0 requires node >= 22 and refuses to start on this
# container's node 20. Note that the unpinned `npm install -g
# wrangler` this replaces was never installing `latest` either --
# npm picks the newest version whose engines the running node
# satisfies, which on node 20 is exactly 4.86.0. So this pins the
# version that has actually been deploying this site, rather than
# silently changing it. Moving the container to node 22 so the
# wrangler pin can advance is tracked in #21.
- name: Install Wrangler
# wrangler 4.86.0, 2026-08-09
run: npm install -g wrangler@4.86.0
- name: Deploy to Cloudflare Pages
run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
notify:
runs-on: ubuntu-latest
needs: [build, deploy]
# Run whether the build and deploy passed or failed. The Notify step
# carries continue-on-error: true so a notification that cannot be sent
# leaves the deploy's result exactly as it was.
if: always()
container:
# node 20.20.2-bookworm, 2026-08-09. Same pinned image as the deploy
# job, chosen because it ships curl; no extra packages to install.
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps:
# needs.deploy.result is "success" only when the deploy job actually
# published; anything else -- a failed build, a failed deploy, a
# cancelled run -- is reported as a failure with a link to the run.
- name: Notify
# curl failing (ntfy unreachable or erroring, or NTFY_TOPIC
# absent) must not fail the run, so continue-on-error lives on
# this step and not on the job: on this Gitea a job-level flag
# still marks the job failed and reddens the commit.
continue-on-error: true
env:
RESULT: ${{ needs.deploy.result }}
NTFY_TOPIC: ${{ secrets.NTFY_TOPIC }}
run: |
short="$(printf '%.7s' "$GITHUB_SHA")"
run_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
if [ "$RESULT" = success ]; then
curl -fsS --max-time 10 \
-H "Title: lora.vegas deployed from $GITHUB_REF_NAME" \
-d "$short deployed to https://lora.vegas/" \
"https://ntfy.sh/$NTFY_TOPIC"
else
curl -fsS --max-time 10 \
-H "Title: lora.vegas deploy from $GITHUB_REF_NAME failed" \
-H "Priority: high" \
-d "Run: $run_url" \
"https://ntfy.sh/$NTFY_TOPIC"
fi