docs(spec): Plan 4d CI workflow design
This commit is contained in:
99
docs/superpowers/specs/2026-04-14-ci-workflow-design.md
Normal file
99
docs/superpowers/specs/2026-04-14-ci-workflow-design.md
Normal 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.
|
||||||
Reference in New Issue
Block a user