ExQuality.Report (ExQuality v0.13.0)
View SourceBuilds the machine-readable form of a run.
mix quality exits 0 or 1 for the whole run, which tells a caller that
something failed but not what. A script that wants to route on the result -
hand the credo findings to one fixer, the test failures to another - would
otherwise have to scrape the console or re-run the tools.
A report answers "which stages ran, which failed, and what did they find" from the same results the human output is rendered from, so the two streams can never disagree.
Shape
{
"version": "0.6.0",
"status": "error",
"duration_ms": 48213,
"profile": "loop",
"scope": "changed",
"base_ref": "origin/main",
"stages": [
{
"name": "Credo",
"status": "error",
"summary": "5 issues (2 readability, 3 design)",
"duration_ms": 412,
"stats": {"issue_count": 5},
"findings": [
{
"file": "lib/user.ex", "line": 42, "column": 3,
"app": "web", "severity": "info",
"check": "Credo.Check.Readability.ModuleDoc",
"message": "Modules should have a @moduledoc tag."
}
]
},
{
"name": "Dialyzer", "status": "skipped",
"summary": "--quick", "duration_ms": 0,
"stats": {}, "findings": []
}
]
}Every stage carries the same keys whatever its status, so a consumer reads
one field for the explanation rather than branching: a skipped stage puts its
reason in summary, exactly as ExQuality.Stage.skipped/2 records it.
A stage that failed without producing findings carries its tool's full output
under output instead, mirroring the human renderer. Findings are the parsed
form; output is the fallback, and one of the two is always present for a
failure.
How much the run covered
profile, scope and base_ref are always present at the root, null when
they do not apply. They are what makes "status": "ok" interpretable: a green
run scoped to three test files is not the same claim as a green full run, and a
caller that lowers a recorded coverage figure or moves a baseline on a green
run has to be able to refuse the narrow one. The test stage repeats them, plus
the files it ran, in its own object. See ExQuality.Scope.
Summary
Functions
Builds a report from the results of a run.
Encodes a report as pretty-printed JSON, newline terminated.
Types
Functions
@spec build([ExQuality.Stage.result()], non_neg_integer(), keyword()) :: t()
Builds a report from the results of a run.
duration_ms is the wall clock time of the whole run, which is not the sum
of the stage durations because the analysis stages run in parallel.
config is the run's loaded config, used for the root profile and for the
scope when the test stage did not run to report one of its own.
iex> alias ExQuality.{Report, Stage}
iex> report = Report.build([Stage.skipped("Dialyzer", "--quick")], 12)
iex> {report.status, report.duration_ms, length(report.stages)}
{"ok", 12, 1}
iex> alias ExQuality.{Report, Stage}
iex> report = Report.build([Stage.skipped("Tests", "--skip test")], 12, profile: :loop)
iex> {report.profile, report.scope}
{"loop", "all"}
Encodes a report as pretty-printed JSON, newline terminated.
iex> ExQuality.Report.encode!(%{status: "ok"})
"{\n \"status\": \"ok\"\n}\n"