defmodule ExCheck.Reporter.Json do @moduledoc false # Strict, single valid JSON object describing the whole run. For tools/scripts; # pairs naturally with `--output PATH`. Failed checks carry their (escaped) output. @behaviour ExCheck.Reporter alias ExCheck.JSON alias ExCheck.Reporter @impl true def report(results, total_duration, opts) do Reporter.emit(JSON.encode(build(results, total_duration)), opts) end @doc false def build(results, total_duration) do failed = Enum.count(results, &match?({:error, _, _}, &1)) %{ status: if(failed == 0, do: "ok", else: "error"), duration_s: total_duration, passed: Enum.count(results, &match?({:ok, _, _}, &1)), failed: failed, skipped: Enum.count(results, &match?({:skipped, _, _}, &1)), checks: results |> Enum.sort_by(&Reporter.summary_order/1) |> Enum.map(&check/1) } end defp check({:ok, {name, cmd, _}, {code, _, duration}}) do {name, app} = Reporter.split_name(name) %{ name: name, app: app, status: "ok", command: command(cmd), exit_code: code, duration_s: duration } end defp check({:error, {name, cmd, _}, {code, output, duration}}) do {name, app} = Reporter.split_name(name) %{ name: name, app: app, status: "error", command: command(cmd), exit_code: code, duration_s: duration, output: Reporter.strip_ansi(output) } end defp check({:skipped, name, reason}) do {name, app} = Reporter.split_name(name) %{name: name, app: app, status: "skipped", reason: Reporter.skip_reason_string(reason)} end defp command(cmd), do: cmd |> List.wrap() |> Enum.join(" ") end