Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CI Scripts

This directory contains scripts used by GitHub Actions workflows.

## format-coverage.sh

Formats Go coverage output as a markdown table with color-coded indicators.

### Usage

```bash
./format-coverage.sh <coverage-file> [current-coverage] [main-coverage]
```

**Arguments:**
- `coverage-file`: Path to the Go coverage file (typically `coverage.out`)
- `current-coverage`: (optional) Overall coverage percentage for display (e.g., "74.3%")
- `main-coverage`: (optional) Main branch coverage percentage for comparison (e.g., "74.0%")

### Examples

**Basic usage:**
```bash
# Generate coverage file first
mise test-coverage

# Format the coverage report
./.github/scripts/format-coverage.sh coverage.out
```

**With coverage percentages:**
```bash
# Calculate coverage
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}')

# Format with coverage display
./.github/scripts/format-coverage.sh coverage.out "$COVERAGE"
```

**With comparison to main:**
```bash
./.github/scripts/format-coverage.sh coverage.out "75.2%" "74.3%"
```

### Output Format

The script generates a markdown report with:
- Overall coverage statistics
- Coverage comparison (if main branch coverage provided)
- Table of coverage by package with color-coded indicators:
- 🟢 Green: ≥90% coverage
- 🟡 Yellow: ≥75% coverage
- 🟠 Orange: ≥50% coverage
- 🔴 Red: <50% coverage
- Collapsible detailed coverage by function

### Local Testing

To test the output locally:

```bash
# Run tests with coverage
mise test-coverage

# Format and preview the output
./.github/scripts/format-coverage.sh coverage.out "74.3%" "74.3%" | less
```

Or save to a file for inspection:

