Skip to content

Set the coverage floor from what the runners measure #230

Set the coverage floor from what the runners measure

Set the coverage floor from what the runners measure #230

Workflow file for this run

name: Test
on:
push:
pull_request:
workflow_call:
concurrency:
group: test-${{ github.ref }}
cancel-in-progress: true
# Verbose pytest defaults: long tracebacks, locals, and a short test summary
# (-ra) so failed/skipped/xfailed tests are listed at the end of the log
# instead of buried in the middle. Applied via env so every pytest invocation
# in this workflow inherits the same diagnostics.
env:
PYTEST_ADDOPTS: "-vv --tb=long --showlocals -ra --color=yes"
PIP_DISABLE_PIP_VERSION_CHECK: "1"
PYTHONUNBUFFERED: "1"
jobs:
# Fast pytest selftests + rawterm/menuconfig smoke test on all platforms.
# Independent of the kernel tree, so it returns feedback quickly and runs
# in parallel with the slower conformance job below.
selftest:
name: Selftest (Python ${{ matrix.target.python }}, ${{ matrix.target.os }})
runs-on: ${{ matrix.target.builder }}
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
# NOTE: Windows runs only the headless-portable subset (no Unix shell).
# Linux spans the supported Python floor (3.8) through current (3.13)
# to keep the python_requires claim honest; macOS/Windows pin 3.12
# since the version-sensitive surface is pure Python and OS-independent.
target:
- python: '3.8'
os: Linux
builder: ubuntu-24.04
- python: '3.10'
os: Linux
builder: ubuntu-24.04
- python: '3.12'
os: Linux
builder: ubuntu-24.04
- python: '3.13'
os: Linux
builder: ubuntu-24.04
- python: '3.12'
os: macOS
builder: macos-15
- python: '3.12'
os: Windows
builder: windows-2022
headless-only: true
steps:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.target.python }}
- name: Install Python dependencies
run: |
set -euo pipefail
python -m pip install --user --upgrade pip
python -m pip install --user setuptools wheel pytest pytest-cov
- name: Check out Kconfiglib source code
uses: actions/checkout@v6
- name: Run pytest selftests
run: |
set -euo pipefail
if [ "${{ matrix.target.headless-only }}" == "true" ]; then
# Windows: portable subset -- excludes tests that need gcc or
# Unix shell commands (Kpreprocess uses $(shell,...) with
# bash-specific syntax).
python -m pytest tests/test_preprocess.py \
-k "test_user_defined or test_success_failure or test_python_fn or test_kconfig_warn"
else
# Coverage on the jobs that run the whole suite. The floor is a
# backstop against a large drop, not a ratchet; raise it as
# coverage improves.
#
# 35 is set against what these runners report, which is 40. Do not
# calibrate it from a local run on Python 3.14 or newer: coverage
# switches to the sys.monitoring backend there and scores the same
# suite at 51, and a floor taken from that number fails every job
# here. COVERAGE_CORE=ctrace reproduces the runner figure locally.
python -m pytest tests/ --ignore=tests/test_conformance.py \
--cov=kconfiglib --cov=menuconfig --cov=guiconfig --cov=rawterm \
--cov-report=term --cov-report=xml:coverage.xml \
--cov-fail-under=35
fi
- name: Store coverage report
# Only the jobs that ran the full suite produce one. !cancelled() rather
# than always(), so that a coverage failure still uploads the report
# explaining it but a cancelled run doesn't stop to upload anything.
if: ${{ !cancelled() && matrix.target.headless-only != true }}
uses: actions/upload-artifact@v6
with:
name: coverage-${{ matrix.target.os }}-py${{ matrix.target.python }}
path: coverage.xml
if-no-files-found: ignore
- name: Validate rawterm and menuconfig (Unix)
# Exercises rawterm Color/Style/Region compositing, terminal init/close
# (termios on Unix), and menuconfig headless mode with style parsing.
if: ${{ matrix.target.os != 'Windows' }}
run: |
set -euo pipefail
python .ci/validate-rawterm.py
- name: Validate rawterm and menuconfig (Windows)
# On Windows, use cmd so Python gets real console handles (bash
# runs through MSYS2/mintty which lacks a native Windows console).
if: ${{ matrix.target.os == 'Windows' }}
shell: cmd
run: |
python .ci/validate-rawterm.py
if errorlevel 1 exit /b %errorlevel%
- name: Diagnostic dump on failure
if: failure()
shell: bash
run: |
# Best-effort diagnostics. Never let this step itself fail the job;
# the real failure has already been recorded above.
set +e
echo "::group::Python environment"
python --version
python -c "import sys, platform; print('exec:', sys.executable); print('arch:', platform.architecture())"
python -m pip list
echo "::endgroup::"
echo "::group::Relevant environment variables"
env | grep -E '^(PYTHON|PIP|PYTEST|KCONFIG_)' | sort
echo "::endgroup::"
# Slow kernel-conformance tests: checkout Linux v6.18, build the C kconfig
# tools, then diff our output against them. Runs in parallel with selftest.
conformance:
name: Conformance (Python ${{ matrix.target.python }}, ${{ matrix.target.os }})
runs-on: ${{ matrix.target.builder }}
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
target:
- python: '3.12'
os: Linux
builder: ubuntu-24.04
- python: '3.12'
os: macOS
builder: macos-15
steps:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.target.python }}
- name: Install Python dependencies
run: |
set -euo pipefail
python -m pip install --user --upgrade pip
python -m pip install --user setuptools wheel pytest
- name: Install GNU toolchain (macOS)
# v6.18 kernel Kconfig probes require GNU Make >= 4.0 and a
# supported linker (GNU ld or LLD). macOS ships Make 3.81
# and Apple ld, neither of which is compatible.
# We add ld.lld to PATH and set LD=ld.lld; reltest forwards LD
# as a make command-line variable to override the kernel
# Makefile's unconditional LD=$(CROSS_COMPILE)ld assignment.
if: ${{ matrix.target.os == 'macOS' }}
run: |
set -euo pipefail
brew install make lld
echo "$(brew --prefix make)/libexec/gnubin" >> "$GITHUB_PATH"
echo "$(brew --prefix lld)/bin" >> "$GITHUB_PATH"
echo "LD=ld.lld" >> "$GITHUB_ENV"
- name: Check out Linux source code
uses: actions/checkout@v6
with:
repository: torvalds/linux
ref: v6.18
- name: Check out Kconfiglib source code
uses: actions/checkout@v6
with:
path: Kconfiglib
- name: Apply Linux Kconfig Makefile patch
run: |
set -euo pipefail
git apply Kconfiglib/makefile.patch
- name: Build kernel C kconfig tools
run: |
set -euo pipefail
${MAKE:-make} -j"$(getconf _NPROCESSORS_ONLN)" ARCH=x86 ${LD:+LD=$LD} allnoconfig
test -x scripts/kconfig/conf
rm -f .config .config.old
- name: Run conformance tests and example scripts
run: |
set -euo pipefail
Kconfiglib/tests/reltest python
- name: Diagnostic dump on failure
if: failure()
run: |
set +e
echo "::group::Kernel kconfig build artifacts"
ls -la scripts/kconfig/ 2>/dev/null
echo "::endgroup::"
echo "::group::Leftover .config (if any)"
cat .config 2>/dev/null | head -200
echo "::endgroup::"
echo "::group::Toolchain versions"
${MAKE:-make} --version 2>/dev/null
${LD:-ld} --version 2>/dev/null
cc --version 2>/dev/null
python --version
echo "::endgroup::"
echo "::group::Relevant environment variables"
env | grep -E '^(PYTHON|PIP|PYTEST|CC|HOSTCC|HOSTCXX|MAKE|LD|ARCH|SRCARCH|srctree|KERNELVERSION|KCONFIG_)' | sort
echo "::endgroup::"