Files
gastown/.github/workflows/ci.yml
Mike Lady f9e788ccfb feat(ci): Add code coverage reporting to GitHub Actions (#246)
* bd sync: 2026-01-05 06:22:43

* bd sync: 2026-01-05 07:08:42

* bd sync: 2026-01-05 07:24:58

* feat: Add code coverage PR comment to GitHub Actions

Adds a step to the CI workflow that:
- Collects code coverage during test runs
- Parses per-package coverage percentages
- Posts a markdown table comment on PRs with:
  - Overall coverage percentage
  - Per-package breakdown table
- Updates existing comment on subsequent pushes

Closes: ga-tl5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): handle fork PR permissions for coverage comment

Fork PRs cannot write comments via GITHUB_TOKEN due to security
restrictions. Add condition to skip comment step for external PRs
and upload coverage report as artifact instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(ci): separate coverage into dedicated job

- Test job now uploads coverage.out and test-output.txt as artifacts
- New Coverage Report job runs after tests complete
- Downloads coverage data, generates report, uploads as artifact
- Always uploads coverage-report artifact (for both fork and internal PRs)
- Comments on PR only for internal PRs (fork PRs get notice message)
- Cleaner separation of concerns

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): coverage job waits for both test and integration

Coverage Report job now depends on [test, integration] to ensure
it only runs after all test stages complete successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): restore Coverage Report job after Test and Integration

Coverage Report job now properly:
- Depends on [test, integration] - waits for both to complete
- Downloads coverage data from Test job
- Generates and uploads coverage-report artifact
- Comments on internal PRs only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add debugging output to TestInstallTownRoleSlots

Add logging for gt install output and bd list to help diagnose
CI failures where agent beads may not be created.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): update beads to @main and fix lint errors

- Change CI to install beads from @main instead of @latest
  (latest release doesn't support role/agent issue types)
- Remove error return from cleanBeadsRuntimeFiles since all
  errors are intentionally ignored (best-effort cleanup)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): pin beads to v0.44.0 for agent/role types

Beads main recently extracted Gas Town-specific types (agent, role, etc.)
from core. Pin CI to v0.44.0 which still has these types.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ci): unpin beads version back to @latest

Beads v0.46.0 now supports agent/role types again.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: remove stale gastown/.beads files from PR

These beads files are local runtime state that shouldn't be committed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 20:45:58 -08:00

248 lines
7.4 KiB
YAML

name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
# Fast check to catch accidental .beads/issues.jsonl changes from contributors
check-no-beads-changes:
name: Check for .beads changes
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check for .beads/issues.jsonl changes
run: |
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^\.beads/issues\.jsonl$"; then
echo "This PR includes changes to .beads/issues.jsonl"
echo ""
echo "This file is the project's issue database and should not be modified in PRs."
echo ""
echo "To fix, run:"
echo " git checkout origin/main -- .beads/issues.jsonl"
echo " git commit --amend"
echo " git push --force"
echo ""
exit 1
fi
echo "No .beads/issues.jsonl changes detected"
# Verify committed formulas allow build without go:generate
# This catches issues where go install @latest would fail
check-embedded-formulas:
name: Check embedded formulas
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Build without go:generate
run: |
# This must succeed with committed formulas only
# If this fails, run: go generate ./... && git add -A && git commit
go build -v ./cmd/gt
- name: Verify formulas are in sync
run: |
# Regenerate and check for differences
go generate ./internal/formula/...
if ! git diff --exit-code internal/formula/formulas/; then
echo ""
echo "ERROR: Committed formulas are out of sync with .beads/formulas/"
echo "Run: go generate ./... && git add -A && git commit"
exit 1
fi
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Configure Git
run: |
git config --global user.name "CI Bot"
git config --global user.email "ci@gastown.test"
- name: Build
run: go build -v ./cmd/gt
- name: Test with Coverage
run: |
go test -race -short -coverprofile=coverage.out ./... 2>&1 | tee test-output.txt
- name: Upload Coverage Data
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: coverage-data
path: |
coverage.out
test-output.txt
# Separate job to process coverage after ALL tests complete
coverage:
name: Coverage Report
runs-on: ubuntu-latest
needs: [test, integration]
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Download Coverage Data
uses: actions/download-artifact@v4
with:
name: coverage-data
- name: Generate Coverage Report
run: |
# Parse per-package coverage from test output
echo "## Code Coverage Report" > coverage-report.md
echo "" >> coverage-report.md
# Get overall coverage
TOTAL=$(go tool cover -func=coverage.out | grep total | awk '{print $3}')
echo "**Overall Coverage: ${TOTAL}**" >> coverage-report.md
echo "" >> coverage-report.md
# Create per-package table
echo "| Package | Coverage |" >> coverage-report.md
echo "|---------|----------|" >> coverage-report.md
# Extract package coverage from all test output lines
grep -E "github.com/steveyegge/gastown.*coverage:" test-output.txt | \
sed 's/.*github.com\/steveyegge\/gastown\///' | \
awk '{
pkg = $1
for (i=2; i<=NF; i++) {
if ($i == "coverage:") {
cov = $(i+1)
break
}
}
printf "| %s | %s |\n", pkg, cov
}' | sort -u >> coverage-report.md
echo "" >> coverage-report.md
echo "---" >> coverage-report.md
echo "_Generated by CI_" >> coverage-report.md
# Show in logs
cat coverage-report.md
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage-report.md
retention-days: 30
- name: Comment Coverage on PR
# Only for internal PRs - fork PRs can't write comments
if: github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('coverage-report.md', 'utf8');
// Find existing coverage comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('## Code Coverage Report')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: report
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: report
});
}
- name: Coverage Note for Fork PRs
if: github.event.pull_request.head.repo.full_name != github.repository
run: |
echo "::notice::Coverage report uploaded as artifact (fork PRs cannot post comments). Download from Actions tab."
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: latest
args: --timeout=5m
integration:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Configure Git
run: |
git config --global user.name "CI Bot"
git config --global user.email "ci@gastown.test"
- name: Install beads (bd)
run: go install github.com/steveyegge/beads/cmd/bd@latest
- name: Build gt
run: go build -v -o gt ./cmd/gt
- name: Add to PATH
run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Integration Tests
run: go test -tags=integration -timeout=5m -v ./internal/cmd/...