docs(spec): Plan 4d CI workflow design

This commit is contained in:
MDietermann
2026-04-14 21:28:44 +02:00
parent 9d08c635ce
commit b30471bacb

View File

@@ -0,0 +1,99 @@
# 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
```yaml
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.