Skip to content

Commit 77c1b85

Browse files
aRustyDevclaude
andcommitted
feat: Add comprehensive testing, coverage, and documentation
- Add more test files for nix, web, and CI hooks - Create code coverage workflow with kcov integration - Add comprehensive hook development guide - Document release automation workflow plans Test Coverage: - Set up coverage reporting with artifacts - Add coverage badges and PR comments - Configure 80% coverage target Documentation: - HOOK_DEVELOPMENT.md: Complete guide for contributors - RELEASE_AUTOMATION.md: Detailed release process plans This completes the next steps for CI/CD maturity improvement. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0d295e7 commit 77c1b85

6 files changed

Lines changed: 979 additions & 0 deletions

File tree

.github/workflows/coverage.yml

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
name: Code Coverage
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
checks: write
12+
pull-requests: write
13+
14+
jobs:
15+
coverage:
16+
name: Test Coverage
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Install dependencies
23+
run: |
24+
sudo apt-get update
25+
sudo apt-get install -y bats kcov
26+
27+
# Install bashcov for additional coverage
28+
sudo gem install bashcov
29+
30+
- name: Create coverage directory
31+
run: mkdir -p coverage
32+
33+
- name: Run tests with kcov
34+
run: |
35+
# Run each test file with kcov
36+
for test_file in tests/**/*.bats; do
37+
if [[ -f "$test_file" ]]; then
38+
test_name=$(basename "$test_file" .bats)
39+
echo "Running coverage for: $test_name"
40+
41+
# Skip if no hook files exist yet
42+
if ! ls hooks/**/*.sh >/dev/null 2>&1; then
43+
echo "No hook files found, skipping coverage"
44+
continue
45+
fi
46+
47+
kcov --exclude-pattern=/usr,/tmp coverage/$test_name \
48+
bats "$test_file" || true
49+
fi
50+
done
51+
52+
- name: Merge coverage reports
53+
run: |
54+
if ls coverage/*/cobertura.xml >/dev/null 2>&1; then
55+
kcov --merge coverage/merged coverage/*
56+
else
57+
echo "No coverage reports found"
58+
mkdir -p coverage/merged
59+
echo '<?xml version="1.0"?><coverage version="1"><packages/></coverage>' > coverage/merged/cobertura.xml
60+
fi
61+
62+
- name: Generate coverage report
63+
run: |
64+
if [[ -f coverage/merged/index.html ]]; then
65+
echo "## Coverage Report Summary" >> $GITHUB_STEP_SUMMARY
66+
echo "" >> $GITHUB_STEP_SUMMARY
67+
68+
# Extract coverage percentage
69+
coverage_percent=$(grep -oP 'Overall coverage rate:.*?(\d+\.\d+)%' coverage/merged/index.html | grep -oP '\d+\.\d+' || echo "0.0")
70+
echo "**Overall Coverage**: ${coverage_percent}%" >> $GITHUB_STEP_SUMMARY
71+
echo "" >> $GITHUB_STEP_SUMMARY
72+
73+
# Coverage badge color
74+
if (( $(echo "$coverage_percent >= 80" | bc -l) )); then
75+
badge_color="brightgreen"
76+
elif (( $(echo "$coverage_percent >= 60" | bc -l) )); then
77+
badge_color="yellow"
78+
else
79+
badge_color="red"
80+
fi
81+
82+
echo "![Coverage](https://img.shields.io/badge/coverage-${coverage_percent}%25-${badge_color})" >> $GITHUB_STEP_SUMMARY
83+
fi
84+
85+
- name: Upload coverage reports
86+
uses: actions/upload-artifact@v4
87+
if: always()
88+
with:
89+
name: coverage-report
90+
path: coverage/merged/
91+
92+
- name: Comment PR with coverage
93+
uses: actions/github-script@v7
94+
if: github.event_name == 'pull_request'
95+
with:
96+
script: |
97+
const fs = require('fs');
98+
let coverageText = 'Coverage report not available';
99+
100+
try {
101+
// Read coverage summary if available
102+
const coverageFile = 'coverage/merged/index.html';
103+
if (fs.existsSync(coverageFile)) {
104+
const content = fs.readFileSync(coverageFile, 'utf8');
105+
const match = content.match(/Overall coverage rate:.*?(\d+\.\d+)%/);
106+
if (match) {
107+
const coverage = match[1];
108+
coverageText = `## Test Coverage Report\n\n**Overall Coverage**: ${coverage}%\n\n`;
109+
110+
if (parseFloat(coverage) < 80) {
111+
coverageText += '⚠️ Coverage is below 80% target\n';
112+
} else {
113+
coverageText += '✅ Coverage meets target\n';
114+
}
115+
}
116+
}
117+
} catch (e) {
118+
console.error('Error reading coverage:', e);
119+
}
120+
121+
github.rest.issues.createComment({
122+
issue_number: context.issue.number,
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
body: coverageText
126+
});
127+
128+
- name: Coverage check
129+
run: |
130+
# Fail if coverage is below threshold
131+
if [[ -f coverage/merged/index.html ]]; then
132+
coverage_percent=$(grep -oP 'Overall coverage rate:.*?(\d+\.\d+)%' coverage/merged/index.html | grep -oP '\d+\.\d+' || echo "0")
133+
134+
echo "Current coverage: ${coverage_percent}%"
135+
136+
# For now, just warn if below 80%
137+
if (( $(echo "$coverage_percent < 80" | bc -l) )); then
138+
echo "::warning::Coverage ${coverage_percent}% is below 80% target"
139+
fi
140+
fi

0 commit comments

Comments
 (0)