diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f37a51b..0940a71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,30 @@ jobs: - name: Run tests run: go test -race -cover ./... + coverage: + name: Coverage + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Check out repository + uses: actions/checkout@v7 + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: 1.26.x + cache: true + - name: Generate coverage + run: go test -race -coverprofile=coverage.out -covermode=atomic ./... + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + use_oidc: true + files: ./coverage.out + disable_search: true + fail_ci_if_error: true + lint: name: Lint runs-on: ubuntu-latest diff --git a/README.md b/README.md index 4fafd47..c213187 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Stacktrace [![CI](https://github.com/NdoleStudio/stacktrace/actions/workflows/ci.yml/badge.svg)](https://github.com/NdoleStudio/stacktrace/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/NdoleStudio/stacktrace/graph/badge.svg)](https://codecov.io/gh/NdoleStudio/stacktrace) [![Go Reference](https://pkg.go.dev/badge/github.com/NdoleStudio/stacktrace.svg)](https://pkg.go.dev/github.com/NdoleStudio/stacktrace) [![License](https://img.shields.io/github/license/NdoleStudio/stacktrace)](LICENSE) diff --git a/docs/superpowers/plans/2026-07-19-codecov.md b/docs/superpowers/plans/2026-07-19-codecov.md new file mode 100644 index 0000000..48c0ded --- /dev/null +++ b/docs/superpowers/plans/2026-07-19-codecov.md @@ -0,0 +1,171 @@ +# Codecov Integration Implementation Plan + +> **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:** Upload one authoritative Go coverage report to Codecov and display its status in the README. + +**Architecture:** Add a dedicated Ubuntu/Go 1.26 coverage job without changing the compatibility matrix or lint job. Generate one atomic race-enabled profile, upload it through OIDC, and link the repository's Codecov badge from the README. + +**Tech Stack:** Go 1.18+, GitHub Actions, `codecov/codecov-action@v5`, GitHub OIDC + +## Global Constraints + +- Keep the existing test matrix and lint job unchanged. +- Run the coverage job on `ubuntu-latest` with Go `1.26.x`. +- Grant `contents: read` and `id-token: write` only to the coverage job. +- Generate `coverage.out` with `go test -race -coverprofile=coverage.out -covermode=atomic ./...`. +- Upload only `./coverage.out` through OIDC and fail CI when the upload fails. +- Add no repository secret or Go dependency. +- Keep README badge links scoped to `NdoleStudio/stacktrace`. + +--- + +### Task 1: Add Codecov coverage reporting + +**Files:** +- Modify: `.github/workflows/ci.yml` +- Modify: `README.md` + +**Interfaces:** +- Consumes: GitHub OIDC identity and Go's `coverage.out` profile. +- Produces: One Codecov coverage upload per workflow run and a repository coverage badge. + +- [ ] **Step 1: Verify Codecov is not configured** + +Run: + +```bash +rg -n "codecov|coverage.out|coverprofile" .github/workflows/ci.yml README.md +``` + +Expected: no output. + +- [ ] **Step 2: Add the dedicated coverage job** + +Insert this job between `test` and `lint`: + +```yaml + coverage: + name: Coverage + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Check out repository + uses: actions/checkout@v7 + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: 1.26.x + cache: true + - name: Generate coverage + run: go test -race -coverprofile=coverage.out -covermode=atomic ./... + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + use_oidc: true + files: ./coverage.out + disable_search: true + fail_ci_if_error: true +``` + +- [ ] **Step 3: Add the README badge** + +Immediately after the CI badge, add: + +```markdown +[![codecov](https://codecov.io/gh/NdoleStudio/stacktrace/graph/badge.svg)](https://codecov.io/gh/NdoleStudio/stacktrace) +``` + +- [ ] **Step 4: Verify the focused changes** + +Run: + +```bash +rg -n "codecov|coverage.out|coverprofile|id-token" .github/workflows/ci.yml README.md +git diff --check +git diff -- .github/workflows/ci.yml README.md +``` + +Expected: one coverage job, one upload step, one badge, no whitespace errors, +and no changes to the existing test matrix or lint job. + +- [ ] **Step 5: Commit the integration** + +```bash +git add .github/workflows/ci.yml README.md +git commit -m "ci: upload coverage to Codecov" +``` + +--- + +### Task 2: Validate the branch + +**Files:** +- Review: `.github/workflows/ci.yml` +- Review: `README.md` + +**Interfaces:** +- Consumes: The complete Codecov integration diff. +- Produces: A clean branch ready to push. + +- [ ] **Step 1: Generate the coverage profile locally** + +Run: + +```bash +go test -coverprofile=coverage.out -covermode=atomic ./... +``` + +Expected: both packages pass and `coverage.out` is created. The local +Windows/ARM64 host omits `-race` because that platform does not support it; +the Ubuntu CI coverage job runs the exact race-enabled command. + +- [ ] **Step 2: Remove the generated profile** + +Run: + +```bash +Remove-Item -LiteralPath coverage.out +git status --short +``` + +Expected: `coverage.out` is removed and no untracked coverage artifact remains. + +- [ ] **Step 3: Run repository checks** + +Run: + +```bash +go test ./... +go vet ./... +golangci-lint fmt --diff +golangci-lint run +pre-commit run --all-files +``` + +Expected: every command passes. + +- [ ] **Step 4: Review the branch diff** + +Run: + +```bash +git diff --check origin/main...HEAD +git status --short +git diff --stat origin/main...HEAD +``` + +Expected: no whitespace errors, a clean worktree, and only the design, plan, +workflow, and README files in the branch. + +- [ ] **Step 5: Push the branch** + +Run: + +```bash +git push -u origin copilot/add-codecov +``` + +Expected: the branch is published successfully. diff --git a/docs/superpowers/specs/2026-07-19-codecov-design.md b/docs/superpowers/specs/2026-07-19-codecov-design.md new file mode 100644 index 0000000..f980a8f --- /dev/null +++ b/docs/superpowers/specs/2026-07-19-codecov-design.md @@ -0,0 +1,65 @@ +# Codecov Integration Design + +## Goal + +Publish repository coverage to Codecov from GitHub Actions and display the +current coverage status in `README.md`. + +## CI Design + +Add one dedicated `coverage` job to `.github/workflows/ci.yml`. The job runs on +Ubuntu with Go 1.26.x, independently of the existing nine-combination +compatibility matrix. This avoids duplicate uploads while keeping the existing +test job unchanged. + +Grant only this job: + +```yaml +permissions: + contents: read + id-token: write +``` + +Generate an atomic race-enabled Go coverage profile: + +```bash +go test -race -coverprofile=coverage.out -covermode=atomic ./... +``` + +Upload only `coverage.out` with `codecov/codecov-action@v5`. Use GitHub OIDC +authentication instead of a repository secret, disable automatic report +search, and fail the job if the upload fails: + +```yaml +with: + use_oidc: true + files: ./coverage.out + disable_search: true + fail_ci_if_error: true +``` + +The repository must be enabled in Codecov for OIDC uploads and badge data. + +## README Design + +Add the Codecov badge immediately after the CI badge: + +```markdown +[![codecov](https://codecov.io/gh/NdoleStudio/stacktrace/graph/badge.svg)](https://codecov.io/gh/NdoleStudio/stacktrace) +``` + +## File Impact + +Modify: + +- `.github/workflows/ci.yml` +- `README.md` + +## Acceptance Checks + +1. The existing compatibility test matrix and lint job remain unchanged. +2. The coverage job has the minimum permissions needed for checkout and OIDC. +3. The coverage profile is explicit, atomic, race-enabled, and uploaded once. +4. Codecov upload failures fail CI. +5. The README badge targets `NdoleStudio/stacktrace`. +6. Existing Go tests, vet, lint, formatting, and pre-commit checks pass.