Skip to main content

gha_expression_proof/
render.rs

1use crate::model::{CheckStatus, EvaluationReceipt};
2use anyhow::Result;
3use clap::ValueEnum;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
6pub enum OutputFormat {
7    Text,
8    Json,
9    Markdown,
10}
11
12pub fn render_receipt(receipt: &EvaluationReceipt, format: OutputFormat) -> Result<String> {
13    match format {
14        OutputFormat::Text => Ok(render_text(receipt)),
15        OutputFormat::Json => Ok(format!("{}\n", serde_json::to_string_pretty(receipt)?)),
16        OutputFormat::Markdown => Ok(render_markdown(receipt)),
17    }
18}
19
20fn render_text(receipt: &EvaluationReceipt) -> String {
21    let mut out = String::new();
22    out.push_str("gha-expression-proof receipt\n");
23    out.push_str(&format!("mode: {}\n", receipt.mode));
24    if let Some(expression) = &receipt.expression {
25        out.push_str(&format!("expression: {expression}\n"));
26    }
27    if let Some(result) = &receipt.result_string {
28        out.push_str(&format!("result: {result}\n"));
29    }
30    if let Some(rendered) = &receipt.rendered {
31        out.push_str(&format!("rendered: {rendered}\n"));
32    }
33    out.push_str(&format!(
34        "summary: {} passed, {} warnings, {} failed, {} skipped\n",
35        receipt.summary.passed,
36        receipt.summary.warnings,
37        receipt.summary.failed,
38        receipt.summary.skipped
39    ));
40
41    out.push_str("\nchecks:\n");
42    for check in &receipt.checks {
43        out.push_str(&format!(
44            "[{}] {} - {}\n",
45            check.status.as_str(),
46            check.id,
47            check.message
48        ));
49    }
50
51    out
52}
53
54fn render_markdown(receipt: &EvaluationReceipt) -> String {
55    let mut out = String::new();
56    out.push_str("# gha-expression-proof Receipt\n\n");
57    out.push_str(&format!("- Mode: `{}`\n", receipt.mode));
58    if let Some(expression) = &receipt.expression {
59        out.push_str(&format!("- Expression: `{}`\n", escape_pipe(expression)));
60    }
61    if let Some(result) = &receipt.result_string {
62        out.push_str(&format!("- Result: `{}`\n", escape_pipe(result)));
63    }
64    if let Some(rendered) = &receipt.rendered {
65        out.push_str(&format!("- Rendered: `{}`\n", escape_pipe(rendered)));
66    }
67    out.push_str(&format!(
68        "- Summary: {} passed, {} warnings, {} failed, {} skipped\n",
69        receipt.summary.passed,
70        receipt.summary.warnings,
71        receipt.summary.failed,
72        receipt.summary.skipped
73    ));
74
75    out.push_str("\n## Checks\n\n");
76    out.push_str("| Status | ID | Message |\n| --- | --- | --- |\n");
77    for check in &receipt.checks {
78        out.push_str(&format!(
79            "| `{}` | `{}` | {} |\n",
80            label(check.status),
81            check.id,
82            escape_pipe(&check.message)
83        ));
84    }
85    out
86}
87
88fn label(status: CheckStatus) -> &'static str {
89    status.as_str()
90}
91
92fn escape_pipe(value: &str) -> String {
93    value.replace('|', "\\|").replace('\n', " ")
94}