# CI workflow — runs on every PR into main. # # Notes for anyone editing this file: # # Custom runner image # Every job runs inside `gitea.dcglab.co.uk/steve/ci-runner-go` # (recipe: https://gitea.dcglab.co.uk/steve/ci/src/branch/main/images/ci-runner-go). # That image already ships: # * Go on PATH at /usr/local/go/bin (so `actions/setup-go` is # redundant and intentionally NOT used here — the action would # otherwise re-download Go on every job) # * Node.js + npm (used by docs / e2e workflows) # * Docker CLI, Buildx, Compose v2 (used by docker-build steps) # When bumping the Go floor, push a new ci-runner-go image with # the matching Go version and bump the date pin in IMAGE below. # # Self-hosted runner expectations # Each runner host bind-mounts persistent volumes for # /root/go/pkg/mod (GOMODCACHE), /root/.cache/go-build (GOCACHE), # and /root/.cache/act (action clones) into every job container — # regardless of which image the container is built from. As a # result: # * Common GitHub actions (actions/checkout, actions/upload-artifact, # golangci/golangci-lint-action) are pre-cloned into # /root/.cache/act on the runner, so the per-job # "git clone https://github.com/actions/..." step is a fetch, # not a full clone. # * golangci-lint is pre-installed at /usr/local/bin/golangci-lint # on the runner host BUT that's outside the job's filesystem # view; the golangci-lint-action below pins a specific version # and re-downloads — that's fine (deterministic CI > marginal # speed). # # Build matrix # Linux amd64 + arm64 + Windows amd64. CGO_ENABLED=0 throughout — # modernc.org/sqlite is pure-Go so no cross-compile toolchain is # needed. -trimpath + -ldflags="-s -w" for reproducible, smaller # binaries. # # Go version # Anchored by the ci-runner-go image (currently Go 1.25.7). Floor # is set by the heaviest dep (modernc.org/sqlite v1.50+ requires # Go 1.23+; we run 1.25 so golangci-lint's Go-version compatibility # check is happy — see the version pin in the lint job). # # upload-artifact # Pinned at v3 historically; v3 was deprecated upstream. v4 should # work but hasn't been validated against this runner's act_runner # version yet. Bump when convenient. name: CI on: pull_request: branches: [main] # Force bash as the default shell. With `container:` set on every # job, Gitea Actions otherwise picks `sh -e` and our `set -euo # pipefail` fails on dash with "Illegal option -o pipefail". defaults: run: shell: bash jobs: test: # Sharded by package group. server/http and store are the two # heavy packages (~156s and ~75s in CI respectively under # `-race`); pulling them onto their own runners lets each shard # have all CPUs to itself instead of CPU-starving each other on # one runner. The third shard ("rest") covers everything else. name: Test (${{ matrix.name }}) runs-on: ubuntu-latest container: gitea.dcglab.co.uk/steve/ci-runner-go:2026-05-08 strategy: fail-fast: false matrix: include: - name: server-http packages: ./internal/server/http/... - name: store packages: ./internal/store/... - name: rest # Computed at runtime — see the "go test" step below. packages: "" steps: - uses: actions/checkout@v4 - name: go vet run: go vet ./... - name: go test run: | set -euo pipefail if [ -n "${{ matrix.packages }}" ]; then pkgs="${{ matrix.packages }}" else # "rest" shard: everything except the dedicated shards. pkgs=$(go list ./... \ | grep -v '/internal/server/http$' \ | grep -v '/internal/store$') fi # shellcheck disable=SC2086 go test -race -coverprofile=coverage.out $pkgs - name: coverage summary run: go tool cover -func=coverage.out | tail -1 lint: name: Lint runs-on: ubuntu-latest container: gitea.dcglab.co.uk/steve/ci-runner-go:2026-05-08 steps: - uses: actions/checkout@v4 - uses: golangci/golangci-lint-action@v7 with: # Must be built against the same Go release as go.mod targets, # otherwise the linter refuses to load with "Go language # version used to build golangci-lint is lower than the # targeted Go version". v2.5.0 is the first v2.x line built # with Go 1.25; bump in lockstep with go.mod. version: v2.5.0 args: --timeout=5m build: name: Build (${{ matrix.goos }}/${{ matrix.goarch }}) runs-on: ubuntu-latest container: gitea.dcglab.co.uk/steve/ci-runner-go:2026-05-08 strategy: fail-fast: false matrix: include: - goos: linux goarch: amd64 - goos: linux goarch: arm64 - goos: windows goarch: amd64 ext: ".exe" steps: - uses: actions/checkout@v4 - name: build server + agent env: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} CGO_ENABLED: "0" run: | mkdir -p bin go build -trimpath -ldflags="-s -w" \ -o bin/restic-manager-server-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }} \ ./cmd/server go build -trimpath -ldflags="-s -w" \ -o bin/restic-manager-agent-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }} \ ./cmd/agent - uses: actions/upload-artifact@v3 with: name: binaries-${{ matrix.goos }}-${{ matrix.goarch }} path: bin/* retention-days: 7