Skip to content

Guardrails / Collectors

Code coverage ​

The coverage the build already measured, read from whichever report format it left behind and normalized into one shape: the line and branch totals across every report, and a summary per file. The covered and missed line numbers are left out unless you set lineDetail, because a large repository's line map is bigger than the facts document is allowed to be. Reports that name the same file are merged line by line, so a per module report and a merged report agree, but a report carrying only totals is added on top.

Facts keycoverage
Versionv1
Scriptcoverage.py
Timeout60 seconds

Inputs ​

InputDescriptionDefaultEnvironment
reportsComma separated globs matched against every file in the working directory and against bare file names, naming the coverage reports to read.jacoco*.xml,jacocoTestReport.xml,cobertura*.xml,coverage*.xml,lcov.info,coverage-final.jsonGUARDRAIL_INPUT_REPORTS
maxFilesMaximum number of files to carry in byFile, those with the most uncovered lines first. The totals still include files that are dropped.500GUARDRAIL_INPUT_MAXFILES
lineDetailtrue to carry the covered and missed line numbers of every file in byFile. A guardrail that checks the lines a change touched needs them; for everything else they only add size.falseGUARDRAIL_INPUT_LINEDETAIL

When a guardrail declares an input with the same name, it passes its value through. That means you set these values in the guardrail's configuration in buildnote.json.

A guardrail asks for these facts by name and reads them back by the same name:

json
{
  "collect": ["coverage"]
}
python
coverage = guardrail.facts("coverage")

Facts ​

These are the fields of the document coverage collects. In a path, [] means each entry of the list before it, and [path] means a key of the object before it.

FactMeaning
sourcereport when a coverage report was read, none when there was none.
reasonWhy nothing was read, present only when source is none.
reportsEvery report that was read, in path order.
reports[].pathPath of the report, relative to the directory the CLI runs in.
reports[].modifiedWhen the report was last written, in ISO 8601, so you can spot a stale report.
reports[].formatFormat it was read as: jacoco, cobertura, istanbul or lcov.
lines.coveredLines at least one report saw executed, counted once across every report that names the file.
lines.missedLines every report saw unexecuted.
lines.percentCovered lines as a percentage of the lines the reports measured, to two decimal places, 0.0 when they measured none.
branchesThe branch totals, or null when no report that was read carries branch coverage.
branches.coveredBranches taken.
branches.missedBranches never taken.
branches.percentTaken branches as a percentage of the branches the reports measured, to two decimal places.
filesHow many files the reports measured, before maxFiles was applied.
byFileA summary per file, the ones with the most uncovered lines first, up to maxFiles.
byFile[path].coveredLines of that file at least one report saw executed.
byFile[path].missedLines of that file every report saw unexecuted.
byFile[path].percentCovered lines of that file as a percentage, to two decimal places.
byFile[path].coveredLinesThe covered line numbers, ascending, present only when lineDetail is true.
byFile[path].missedLinesThe missed line numbers, ascending, present only when lineDetail is true.
droppedFiles left out of byFile because maxFiles was reached.

If a collector can't finish, it prints what it gathered so far along with an incomplete key that says why. Facts after the point where it stopped are missing, so a check that depends on them should read incomplete first.

Example facts ​

Here are the facts the coverage collector gathers from an example project:

json
{
  "source": "report",
  "reports": [
    {
      "path": "jacocoTestReport.xml",
      "modified": "2026-03-04T10:15:00Z",
      "format": "jacoco"
    }
  ],
  "lines": {
    "covered": 4,
    "missed": 3,
    "percent": 57.14
  },
  "branches": {
    "covered": 1,
    "missed": 3,
    "percent": 25.0
  },
  "files": 2,
  "byFile": {
    "com/company/widget/Broker.kt": {
      "covered": 1,
      "missed": 2,
      "percent": 33.33
    },
    "com/company/widget/Queue.kt": {
      "covered": 3,
      "missed": 1,
      "percent": 75.0
    }
  },
  "dropped": 0
}

Collected for ​

GuardrailCategoryInputs
tests/coverage-floortestsnone

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412