Skip to content

Commit

Permalink
feat: add html output
Browse files Browse the repository at this point in the history
  • Loading branch information
dhth committed Mar 26, 2024
1 parent 2d482de commit 256d60d
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ act3
cosign.key
cosign.pub
justfile
docs/sample.html
30 changes: 29 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ func die(msg string, args ...any) {
os.Exit(1)
}

var (
format = flag.String("format", "", "output format to use; possible values: html")
htmlTemplateFile = flag.String("html-template-file", "", "path of the HTML template file to use")
)

func Execute() {
currentUser, err := user.Current()
var defaultConfigFilePath string
Expand All @@ -34,6 +39,16 @@ func Execute() {
die("config-file cannot be empty")
}

var outputFmt ui.OutputFmt
if *format != "" {
switch *format {
case "html":
outputFmt = ui.HTMLFmt
default:
die("unsupported value for format")
}
}

configFilePathExpanded := expandTilde(*configFilePath)

_, err = os.Stat(configFilePathExpanded)
Expand All @@ -49,10 +64,23 @@ func Execute() {
die(cfgErrSuggestion(fmt.Sprintf("No workflows found")))
}

var htmlTemplate string
if *htmlTemplateFile != "" {
_, err := os.Stat(*htmlTemplateFile)
if os.IsNotExist(err) {
die(fmt.Sprintf("Error: template file doesn't exist at %q", *htmlTemplateFile))
}
templateFileContents, err := os.ReadFile(*htmlTemplateFile)
if err != nil {
die(fmt.Sprintf("Error: couldn't read template file %q", *htmlTemplateFile))
}
htmlTemplate = string(templateFileContents)
}

ghClient, err := getGHClient()
if err != nil {
die("Error: %q", err.Error())
}

ui.RenderUI(ghClient, workflows)
ui.RenderUI(ghClient, workflows, outputFmt, htmlTemplate)
}
Binary file added docs/favicon.ico
Binary file not shown.
64 changes: 64 additions & 0 deletions docs/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<script src="https://cdn.tailwindcss.com"></script>
<title>{{.Title}}</title>
</head>
<body class="bg-[#282828] text-xl">
<div class="container mx-auto p-4">
<h1 class="text-[#fbf1c7] text-2xl mb-4 font-bold">{{.Title}}</h1>
<p class="text-stone-300 italic mb-4 mt-8">Generated at {{.Timestamp}}</p>
<table class="table-auto font-bold text-left">
<thead>
<tr class="text-[#fbf1c7] bg-[#3c3836]">
{{range .Columns -}}
<th class="px-4 py-2">{{.}}</th>
{{end -}}
</tr>
</thead>
<tbody>
{{range .Rows -}}
<tr>
<td class="px-4 py-2 text-[#d3869b]">{{.Key}}</td>
{{range .Data -}}
{{if .Success}}
<td class="px-4 py-2 text-[#b8bb26]">{{.Result}}</td>
{{else}}
<td class="px-4 py-2 text-[#fb4934]">{{.Result}}</td>
{{end}}
{{end -}}
</tr>
{{end -}}
</tbody>
</table>

{{if .Failures }}
<br>
<hr>
<br>
<p class="text-[#fb4934] font-bold italic">Failures</p>
<br>
{{range $key, $value := .Failures -}}
<p class="text-[#a89984] italic">{{$key}}: <a class="underline" href="{{$value}}" target="_blank">{{$value}}</a></p>
<br>
{{end -}}
{{end -}}

{{if .Errors }}
<br>
<hr>
<br>
<p class="text-[#fb4934] font-bold italic">Errors</p>
<br>
{{range $index, $error := .Errors -}}
<p class="text-[#a89984] italic">{{$index}}: {{$error}}</p>
<br>
{{end -}}
{{end -}}
</div>
</body>
</html>

4 changes: 3 additions & 1 deletion ui/initial.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package ui

import "github.com/shurcooL/githubv4"

