Packages

Pure-Elixir, Phoenix-first PDF/document generation with deterministic layout and pagination

Current section

Files

Jump to
rendro lib mix tasks verify.ex
Raw

lib/mix/tasks/verify.ex

defmodule Mix.Tasks.Verify do
use Mix.Task
@moduledoc """
Runs full verification suite with deterministic and advisory lanes.
"""
@moduledoc tags: [:adapter]
@shortdoc "Runs full verification suite with deterministic and advisory lanes"
def run(_args) do
case run_with_lanes(default_lanes()) do
{:ok, _results} -> :ok
{:error, _results} -> exit({:shutdown, 1})
end
end
def run_with_lanes(lanes \\ default_lanes()) do
Mix.shell().info("=== RENDRO VERIFICATION SUITE ===")
results =
Enum.flat_map(lanes, fn {lane_name, steps} ->
Mix.shell().info("\n[LANE: #{lane_name}]")
Enum.map(steps, fn {step_name, fun} ->
run_step(lane_name, step_name, fun)
end)
end)
print_summary(results)
if Enum.any?(results, &(&1.status == :fail)) do
{:error, results}
else
{:ok, results}
end
end
defp default_lanes do
if test_process_running?() do
Application.get_env(:rendro, :verify_test_lanes, verification_lanes())
else
verification_lanes()
end
end
defp test_process_running? do
Mix.env() == :test and Code.ensure_loaded?(ExUnit.Server) and Process.whereis(ExUnit.Server)
end
defp verification_lanes do
[
{"DETERMINISTIC (CORE)",
[
{"CI", fn -> run_system_step("mix", ["ci"]) end},
{"Docs Contract", fn -> run_system_step("mix", ["docs.contract"]) end}
]},
{"ADVISORY (ADAPTERS)",
[
{"Phoenix Example", &verify_phoenix_example/0}
]}
]
end
defp run_step(lane_name, step_name, fun) do
Mix.shell().info("Running #{step_name}...")
result =
try do
case fun.() do
:ok ->
%{lane: lane_name, step: step_name, status: :pass}
{:error, code, output} ->
%{lane: lane_name, step: step_name, status: :fail, code: code, output: output}
{:error, reason} ->
%{lane: lane_name, step: step_name, status: :fail, code: 1, output: inspect(reason)}
_ ->
%{lane: lane_name, step: step_name, status: :pass}
end
rescue
error ->
%{
lane: lane_name,
step: step_name,
status: :fail,
code: 1,
output: Exception.message(error)
}
catch
:exit, {:shutdown, code} when code != 0 ->
%{lane: lane_name, step: step_name, status: :fail, code: code}
kind, reason ->
%{
lane: lane_name,
step: step_name,
status: :fail,
code: 1,
output: "#{inspect(kind)}: #{inspect(reason)}"
}
end
print_step_result(result)
result
end
defp print_step_result(%{step: step_name, status: :pass}) do
Mix.shell().info(" - #{step_name}: PASS")
end
defp print_step_result(%{step: step_name, status: :fail} = result) do
code = Map.get(result, :code, 1)
Mix.shell().error(" - #{step_name}: FAIL (code #{code})")
case Map.get(result, :output) do
output when is_binary(output) and output != "" ->
Mix.shell().error(output)
_ ->
:ok
end
end
defp print_summary(results) do
Mix.shell().info("\nVERIFICATION COMPLETE")
Mix.shell().info("Summary:")
Enum.each(results, fn %{lane: lane_name, step: step_name, status: status} ->
Mix.shell().info(" - [#{lane_name}] #{step_name}: #{String.upcase(to_string(status))}")
end)
if Enum.any?(results, &(&1.status == :fail)) do
Mix.shell().error("Overall: FAIL")
else
Mix.shell().info("Overall: PASS")
end
end
defp verify_phoenix_example do
File.cd!("examples/phoenix_example", fn ->
with :ok <- run_system_step("mix", ["deps.get"]) do
run_system_step("mix", ["compile"])
end
end)
end
defp run_system_step(command, args) do
{output, exit_code} = System.cmd(command, args, stderr_to_stdout: true)
if exit_code == 0 do
:ok
else
{:error, exit_code, output}
end
end
end