Skip to content

feat(stats): add optional ow_stats module and demo5 #116

feat(stats): add optional ow_stats module and demo5

feat(stats): add optional ow_stats module and demo5 #116

Workflow file for this run

name: Code Quality
on:
push:
branches: [ "master", "main" ]
pull_request:
branches: [ "master", "main" ]
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install clang-format (pinned)
run: pip install clang-format==18.1.8
- name: Check code formatting
run: clang-format --dry-run --Werror inc/ds18b20.h inc/onewire.h inc/app.h src/ds18b20.c src/onewire.c src/app.c src/demo.c src/demo2.c src/demo3.c tests/mock/*.h tests/mock/*.c tests/test/*.c
host-tests:
strategy:
fail-fast: false
matrix:
backend: [f1, f0, g0]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install host GCC
run: sudo apt-get update && sudo apt-get install -y gcc
- name: Download CMSIS dependencies
# All families up front: the host suites compile against mocks, but
# keeping every backend's dependency set present lets any matrix cell
# configure either target without re-downloading.
run: |
make download-deps
make OW_TARGET=f0 download-deps
make OW_TARGET=g0 download-deps
- name: Build and run host tests (F1)
if: matrix.backend == 'f1'
run: make test
- name: Build and run host tests (F0)
if: matrix.backend == 'f0'
run: make test-f0
- name: Build and run host tests (G0)
if: matrix.backend == 'g0'
run: make test-g0
coverage:
strategy:
fail-fast: false
matrix:
backend: [f1, f0, g0]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install host GCC and lcov
run: sudo apt-get update && sudo apt-get install -y gcc lcov
- name: Download CMSIS dependencies
run: |
make download-deps
make OW_TARGET=f0 download-deps
make OW_TARGET=g0 download-deps
- name: Build and run host tests with coverage
# COVERAGE=1 adds --coverage (gcov instrumentation) to the host test
# build. The test executables run from the repository root, so the
# .gcno/.gcda files land there as well — capture scans the whole
# checkout and the merge step filters out everything that is not the
# driver core. `make clean` first guarantees a fresh instrumented
# build.
run: |
make clean
if [ "${{ matrix.backend }}" = "f0" ]; then
make test-f0 COVERAGE=1
elif [ "${{ matrix.backend }}" = "g0" ]; then
make test-g0 COVERAGE=1
else
make test COVERAGE=1
fi
- name: Capture coverage trace
run: lcov --capture --directory . --output-file coverage-${{ matrix.backend }}.info --rc branch_coverage=1
- name: Upload coverage trace
uses: actions/upload-artifact@v7
with:
name: coverage-traces-${{ matrix.backend }}
path: coverage-${{ matrix.backend }}.info
coverage-badge:
needs: coverage
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
# genhtml annotates the merged report with source lines, so the
# checkout must be present (the trace stores runner workspace paths,
# which match $GITHUB_WORKSPACE exactly).
- uses: actions/checkout@v5
- name: Install lcov
run: sudo apt-get update && sudo apt-get install -y lcov
- name: Download coverage traces
uses: actions/download-artifact@v7
with:
pattern: coverage-traces-*
path: traces
- name: Merge and filter traces
# Union of every backend's trace measures the MCU-independent core;
# port headers (register plumbing per family) stay out of the metric
# so adding new MCU ports never dilutes the number.
run: |
ARGS=""
for f in traces/*/coverage-*.info; do
ARGS="$ARGS -a $f"
done
lcov $ARGS --output-file union.info --rc branch_coverage=1
lcov --remove union.info '*/tests/*' '/usr/*' '*/inc/macro.h' '*/port/*' \
--output-file core.info --rc branch_coverage=1 --ignore-errors unused
lcov --summary core.info --rc branch_coverage=1 > summary.txt || true
cat summary.txt
- name: Generate HTML report and badge SVG
run: |
mkdir -p publish/coverage
genhtml core.info --output-directory publish/coverage \
--branch-coverage --title "stm32-async-1wire core coverage"
python3 - <<'PY'
import re
text = open("summary.txt").read()
m = re.search(r"lines\.+: ([\d.]+)%", text)
pct = int(round(float(m.group(1))))
color = "#4c1" if pct >= 90 else "#dfb317" if pct >= 75 else "#cb2431"
svg = (
'<svg xmlns="http://www.w3.org/2000/svg" width="112" height="20" role="img">'
'<linearGradient id="g" 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="112" height="20" rx="3" fill="#fff"/></clipPath>'
f'<g clip-path="url(#r)"><rect width="69" height="20" fill="#555"/>'
f'<rect x="69" width="43" height="20" fill="{color}"/>'
'<rect width="112" height="20" fill="url(#g)"/></g>'
'<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11">'
'<text x="34.5" y="15">coverage</text>'
f'<text x="89.5" y="15">{pct}%</text></g></svg>'
)
open("publish/coverage-badge.svg", "w").write(svg)
# The report itself lives under coverage/; give the Pages root a
# redirecting landing page so the bare URL works.
open("publish/index.html", "w").write(
'<!doctype html>\n<html lang="en">\n<head>\n'
'<meta charset="utf-8">\n'
'<title>stm32-async-1wire coverage</title>\n'
'<meta http-equiv="refresh" content="0; url=coverage/">\n'
'<link rel="canonical" href="coverage/">\n</head>\n<body>\n'
'<p>Redirecting to the <a href="coverage/">coverage report'
'&hellip;</a></p>\n</body>\n</html>\n'
)
print("badge:", pct, "%")
PY
- name: Publish to gh-pages
env:
REPO_URL: https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git
run: |
set -e
DIR=/tmp/gh-pages
rm -rf "$DIR"
if git clone --depth 1 --branch gh-pages "$REPO_URL" "$DIR" 2>/dev/null; then
cd "$DIR"
git rm -rq .
else
git init -q -b gh-pages "$DIR"
cd "$DIR"
git remote add origin "$REPO_URL"
echo "stm32-async-1wire coverage pages" > .placeholder.md
fi
cp -r "$GITHUB_WORKSPACE"/publish/* .
git add -A
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit -qm "docs(coverage): refresh report and badge (${GITHUB_SHA::7})" \
|| echo "nothing to commit"
git push -q origin gh-pages
cppcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install cppcheck
run: sudo apt-get update && sudo apt-get install -y cppcheck
- name: Download CMSIS dependencies
run: make download-deps
- name: Run static analysis
run: cppcheck --enable=warning,style,performance,portability --error-exitcode=1 --suppress=missingIncludeSystem --suppress=unusedFunction --suppress=constVariablePointer --suppress=constParameterPointer --suppress=comparePointers -I. -Iinc -ICMSIS/core -ICMSIS/device -DSTM32F103xB -D OW_PORT_TARGET_F1 -D__GNUC__ src/ds18b20.c src/onewire.c src/app.c src/demo.c src/demo2.c src/demo3.c
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install ARM GCC
uses: carlosperate/arm-none-eabi-gcc-action@v1
- name: Cache CMSIS dependencies
id: cache-deps
uses: actions/cache@v5
with:
path: CMSIS/
key: ${{ runner.os }}-cmsis-${{ hashFiles('Makefile') }}
- name: Download dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: make download-deps
- name: Build release (demo)
run: make
- name: Build release (demo2)
run: make APP=demo2
- name: Build release (demo3)
run: make APP=demo3
# Backend-specific register plumbing (e.g. the F0 GPIO BSRR bit naming)
# only compiles into real firmware here — host suites run against mocks.
# Smoke-build both backends and both clock branches of app.c so a
# family-only breakage cannot reach a tag.
- name: Build release (F0 backend)
run: make clean && make OW_TARGET=f0
- name: Build release (F0 backend, 8MHz RC)
run: make clean && make OW_TARGET=f0 SYSCLK_MHZ=8
- name: Build release (G0 backend)
run: make clean && make OW_TARGET=g0
- name: Build release (G0 backend, 16MHz RC)
run: make clean && make OW_TARGET=g0 SYSCLK_MHZ=16
- name: Build with GCC analyzer
run: make clean && make all EXT="-fanalyzer"
continue-on-error: true