func InitialModel(ghClient *githubv4.Client, workflows []Workflow) model {
func InitialModel(ghClient *githubv4.Client, workflows []Workflow, outputFmt OutputFmt, htmlTemplate string) model {

workflowResults := make(map[string][]string)

Expand All @@ -21,6 +21,8 @@ func InitialModel(ghClient *githubv4.Client, workflows []Workflow) model {
ghClient: ghClient,
workflows: workflows,
workFlowResults: workflowResults,
outputFmt: outputFmt,
htmlTemplate: htmlTemplate,
message: "hello",
errors: errors,
failedWorkflowURLs: failedWorkflowRunURLs,
Expand Down
3 changes: 3 additions & 0 deletions ui/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ type model struct {
ghClient *githubv4.Client
workFlowResults map[string][]string
numResults int
outputFmt OutputFmt
message string
htmlTemplate string
errors []error
failedWorkflowURLs map[string]string
outputPrinted bool
}

func (m model) Init() tea.Cmd {
Expand Down
81 changes: 81 additions & 0 deletions ui/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ui

const (
HTMLTemplText = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<title>{{.Title}}</title>
</head>
<body class="bg-slate-900 text-xl">
<div class="container mx-auto p-4">
<h1 class="text-stone-50 text-2xl mb-4 font-bold">{{.Title}}</h1>
<p class="text-stone-300 italic mb-4 mt-8">Generated at {{.Timestamp}}</p>
<table class="table-auto font-bold text-left">
<thead>
<tr class="text-stone-50 bg-slate-700">
{{range .Columns -}}
<th class="px-4 py-2">{{.}}</th>
{{end -}}
</tr>
</thead>
<tbody>
{{range .Rows -}}
<tr>
<td class="px-4 py-2 text-blue-400">{{.Key}}</td>
{{range .Data -}}
{{if .Success}}
<td class="px-4 py-2 text-green-400">{{.Result}}</td>
{{else}}
<td class="px-4 py-2 text-rose-400">{{.Result}}</td>
{{end}}
{{end -}}
</tr>
{{end -}}
</tbody>
</table>
{{if .Failures }}
<br>
<hr>
<br>
<p class="text-[#fb4934] font-bold italic">Failures</p>
<br>
{{range $key, $value := .Failures -}}
<p class="text-gray-400 italic">{{$key}}: <a class="underline" href="{{$value}}" target="_blank">{{$value}}</a></p>
<br>
{{end -}}
{{end -}}
{{if .Errors }}
<br>
<hr>
<br>
<p class="text-red-600 font-bold italic">Errors</p>
<br>
{{range $index, $error := .Errors -}}
<p class="text-gray-400 italic">{{$index}}: {{$error}}</p>
<br>
{{end -}}
{{end -}}
</div>
</body>
</html>
`
errorTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Something went wrong generating the HTML</p>
<p>Error: %s</p>
</body>
</html>
`
)
26 changes: 26 additions & 0 deletions ui/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,29 @@ type NodeResult struct {
type QueryResult struct {
NodeResult `graphql:"node(id: $workflowId)"`
}

type OutputFmt uint

const (
UnspecifiedFmt OutputFmt = iota
HTMLFmt
)

type HTMLWorkflowResult struct {
Result string
Success bool
}

type HTMLDataRow struct {
Key string
Data []HTMLWorkflowResult
}

type HTMLData struct {
Title string
Columns []string
Rows []HTMLDataRow
Failures map[string]string
Errors *[]error
Timestamp string
}
11 changes: 9 additions & 2 deletions ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/shurcooL/githubv4"
)

func RenderUI(ghClient *githubv4.Client, workflows []Workflow) {
func RenderUI(ghClient *githubv4.Client, workflows []Workflow, outputFmt OutputFmt, htmlTemplate string) {

if len(os.Getenv("DEBUG")) > 0 {
f, err := tea.LogToFile("debug.log", "debug")
Expand All @@ -20,7 +20,14 @@ func RenderUI(ghClient *githubv4.Client, workflows []Workflow) {
defer f.Close()
}

p := tea.NewProgram(InitialModel(ghClient, workflows))
var opts []tea.ProgramOption
if outputFmt != UnspecifiedFmt {
opts = append(opts, tea.WithoutRenderer())
// TODO: this may be a hack, and will prevent using STDIN for
// CLI mode, find a better way
opts = append(opts, tea.WithInput(nil))
}
p := tea.NewProgram(InitialModel(ghClient, workflows, outputFmt, htmlTemplate), opts...)
if _, err := p.Run(); err != nil {
log.Fatalf("Something went wrong %s", err)
}
Expand Down
8 changes: 8 additions & 0 deletions ui/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, quitProg()
}
case quitProgMsg:
if !m.outputPrinted {
switch m.outputFmt {
case HTMLFmt:
v := m.renderHTML()
fmt.Print(v)
m.outputPrinted = true
}
}
return m, tea.Quit
}
return m, nil
Expand Down
75 changes: 75 additions & 0 deletions ui/view.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package ui

import (
"bytes"
"fmt"
"strings"
"time"

"html/template"

"github.com/charmbracelet/lipgloss"
)
Expand All @@ -12,6 +16,77 @@ const (
WORKFLOW_NAME_WIDTH = 30
)

const (
ErrorFetchingVersion = "error"
SystemNotFound = "not found"
)

func (m model) renderHTML() string {

var columns []string
var rows []HTMLDataRow

data := HTMLData{
Title: "act3",
}

columns = append(columns, "workflow")
for _, env := range []string{"last", "2nd last", "3rd last"} {
columns = append(columns, env)
}

for _, workflow := range m.workflows {

var workflowKey string
if workflow.Key != nil {
workflowKey = *workflow.Key
} else {
workflowKey = fmt.Sprintf("%s:%s", workflow.Repo, workflow.Name)
}

var data []HTMLWorkflowResult
for _, workflowRunResult := range m.workFlowResults[workflow.ID] {
data = append(data, HTMLWorkflowResult{
Result: workflowRunResult,
Success: strings.Contains(workflowRunResult, "SUCCESS"),
})
}
rows = append(rows, HTMLDataRow{
Key: workflowKey,
Data: data,
})
}

data.Columns = columns
data.Rows = rows
if len(m.errors) > 0 {
data.Errors = &m.errors
}
if len(m.failedWorkflowURLs) > 0 {
data.Failures = m.failedWorkflowURLs
}
data.Timestamp = time.Now().Format("2006-01-02 15:04:05 MST")

var tmpl *template.Template
var err error
if m.htmlTemplate == "" {
tmpl, err = template.New("act3").Parse(HTMLTemplText)
} else {
tmpl, err = template.New("act3").Parse(m.htmlTemplate)
}
if err != nil {
return fmt.Sprintf(string(errorTemplate), err.Error())
}

var buf bytes.Buffer
err = tmpl.Execute(&buf, data)
if err != nil {
return fmt.Sprintf(string(errorTemplate), err.Error())
}

return buf.String()
}

func (m model) View() string {
var s string

Expand Down

0 comments on commit 256d60d

Please sign in to comment.