ci: run the build pipeline on Gitea Actions

Point `uses:` at full GitHub URLs so step resolution does not depend on
the instance's DEFAULT_ACTIONS_URL, publish the image to Gitea's own
container registry, and drop the Pages deploy.

Pages has no Gitea equivalent and the container image is the deploy
artefact now, so the job is removed rather than replaced. `build` stays:
it is what produces the site bundle, and test/refresh.test.ts pins the
refresh-bookkeeping restore to the slice between `build:` and `image:`.
Its BASE_PATH goes, though — that existed only for the /<repo>/ subpath
Pages served from, and serve.ts serves the image at the root.

The registry host is derived from github.server_url rather than
hardcoded, so a fork on another instance pushes to its own registry.
Layer cache moves from type=gha to type=registry: Gitea does expose the
Actions cache API, but buildx's gha backend is the least reliable part
of that compatibility surface and we are already authenticated to a
registry that can hold the layers.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-09-16 04:28:53 +02:00
co-authored by Claude Opus 5
parent b2ec0951f4
commit ec80e76cdc
+38 -59
View File
@@ -20,9 +20,9 @@ jobs:
name: Typecheck, test, feed name: Typecheck, test, feed
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: https://github.com/actions/checkout@v4
- uses: oven-sh/setup-bun@v2 - uses: https://github.com/oven-sh/setup-bun@v2
with: with:
bun-version: "1.3" bun-version: "1.3"
@@ -36,7 +36,7 @@ jobs:
# Restore-only: refresh.yml owns writing this cache, and a miss just # Restore-only: refresh.yml owns writing this cache, and a miss just
# returns the pre-existing fallback behaviour. # returns the pre-existing fallback behaviour.
- name: Restore refresh bookkeeping - name: Restore refresh bookkeeping
uses: actions/cache/restore@v4 uses: https://github.com/actions/cache/restore@v4
with: with:
path: snapshots/*.state.json path: snapshots/*.state.json
key: refresh-state- key: refresh-state-
@@ -105,8 +105,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: check needs: check
steps: steps:
- uses: actions/checkout@v4 - uses: https://github.com/actions/checkout@v4
- uses: oven-sh/setup-bun@v2 - uses: https://github.com/oven-sh/setup-bun@v2
with: with:
bun-version: "1.3" bun-version: "1.3"
- run: bun install --frozen-lockfile - run: bun install --frozen-lockfile
@@ -114,19 +114,19 @@ jobs:
# This is the job whose output is deployed, so this is the one that must # This is the job whose output is deployed, so this is the one that must
# see the refresh bookkeeping; see the same step in `check`. # see the refresh bookkeeping; see the same step in `check`.
- name: Restore refresh bookkeeping - name: Restore refresh bookkeeping
uses: actions/cache/restore@v4 uses: https://github.com/actions/cache/restore@v4
with: with:
path: snapshots/*.state.json path: snapshots/*.state.json
key: refresh-state- key: refresh-state-
restore-keys: refresh-state- restore-keys: refresh-state-
- name: Build - name: Build
# Pages serves from /<repo>/, so the app is built with a matching base # Built at the domain root, because the container image is what gets
# href. Built at the domain root it would 404 on every asset. # deployed and `serve.ts` serves from `/`. A BASE_PATH belongs here only
env: # if this artefact is ever hosted under a subpath again — it was set to
BASE_PATH: /${{ github.event.repository.name }}/ # /<repo>/ for GitHub Pages, which this pipeline no longer deploys to.
run: bun run build run: bun run build
- uses: actions/upload-artifact@v4 - uses: https://github.com/actions/upload-artifact@v4
with: with:
name: site name: site
path: public/ path: public/
@@ -143,66 +143,45 @@ jobs:
contents: read contents: read
packages: write packages: write
steps: steps:
- uses: actions/checkout@v4 - uses: https://github.com/actions/checkout@v4
- uses: docker/setup-buildx-action@v3 - uses: https://github.com/docker/setup-buildx-action@v3
- name: Lowercase image name - name: Lowercase image name
id: img id: img
# GHCR rejects any uppercase in a repository name, and # Gitea's container registry, like GHCR before it, rejects any uppercase
# github.repository preserves the owner's casing verbatim. # in a repository name, and github.repository preserves the owner's
run: echo "name=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" # casing verbatim. The host is read from github.server_url rather than
# hardcoded, so a fork on another Gitea instance pushes to its own
# registry instead of this one.
env:
SERVER_URL: ${{ github.server_url }}
run: |
host="${SERVER_URL#https://}"
host="${host#http://}"
host="${host%%/*}"
# Two outputs on purpose: login wants the bare host, the tags want the
# full path. Passing the full path as the registry authenticates
# against a host that does not exist.
echo "host=${host}" >> "$GITHUB_OUTPUT"
echo "name=${host}/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"
- uses: docker/login-action@v3 - uses: https://github.com/docker/login-action@v3
with: with:
registry: ghcr.io registry: ${{ steps.img.outputs.host }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6 - uses: https://github.com/docker/build-push-action@v6
with: with:
context: . context: .
push: true push: true
tags: | tags: |
${{ steps.img.outputs.name }}:latest ${{ steps.img.outputs.name }}:latest
${{ steps.img.outputs.name }}:${{ github.sha }} ${{ steps.img.outputs.name }}:${{ github.sha }}
cache-from: type=gha # Registry cache rather than `type=gha`. Gitea does expose the Actions
cache-to: type=gha,mode=max # cache API, but buildx's gha backend is the least reliable corner of
# that compatibility surface, and we are already authenticated to a
# Deploying to Pages needs two one-time steps that CI cannot do for itself: # registry that can hold the layers.
# cache-from: type=registry,ref=${{ steps.img.outputs.name }}:buildcache
# 1. Settings → Pages → Source: "GitHub Actions". cache-to: type=registry,ref=${{ steps.img.outputs.name }}:buildcache,mode=max
# The default GITHUB_TOKEN cannot do this. Creating a Pages site needs
# `administration: write`, which is not a permission a workflow can grant
# GITHUB_TOKEN, so `configure-pages` with enablement: true fails with
# "Resource not accessible by integration".
# 2. Settings → Secrets and variables → Actions → Variables:
# set DEPLOY_PAGES to "true".
#
# Gated on that variable so the pipeline stays green for anyone who does not
# want Pages, rather than failing on every push forever.
pages:
name: Deploy to Pages
runs-on: ubuntu-latest
needs: build
if: >-
github.ref == 'refs/heads/main' &&
github.event_name != 'pull_request' &&
vars.DEPLOY_PAGES == 'true'
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/download-artifact@v4
with:
name: site
path: public
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: public
- id: deploy
uses: actions/deploy-pages@v4