```bash
./.github/scripts/format-coverage.sh coverage.out "74.3%" > coverage-report.md
120 changes: 120 additions & 0 deletions .github/scripts/format-coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
set -euo pipefail

# Script to format Go coverage output as a markdown table
# Usage: ./format-coverage.sh coverage.out [current-coverage] [main-coverage]

COVERAGE_FILE="${1:-coverage.out}"
CURRENT_COVERAGE="${2:-}"
MAIN_COVERAGE="${3:-}"

if [ ! -f "$COVERAGE_FILE" ]; then
echo "Error: Coverage file '$COVERAGE_FILE' not found"
exit 1
fi

# Start markdown output
echo "## 📊 Test Coverage Report"
echo ""

# Show current and main coverage if provided
if [ -n "$CURRENT_COVERAGE" ]; then
echo "**Current Coverage:** \`$CURRENT_COVERAGE\`"

if [ -n "$MAIN_COVERAGE" ]; then
echo "**Main Branch Coverage:** \`$MAIN_COVERAGE\`"
echo ""

# Calculate difference
CURRENT_NUM=$(echo "$CURRENT_COVERAGE" | sed 's/%//')
MAIN_NUM=$(echo "$MAIN_COVERAGE" | sed 's/%//')

if [ -n "$CURRENT_NUM" ] && [ -n "$MAIN_NUM" ]; then
DIFF=$(echo "$CURRENT_NUM - $MAIN_NUM" | bc -l 2>/dev/null || echo "0")

if [ "$(echo "$DIFF > 0" | bc -l 2>/dev/null || echo "0")" = "1" ]; then
echo "**Coverage Change:** 📈 +${DIFF}% (improved)"
elif [ "$(echo "$DIFF < 0" | bc -l 2>/dev/null || echo "0")" = "1" ]; then
DIFF_ABS=$(echo "$DIFF * -1" | bc -l 2>/dev/null || echo "${DIFF#-}")
echo "**Coverage Change:** 📉 -${DIFF_ABS}% (decreased)"
else
echo "**Coverage Change:** ✅ No change"
fi
fi
fi
fi

echo ""
echo "### Coverage by Package"
echo ""

# Create table header
echo "| Package | Coverage |"
echo "|---------|----------|"

# Parse coverage and group by package
go tool cover -func="$COVERAGE_FILE" | grep -E '\.go:[0-9]+:' | \
awk -F: '{
# Extract package path from filename
split($1, parts, "/");
pkg = "";
for(i=1; i<length(parts); i++) {
if(pkg != "") pkg = pkg "/";
pkg = pkg parts[i];
}

# Extract coverage percentage from the last field
split($0, line, /[[:space:]]+/);
coverage = line[length(line)];

# Store coverage by package
if(pkg in packages) {
packages[pkg] = packages[pkg] "," coverage;
} else {
packages[pkg] = coverage;
}
}
END {
for(pkg in packages) {
# Calculate average coverage for package
split(packages[pkg], covs, ",");
sum = 0;
count = 0;
for(i in covs) {
gsub(/%/, "", covs[i]);
sum += covs[i];
count++;
}
avg = (count > 0) ? sum/count : 0;

# Format package name (remove common prefix)
display_pkg = pkg;
gsub(/github\.com\/speakeasy-api\/openapi\//, "", display_pkg);

# Add emoji indicators based on coverage level
emoji = "🔴";
if(avg >= 90) emoji = "🟢";
else if(avg >= 75) emoji = "🟡";
else if(avg >= 50) emoji = "🟠";

# Output with coverage value for sorting
printf "%.1f|`%s`|%s\n", avg, display_pkg, emoji;
}
}' | sort -n | awk -F'|' '{
# Re-format after sorting by coverage
printf "| %s | %s %.1f%% |\n", $2, $3, $1;
}'

echo ""
echo "<details>"
echo "<summary>📋 Detailed Coverage by Function (click to expand)</summary>"
echo ""
echo "\`\`\`"
go tool cover -func="$COVERAGE_FILE"
echo "\`\`\`"
echo "</details>"
echo ""
echo "- 🧪 All tests passed"
echo "- 📈 Full coverage report available in workflow artifacts"
echo ""
echo "_Generated by GitHub Actions_"
42 changes: 3 additions & 39 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -190,47 +190,11 @@ jobs:
- name: Generate coverage summary
id: coverage-summary
run: |
echo "## 📊 Test Coverage Report" > coverage-summary.md
echo "" >> coverage-summary.md

# Current coverage
# Use the formatting script
CURRENT_COV="${{ steps.coverage.outputs.coverage }}"
echo "**Current Coverage:** \`$CURRENT_COV\`" >> coverage-summary.md

# Compare with main if this is a PR
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ steps.main-coverage.outputs.main-coverage }}" != "" ]; then
MAIN_COV="${{ steps.main-coverage.outputs.main-coverage }}"
echo "**Main Branch Coverage:** \`$MAIN_COV\`" >> coverage-summary.md
echo "" >> coverage-summary.md

# Calculate difference
CURRENT_NUM=$(echo $CURRENT_COV | sed 's/%//')
MAIN_NUM=$(echo $MAIN_COV | sed 's/%//')

if [ "$CURRENT_NUM" != "" ] && [ "$MAIN_NUM" != "" ]; then
DIFF=$(echo "$CURRENT_NUM - $MAIN_NUM" | bc -l 2>/dev/null || echo "0")

if [ "$(echo "$DIFF > 0" | bc -l 2>/dev/null)" = "1" ]; then
echo "**Coverage Change:** 📈 +${DIFF}% (improved)" >> coverage-summary.md
elif [ "$(echo "$DIFF < 0" | bc -l 2>/dev/null)" = "1" ]; then
DIFF_ABS=$(echo "$DIFF * -1" | bc -l 2>/dev/null || echo "${DIFF#-}")
echo "**Coverage Change:** 📉 -${DIFF_ABS}% (decreased)" >> coverage-summary.md
else
echo "**Coverage Change:** ✅ No change" >> coverage-summary.md
fi
fi
fi
MAIN_COV="${{ steps.main-coverage.outputs.main-coverage }}"

echo "" >> coverage-summary.md
echo "### Coverage by Package" >> coverage-summary.md
echo "\`\`\`" >> coverage-summary.md
go tool cover -func=coverage.out >> coverage-summary.md
echo "\`\`\`" >> coverage-summary.md
echo "" >> coverage-summary.md
echo "- 🧪 All tests passed" >> coverage-summary.md
echo "- 📈 Full coverage report available in workflow artifacts" >> coverage-summary.md
echo "" >> coverage-summary.md
echo "_Generated by GitHub Actions_" >> coverage-summary.md
./.github/scripts/format-coverage.sh coverage.out "$CURRENT_COV" "$MAIN_COV" > coverage-summary.md

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ import (
- Use `assert.Equal()` for value comparisons with descriptive messages
- Use `assert.Nil()` and `assert.NotNil()` for pointer checks
- Use `require.*` when the test should stop on failure (e.g., setup operations)
- **Use `require.Error()` for error assertions** - The linter enforces this via testifylint
- **Always include descriptive error messages**

```go
Expand Down
Loading