feat: extract coverage-gate action from Cue for reuse across projects
- Move coveragegate tool from cue/tools to vociferate/coverage-gate - Create composite action with JSON metrics output for CI - Update tool to export passes/total_coverage/packages_checked/packages_failed - Support per-package threshold policy via JSON configuration - Change module path to git.hrafn.xyz/aether/vociferate/coverage-gate
This commit is contained in:
91
coverage-gate/action.yml
Normal file
91
coverage-gate/action.yml
Normal file
@@ -0,0 +1,91 @@
|
||||
name: vociferate/coverage-gate
|
||||
description: >
|
||||
Enforce per-package code coverage thresholds against Go coverage profiles.
|
||||
Supports JSON policy files with per-package overrides and global minimums.
|
||||
|
||||
inputs:
|
||||
profile:
|
||||
description: Path to Go coverage profile file (output from `go test -coverprofile=...`).
|
||||
required: false
|
||||
default: coverage.out
|
||||
policy:
|
||||
description: Path to JSON file defining coverage thresholds and per-package overrides.
|
||||
required: false
|
||||
default: docs/coverage-thresholds.json
|
||||
src-root:
|
||||
description: Source root directory for package discovery (passed to `go list ./...`).
|
||||
required: false
|
||||
default: .
|
||||
summary-file:
|
||||
description: Optional file path to append markdown summary of coverage results.
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
outputs:
|
||||
passed:
|
||||
description: 'Boolean: true if all packages meet threshold, false if any failed.'
|
||||
value: ${{ steps.gate.outputs.passed }}
|
||||
total-coverage:
|
||||
description: Repository-wide statement coverage percentage.
|
||||
value: ${{ steps.gate.outputs.total_coverage }}
|
||||
packages-checked:
|
||||
description: Number of packages evaluated against policy.
|
||||
value: ${{ steps.gate.outputs.packages_checked }}
|
||||
packages-failed:
|
||||
description: Number of packages below threshold.
|
||||
value: ${{ steps.gate.outputs.packages_failed }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- id: gate
|
||||
shell: bash
|
||||
working-directory: ${{ github.action_path }}
|
||||
env:
|
||||
PROFILE: ${{ inputs.profile }}
|
||||
POLICY: ${{ inputs.policy }}
|
||||
SRC_ROOT: ${{ inputs.src-root }}
|
||||
SUMMARY_FILE: ${{ inputs.summary-file }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Run coverage gate and capture output
|
||||
EXIT_CODE=0
|
||||
OUTPUT=$(go run . \
|
||||
--profile "$PROFILE" \
|
||||
--policy "$POLICY" \
|
||||
--src-root "$SRC_ROOT" \
|
||||
) || EXIT_CODE=$?
|
||||
|
||||
echo "$OUTPUT"
|
||||
|
||||
# Parse summary from output (tool prints JSON stats on last line)
|
||||
SUMMARY_LINE=$(echo "$OUTPUT" | tail -1)
|
||||
|
||||
# Determine pass/fail
|
||||
if [[ $EXIT_CODE -eq 0 ]]; then
|
||||
echo "passed=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "passed=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# Extract metrics (tool outputs: packages_checked, packages_failed, total_coverage on summary line)
|
||||
if echo "$SUMMARY_LINE" | jq . &>/dev/null; then
|
||||
echo "total_coverage=$(echo "$SUMMARY_LINE" | jq -r '.total_coverage')" >> "$GITHUB_OUTPUT"
|
||||
echo "packages_checked=$(echo "$SUMMARY_LINE" | jq -r '.packages_checked')" >> "$GITHUB_OUTPUT"
|
||||
echo "packages_failed=$(echo "$SUMMARY_LINE" | jq -r '.packages_failed')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Append to summary file if provided
|
||||
if [[ -n "$SUMMARY_FILE" ]]; then
|
||||
{
|
||||
echo "## Coverage Gate Results"
|
||||
echo
|
||||
echo "- **Passed:** $([ "$EXIT_CODE" -eq 0 ] && echo '✓ Yes' || echo '✗ No')"
|
||||
echo "- **Total Coverage:** $(echo "$SUMMARY_LINE" | jq -r '.total_coverage')%"
|
||||
echo "- **Packages Checked:** $(echo "$SUMMARY_LINE" | jq -r '.packages_checked')"
|
||||
echo "- **Packages Failed:** $(echo "$SUMMARY_LINE" | jq -r '.packages_failed')"
|
||||
} >> "$SUMMARY_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit $EXIT_CODE
|
||||
Reference in New Issue
Block a user