Files
Archduino/docs/superpowers/specs/2026-04-14-ci-workflow-design.md
2026-04-14 21:28:44 +02:00

4.7 KiB
Raw Blame History

CI Workflow Design (Plan 4d)

Date: 2026-04-14 Scope: Plan 4d of the Archduino Go rewrite — validate Go code quality, build health, and release config on every change.

Goal

A single Gitea Actions workflow that gives fast, reliable feedback on every push and pull request. It runs unit tests with the race detector, static checks, a build sanity pass, shell-script linting, and validates the goreleaser config — all inside an Arch Linux container for environmental fidelity with the target platform.

Non-goals

  • No integration tests that invoke a real archduino install against live pacman/AUR mirrors. That requires a privileged container and mirror access; it lives in a future plan if ever needed.
  • No golangci-lint. The go vet + gofmt baseline is enough for this codebase; revisit only if linting gaps surface.
  • No coverage reporting or codecov upload.
  • No scheduled/nightly runs. Trigger is push + PR only.

Trigger

on:
  push:
  pull_request:

Fires on every push to every branch and every pull request. Matches a single-developer workflow where noisy branches aren't a real concern; immediate feedback is worth the runner minutes.

Runner

  • runs-on: ubuntu-latest — same runner label used by the Plan 4c release workflow.
  • container: archlinux:latest — tests execute inside a fresh Arch userspace each run, matching Archduino's sole supported OS.

Runner infrastructure: depends on the same Gitea Actions runner registered for Plan 4c. No new infra introduced by this plan. If the runner is offline, CI queues rather than failing; this is acceptable behavior.

Job steps (single job, sequential)

  1. Install container prereqs. Before actions/checkout can run, the Arch image needs git; the later steps also need base-devel (for the C toolchain Go occasionally pulls in for cgo-adjacent deps) and shellcheck. Run once up front:

    pacman -Sy --needed --noconfirm base-devel git shellcheck
    

    Note: go is intentionally NOT installed here — actions/setup-go installs the pinned version.

  2. Checkout code. actions/checkout@v4 with fetch-depth: 1 (CI doesn't need history).

  3. Set up Go. actions/setup-go@v5 with:

    • go-version-file: go.mod (pinned, deterministic)
    • cache: true (built-in cache of $GOMODCACHE + $GOCACHE, keyed on go.sum)
  4. go vet ./... — catches obvious correctness issues the compiler misses.

  5. gofmt check:

    diff=$(gofmt -l .)
    if [ -n "$diff" ]; then
      echo "files need gofmt:"; echo "$diff"; exit 1
    fi
    

    Fails the build if any Go file isn't canonically formatted.

  6. go build ./... — compiles every package. Catches deadcode paths and untested packages that go test would otherwise skip.

  7. go test -race ./... — full unit test suite with the race detector. The engine (DAG scheduler) and privilege.Acquire (sudo keepalive goroutine) are the concurrency hotspots this covers.

  8. shellcheck bootstrap.sh — lints the user-facing shell installer. install.sh.legacy is NOT linted; it's archived code.

  9. Install goreleaser + goreleaser check:

    go install github.com/goreleaser/goreleaser/v2@latest
    "$(go env GOPATH)/bin/goreleaser" check
    

    Validates .goreleaser.yaml on every change. Cheap insurance against config drift.

Runtime expectations

  • Arch image pull: ~15–30s (cached on the runner after first run).
  • pacman -Sy … base-devel git shellcheck: ~10–20s.
  • actions/setup-go + cache restore: ~5–10s warm, ~30s cold.
  • go build ./... + go test -race ./...: ~30–60s given 37 test files with mostly mocked I/O.
  • go vet, gofmt, shellcheck, goreleaser check: <5s combined.
  • Total per run: ~1–2 min warm cache, ~3 min cold.

Error handling

  • Sequential steps; the first failure fails the workflow. No continue-on-error anywhere.
  • gofmt check uses an explicit guard (not just -l) so a non-empty output is a clear failure.
  • setup-go cache misses silently fall back to a clean install — no workflow-breaking behavior.

Caching

actions/setup-go@v5 handles Go build/module caching natively via cache: true. No extra cache step. The pacman packages are re-installed every run; caching them is not worth the complexity for ~15s of savings on a 90s run.

Files touched

  • Create: .gitea/workflows/ci.yml

No other repo changes; the existing tests, go.mod, .goreleaser.yaml, and bootstrap.sh all stay as-is.

Interaction with Plan 4c

The release workflow (.gitea/workflows/release.yml) is unchanged. Both workflows share the Gitea Actions runner but never run together: CI fires on push/PR, release fires on tag push. Independent files, independent triggers, zero coupling.