Add reports/render.go
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// render.go — Go-based IEC 62443-3-3 SL2 compliance report renderer.
|
||||
//
|
||||
// Loads a JSON report produced by ansible-test and renders it through
|
||||
// an external Go template file (report.gohtml by default).
|
||||
//
|
||||
// Usage:
|
||||
// go run render.go <report.json> [template.gohtml]
|
||||
//
|
||||
// The template receives the full JSON document as an untyped map.
|
||||
// Registered template functions:
|
||||
// passIcon — maps passed value to ✅/❌/🔍/❓
|
||||
// severityIcon — maps severity string to 🔴/🟠/🟡/🟢/⚪
|
||||
// title — capitalizes first letter of each word
|
||||
// divf — float64 division (a/b*100) for percentages
|
||||
// add, sub — integer arithmetic
|
||||
//
|
||||
// Dependencies:
|
||||
// golang.org/x/text v0.14.0 (for cases.Title)
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: gomplate-report <report.json> [template.gohtml]\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
jsonPath := os.Args[1]
|
||||
tmplPath := "reports/report.gohtml"
|
||||
if len(os.Args) >= 3 {
|
||||
tmplPath = os.Args[2]
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(jsonPath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading JSON: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var report map[string]any
|
||||
if err := json.Unmarshal(data, &report); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing JSON: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
funcMap := template.FuncMap{
|
||||
"passIcon": func(v any) string {
|
||||
b, ok := v.(bool)
|
||||
if !ok {
|
||||
return "❓ MANUAL"
|
||||
}
|
||||
if b {
|
||||
return "✅ PASS"
|
||||
}
|
||||
return "❌ FAIL"
|
||||
},
|
||||
"severityIcon": func(s string) string {
|
||||
switch s {
|
||||
case "critical":
|
||||
return "🔴"
|
||||
case "high":
|
||||
return "🟠"
|
||||
case "medium":
|
||||
return "🟡"
|
||||
case "low":
|
||||
return "🟢"
|
||||
}
|
||||
return "⚪"
|
||||
},
|
||||
"title": cases.Title(language.English).String,
|
||||
"divf": func(a, b int) float64 {
|
||||
if b == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(a) / float64(b) * 100.0
|
||||
},
|
||||
"add": func(a, b int) int { return a + b },
|
||||
"sub": func(a, b int) int { return a - b },
|
||||
}
|
||||
|
||||
tmpl, err := template.New("report.gohtml").Funcs(funcMap).ParseFiles(tmplPath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing template: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := tmpl.ExecuteTemplate(os.Stdout, "report.gohtml", report); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error rendering: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user