Custom Runner
The custom runner mechanism lets you plug any language, test framework, or coverage tool into nolapse. You write a script that measures coverage and prints one structured line to stdout. nolapse handles the rest — baseline comparison, threshold enforcement, CI reporting.
The runner contract
Section titled “The runner contract”A nolapse runner is any executable that satisfies these rules:
-
Invocation. nolapse calls it as:
python3 <script> <repo_path>for Python, or directly as<script> <repo_path>for shell/binary runners. The first (and only) positional argument is the absolute path to the repository root. -
Output. The runner must print the following line to stdout at some point during execution:
nolapse-coverage: <number>where
<number>is the coverage percentage as a decimal, e.g.73.4or100.0. Any other stdout output is ignored. Stderr is forwarded to the nolapse log. -
Exit codes. Exit
0if coverage was measured successfully. Exit1(or any non-zero) if measurement failed. nolapse will surface the failure and abort without comparing to a baseline. -
Timeout. Runners are not given an infinite window. Keep execution under the timeout of whichever built-in runner your
langsetting maps to. Forlang: customthe timeout is 10 minutes.
Telling nolapse to use your runner
Section titled “Telling nolapse to use your runner”Set NOLAPSE_RUNNER_PATH to the absolute path of your runner script before invoking nolapse:
export NOLAPSE_RUNNER_PATH=/path/to/my-runner.shnolapse run --repo .You can also set it inline:
NOLAPSE_RUNNER_PATH=./nolapse-runner.sh nolapse run --repo .In nolapse.yaml, set lang: custom so nolapse knows to delegate entirely to the external script rather than using any built-in logic:
lang: customwarn_threshold: -1.0fail_threshold: -5.0strict_mode: falseMinimal shell example
Section titled “Minimal shell example”The following script is a complete, working custom runner for a hypothetical make coverage target that writes a coverage-report.txt file containing a line like Total: 76.3%.
#!/usr/bin/env bashset -euo pipefail
REPO_PATH="${1:-.}"cd "$REPO_PATH"
# Run your test suite and generate coverage outputmake coverage 2>/dev/null
# Extract the percentage from whatever format your tool producesPCT=$(grep -oP 'Total:\s+\K[\d.]+' coverage-report.txt)
if [ -z "$PCT" ]; then echo "custom-runner: could not parse coverage percentage" >&2 exit 1fi
# Emit the required summary lineecho "nolapse-coverage: ${PCT}"Save it, make it executable (chmod +x nolapse-runner.sh), then:
NOLAPSE_RUNNER_PATH=./nolapse-runner.sh nolapse run --repo .Python runner example
Section titled “Python runner example”#!/usr/bin/env python3"""Minimal nolapse custom runner — reads coverage from a JSON file."""
import jsonimport sysfrom pathlib import Path
repo_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(".")
coverage_file = repo_path / "coverage-output.json"if not coverage_file.exists(): print(f"custom-runner: {coverage_file} not found", file=sys.stderr) sys.exit(1)
data = json.loads(coverage_file.read_text())pct = data["totals"]["percent_covered"] # adjust key path for your tool
print(f"nolapse-coverage: {pct:.1f}")What nolapse does after receiving the output line
Section titled “What nolapse does after receiving the output line”Once the runner exits 0 and the nolapse-coverage: line has been captured, nolapse:
- Parses the percentage value.
- Loads
nolapse-baseline.jsonfrom the--repodirectory. - Computes
delta = current - baseline. - Applies threshold logic:
delta > -warn_threshold→ passdelta > -fail_threshold→ warn (exit 0, warning message)delta ≤ -fail_threshold→ fail (exit 1)
- If
strict_mode: true, any negative delta fails regardless of thresholds.
Using a custom runner for languages without built-in support
Section titled “Using a custom runner for languages without built-in support”For languages that do not yet have a built-in nolapse runner (Node.js, Java, .NET), the custom runner is the recommended approach. See the per-language pages for ready-made examples: