Files
Ilia Denisov 81d8be08b2 phase 22
2026-05-11 11:38:40 +02:00
..
2026-05-07 08:24:44 +02:00
2026-05-07 08:24:44 +02:00
2026-05-11 11:38:40 +02:00
2026-05-07 08:24:44 +02:00
2026-05-07 08:24:44 +02:00

Local Gitea CI

Self-contained Gitea + Actions runner for verifying .gitea/workflows/* honestly before pushing to a real Gitea instance. Runs natively on arm64 (Apple Silicon) — every image below has an arm64 variant, so Docker pulls the right architecture and the runner executes workflow steps without QEMU emulation.

Prerequisites

  • Docker (Colima or Docker Desktop)
  • python3, curl, bash — all built into macOS

First time

make -C tools/local-ci up

This:

  1. brings up the Gitea container;
  2. creates an admin user (galaxy / galaxy-dev);
  3. creates the galaxy/galaxy repo;
  4. fetches a runner registration token from the Gitea API;
  5. brings up the runner with that token (the runner persists its credentials in a Docker volume and ignores the token on subsequent restarts).

The script is idempotent — re-running it is safe.

Pushing a branch

make -C tools/local-ci push

This adds a local-gitea remote on the first run and then pushes the current HEAD. Equivalent manual flow:

git remote add local-gitea \
    http://galaxy:galaxy-dev@localhost:3000/galaxy/galaxy.git
git push local-gitea HEAD

The Tier 1 workflow fires on push to any branch and the Tier 2 workflow fires on tags matching v*. Watch runs at:

http://localhost:3000/galaxy/galaxy/actions

Operational targets

Target What it does
make up Bring up Gitea + runner (idempotent)
make down Stop both containers (state preserved)
make logs Tail logs from both containers
make status Show container status
make push Push current HEAD to local Gitea
make clean Stop and wipe all local state (full reset)

What's in the box

Component Image Role
Gitea gitea/gitea:1.23 Server with SQLite backend
act_runner gitea/act_runner:0.6.1 Single-capacity runner registered on boot
Workflow catthehacker/ubuntu:act-latest Image spawned per job (multi-arch)

The runner mounts the host Docker socket and spawns workflow containers on the same Docker network as Gitea, so actions/checkout reaches the server at http://gitea:3000 from inside spawned containers.

Caveats

  • Gitea's ROOT_URL is set to http://gitea:3000/ so spawned workflow containers reach the server through the compose network. The web UI works at http://localhost:3000 via port mapping, but copy-paste URLs in the UI may show gitea:3000 instead of localhost:3000. Harmless for local dev; switch the host part by hand when copying.
  • The runner is single-capacity (runner.capacity: 1 in config.yaml). Concurrent jobs queue. Bump if you need parallel jobs.
  • First push from a fresh checkout uploads the full repo history (~tens of MB). Subsequent pushes are deltas.
  • actions/upload-artifact@v4 requires Gitea ≥ 1.21 — we pin 1.23 to stay above the cutoff.
  • Workflow steps run as root inside the spawned container; this matches the upstream catthehacker behaviour. Keep that in mind if you add steps that touch host-mounted directories.
  • On Apple Silicon the runner image and its catthehacker child run natively as arm64. Some pre-built tools that ship in the image are amd64-only and would fall back to QEMU; setup-go, setup-node, and pnpm/action-setup all download arm64 binaries themselves, so the workflow steps we care about stay native.