Skip to content
Merged
51 changes: 51 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Coverage

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: write

jobs:
coverage:
name: Code Coverage
timeout-minutes: 60
runs-on: ${{ github.repository_owner == 'intel' && 'intel-ubuntu-latest' || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Dart
uses: dart-lang/setup-dart@v1

- name: Install dependencies
run: tool/gh_actions/install_dependencies.sh

- name: Install Icarus Verilog
run: tool/gh_actions/install_iverilog.sh

- name: Generate coverage and badge
run: tool/gh_actions/generate_coverage.sh

- name: Commit coverage badge
run: |
BRANCH_NAME="${{ github.ref_name }}"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"

# Fetch and checkout badges branch
git fetch origin badges:badges 2>/dev/null || git checkout --orphan badges
git checkout badges 2>/dev/null || true

# Clean and copy badge
git rm -rf . 2>/dev/null || true
mkdir -p coverage
cp /tmp/coverage-badge.svg "coverage/${BRANCH_NAME}.svg"

git add "coverage/${BRANCH_NAME}.svg"
git diff --staged --quiet || git commit -m "Update coverage badge for ${BRANCH_NAME} [skip ci]"

git push origin badges --force
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ doc/api/

# Other stuff
tmp_test/
coverage/
*.sv
*.vcd
*_fsm.md
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Rapid Open Hardware Development (ROHD) Framework

[![Tests](https://github.com/intel/rohd/actions/workflows/general.yml/badge.svg?event=push)](https://github.com/intel/rohd/actions/workflows/general.yml)
[![Coverage](https://raw.githubusercontent.com/intel/rohd/badges/coverage/main.svg)](https://github.com/intel/rohd/actions/workflows/coverage.yml)
[![API Docs](https://img.shields.io/badge/API%20Docs-generated-success)](https://intel.github.io/rohd/rohd/rohd-library.html)
[![Chat](https://img.shields.io/discord/1001179329411166267?label=Chat)](https://discord.gg/jubxF84yGw)
[![License](https://img.shields.io/badge/License-BSD--3-blue)](https://github.com/intel/rohd/blob/main/LICENSE)
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ dependencies:

dev_dependencies:
benchmark_harness: ^2.2.0
coverage: ^1.10.0
yaml: ^3.1.1
99 changes: 99 additions & 0 deletions tool/gh_actions/generate_coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash

# Copyright (C) 2026 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
# generate_coverage.sh
# Generate code coverage and SVG badge
#
# 2026 January 20
# Author: Maifee Ul Asad<maifeeulasad@gmail.com>

set -euo pipefail

# Remove old coverage data
rm -rf coverage

# Run tests with coverage
dart test --coverage=coverage || true
Comment thread
maifeeulasad marked this conversation as resolved.
Outdated

# Check if coverage was generated
if [ ! -d "coverage" ]; then
echo "Error: Coverage directory not created"
exit 1
fi

# Format to LCOV
dart run coverage:format_coverage \
--lcov \
--in=coverage \
--out=coverage/lcov.info \
--packages=.dart_tool/package_config.json \
--report-on=lib

# Install lcov if needed
if ! command -v lcov &> /dev/null; then
if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then
sudo apt update -y
sudo apt install -y lcov
fi
fi

# Extract coverage percentage
if command -v lcov &> /dev/null; then
SUMMARY=$(lcov --summary coverage/lcov.info 2>&1 | grep -E "lines\.*:")
PERCENT=$(echo "$SUMMARY" | grep -oP '\d+\.\d+' | head -1)
echo "Coverage: ${PERCENT}%"
else
PERCENT="0.0"
echo "Coverage: 0.0%"
Comment thread
maifeeulasad marked this conversation as resolved.
Outdated
fi

# Determine color
if (( $(echo "$PERCENT >= 90" | bc -l) )); then
COLOR="#4c1" # bright green
elif (( $(echo "$PERCENT >= 80" | bc -l) )); then
COLOR="#97ca00" # green
elif (( $(echo "$PERCENT >= 70" | bc -l) )); then
COLOR="#dfb317" # yellow
elif (( $(echo "$PERCENT >= 60" | bc -l) )); then
COLOR="#fe7d37" # orange
else
COLOR="#e05d44" # red
fi

# Calculate dimensions
TEXT="${PERCENT}%"
TEXT_LEN=${#TEXT}
TEXT_WIDTH=$((TEXT_LEN * 63))
LABEL_WIDTH=63
VALUE_WIDTH=$((TEXT_WIDTH / 10 + 10))
TOTAL_WIDTH=$((LABEL_WIDTH + VALUE_WIDTH))

# Generate SVG badge
# Style credit goes to shields.io
cat > /tmp/coverage-badge.svg << EOFSVG
Comment thread
mkorbel1 marked this conversation as resolved.
Outdated
<svg xmlns="http://www.w3.org/2000/svg" width="${TOTAL_WIDTH}" height="20" role="img" aria-label="coverage: ${TEXT}">
<title>coverage: ${TEXT}</title>
<linearGradient id="s" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<clipPath id="r">
<rect width="${TOTAL_WIDTH}" height="20" rx="3" fill="#fff"/>
</clipPath>
<g clip-path="url(#r)">
<rect width="${LABEL_WIDTH}" height="20" fill="#555"/>
<rect x="${LABEL_WIDTH}" width="${VALUE_WIDTH}" height="20" fill="${COLOR}"/>
<rect width="${TOTAL_WIDTH}" height="20" fill="url(#s)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
<text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">coverage</text>
<text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">coverage</text>
<text aria-hidden="true" x="$((LABEL_WIDTH * 10 + VALUE_WIDTH * 5))" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${TEXT_WIDTH}">${TEXT}</text>
<text x="$((LABEL_WIDTH * 10 + VALUE_WIDTH * 5))" y="140" transform="scale(.1)" fill="#fff" textLength="${TEXT_WIDTH}">${TEXT}</text>
</g>
</svg>
EOFSVG

echo "Generated SVG badge at /tmp/coverage-badge.svg"