Files
Archduino/docs/superpowers/plans/2026-04-14-ci-workflow.md
2026-04-14 21:30:01 +02:00

206 lines
6.5 KiB
Markdown

# CI Workflow Implementation Plan (Plan 4d)
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a single Gitea Actions CI workflow that runs `go vet` + `gofmt` check + `go build` + `go test -race` + `shellcheck` + `goreleaser check` inside an `archlinux:latest` container on every push and PR.
**Architecture:** One workflow file (`.gitea/workflows/ci.yml`), one job with sequential steps. The Arch container gives environmental fidelity; `actions/setup-go@v5` pins Go via `go-version-file: go.mod` for reproducibility.
**Tech Stack:** Gitea Actions, archlinux:latest container, Go (version pinned in go.mod), shellcheck, goreleaser v2.
**Spec:** `docs/superpowers/specs/2026-04-14-ci-workflow-design.md`
---
## File Structure
**New files:**
- `.gitea/workflows/ci.yml` — single-job CI workflow
**No other files change.**
---
## Task 1: Pre-flight — verify all CI steps pass locally
Before writing the workflow, run every command it will execute locally to confirm the repo is in a CI-passing state. If any command fails, either the plan's step is wrong or the repo has a latent issue — either way, CI will fail without this check.
**Files:** none (validation only)
- [ ] **Step 1: `go vet ./...`**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
go vet ./...
```
Expected: exit 0, no output.
If warnings appear, STOP and report — fixing them is out of scope for this plan but must happen before CI can land.
- [ ] **Step 2: `gofmt` check**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
diff=$(gofmt -l .)
if [ -n "$diff" ]; then echo "FILES NEEDING FMT:"; echo "$diff"; exit 1; fi
echo "gofmt clean"
```
Expected: `gofmt clean`.
If any files are listed, STOP and report. Fixing formatting is out of scope — do NOT auto-fix in this plan. The user should decide whether to format in a separate commit first.
- [ ] **Step 3: `go build ./...`**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
go build ./...
```
Expected: exit 0, no output.
- [ ] **Step 4: `go test -race ./...`**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
go test -race ./...
```
Expected: all packages report `ok` or `no test files`. Failures = STOP and report. Race detector findings = STOP and report (they indicate real concurrency bugs).
- [ ] **Step 5: `shellcheck bootstrap.sh`**
```bash
command -v shellcheck || { echo "shellcheck not installed; install via: sudo pacman -S shellcheck"; exit 1; }
shellcheck /home/marvin/git-clones/ArduinoArchSetup/bootstrap.sh
```
Expected: exit 0, no output.
If shellcheck isn't installed locally, install it (`sudo pacman -S shellcheck`) and retry. If findings appear, STOP and report — bootstrap.sh was validated by `bash -n` only, so this is the first shellcheck run.
- [ ] **Step 6: `goreleaser check`**
```bash
command -v goreleaser || command -v /home/marvin/go/bin/goreleaser || { echo "goreleaser missing"; exit 1; }
(command -v goreleaser && goreleaser check) || /home/marvin/go/bin/goreleaser check
```
Expected: `• 1 configuration file(s) validated` or equivalent success message.
- [ ] **Step 7: No commit**
This task is informational. If all six steps passed, proceed to Task 2. If any failed, report findings to the controller and HALT — the CI workflow cannot land until the repo is in a passing state.
---
## Task 2: Author `.gitea/workflows/ci.yml`
**Files:**
- Create: `.gitea/workflows/ci.yml`
- [ ] **Step 1: Write the workflow file**
Create `/home/marvin/git-clones/ArduinoArchSetup/.gitea/workflows/ci.yml`:
```yaml
name: ci
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
container:
image: archlinux:latest
steps:
- name: Install container prereqs
run: pacman -Sy --needed --noconfirm base-devel git shellcheck
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: go vet
run: go vet ./...
- name: gofmt check
run: |
diff=$(gofmt -l .)
if [ -n "$diff" ]; then
echo "files need gofmt:"
echo "$diff"
exit 1
fi
- name: go build
run: go build ./...
- name: go test -race
run: go test -race ./...
- name: shellcheck bootstrap.sh
run: shellcheck bootstrap.sh
- name: Install goreleaser
run: go install github.com/goreleaser/goreleaser/v2@latest
- name: goreleaser check
run: $(go env GOPATH)/bin/goreleaser check
```
- [ ] **Step 2: Validate YAML syntax**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
python3 -c "import yaml; yaml.safe_load(open('.gitea/workflows/ci.yml'))" && echo "yaml ok"
```
Expected: `yaml ok`.
- [ ] **Step 3: Sanity-check step ordering against spec**
Open the file and confirm the step order matches the spec's Section "Job steps":
1. Install container prereqs
2. Checkout
3. Setup Go
4. go vet
5. gofmt check
6. go build
7. go test -race
8. shellcheck bootstrap.sh
9. Install goreleaser
10. goreleaser check
No grouping or reordering. This is only a human-verified check (no command).
- [ ] **Step 4: Commit**
```bash
cd /home/marvin/git-clones/ArduinoArchSetup
git add .gitea/workflows/ci.yml
git commit -m "ci: add Gitea Actions workflow for test, vet, fmt, build, shellcheck, goreleaser check"
```
Do NOT add any Co-Authored-By trailer — repo convention forbids it.
---
## Notes for the executing agent
- **One file, one job.** Don't split into multiple jobs or multiple workflows. The spec is explicit.
- **Do not try to run the workflow itself** — that requires a Gitea Actions runner (Plan 4c Task 9, currently deferred). The workflow will queue when pushed until a runner is online; that's fine.
- **If Task 1 reveals failures** in `go vet`, `gofmt`, `go test -race`, or `shellcheck`, stop and escalate. Those are pre-existing issues the controller needs to address in a separate commit/plan; this plan only adds the workflow that detects them.
- **Why `$(go env GOPATH)/bin/goreleaser` explicitly** in step 10: `go install` puts binaries in `GOPATH/bin`, which isn't on `$PATH` inside the stock Arch container. Using the absolute path is simpler than mutating PATH.
- **YAML indentation is significant.** Use 2-space indents matching the example above. Do not substitute tabs.