diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 000000000..9a2362674 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -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/generate_coverage.sh --generate-svg + + - 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 diff --git a/.gitignore b/.gitignore index 98212bce0..ebf4519e8 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ doc/api/ # Other stuff tmp_test/ +coverage/ *.sv *.vcd *_fsm.md diff --git a/pubspec.yaml b/pubspec.yaml index f9672b2c4..a0f3395ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,4 +17,5 @@ dependencies: dev_dependencies: benchmark_harness: ^2.2.0 + coverage: ^1.10.0 yaml: ^3.1.1 diff --git a/tool/generate_coverage.sh b/tool/generate_coverage.sh index d217179cb..0ab202ff3 100755 --- a/tool/generate_coverage.sh +++ b/tool/generate_coverage.sh @@ -1,13 +1,15 @@ #!/bin/bash -# Copyright (C) 2022-2023 Intel Corporation +# Copyright (C) 2022-2026 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause # # generate_coverage.sh # Determines code coverage by tests and generates an HTML representation. +# and SVG badge with additional arguments for CI integration. # # 2022 May 5 # Author: Max Korbel +# Author: Maifee Ul Asad ### WARNING ### # The "x" option outputs all script commands. This allows you to track @@ -16,15 +18,115 @@ set -euxo pipefail #=============# -declare -r coverage_dir='build/coverage' -declare -r html_dir="${coverage_dir}/genhtml" +# Parse arguments +GENERATE_SVG=false +for arg in "$@"; do + case $arg in + --generate-svg) + GENERATE_SVG=true + shift + ;; + *) + ;; + esac +done -# requires enabling "coverage": -# > dart pub global activate coverage -dart pub global run coverage:test_with_coverage --branch-coverage --out=${coverage_dir} +# Remove old coverage data +rm -rf coverage -# requires installing "lcov": -# > sudo apt install lcov -genhtml --output-directory=${html_dir} --rc lcov_branch_coverage=1 ${coverage_dir}/lcov.info +# Run tests with coverage +dart test --coverage=coverage || true -printf '\n%s\n\n' "Open ${html_dir}/index.html to review code coverage results." +# 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 + +# Generate HTML report +genhtml -o coverage/html coverage/lcov.info --branch-coverage +printf '\n%s\n\n' "Open coverage/html/index.html to review code coverage results." + +# 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="Generation Failed" + echo "Coverage generation failed" +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 +if [ "$PERCENT" = "Generation Failed" ]; then + COLOR="#e05d44" # red +fi + +# Calculate dimensions +if [ "$PERCENT" = "Generation Failed" ]; then + TEXT="Error: coverage collection failed!" +else + TEXT="${PERCENT}%" +fi +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 only if requested +if [ "$GENERATE_SVG" = true ]; then + # Style credit goes to shields.io + cat > /tmp/coverage-badge.svg << EOFSVG + + coverage: ${TEXT} + + + + + + + + + + + + + + + coverage + + ${TEXT} + + +EOFSVG + + echo "Generated SVG badge at /tmp/coverage-badge.svg" +fi