Skip to content

Commit

Permalink
Add Markdown Summary Output in report.go & add Tests in report_test.go
Browse files Browse the repository at this point in the history
Implement generateMarkdownSummary() in report.go for Markdown CLI output
Add test cases for generateMarkdownSummary() in report_test.go
Introduce new output option summary-markdown for GitHub Action
Add status icon to Markdown summary

resolves: HACBS-2672
Signed-off-by: Sean Conroy [email protected]
  • Loading branch information
seanconroy2021 authored Oct 3, 2023
2 parents b56e7c8 + 05e11b8 commit c6741e6
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 3 deletions.
66 changes: 66 additions & 0 deletions internal/applicationsnapshot/__snapshots__/report_test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

[Test_GenerateMarkdownSummary/One_Warning_and_One_Success - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 1 | :white_check_mark: |
| Failures | 0 | :white_check_mark: |
| Warnings | 1 | :x: |
| Result | | :white_check_mark: |

---

[Test_GenerateMarkdownSummary/One_failure_and_One_Success - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 1 | :x: |
| Failures | 1 | :x: |
| Warnings | 0 | :white_check_mark: |
| Result | | :white_check_mark: |

---

[Test_GenerateMarkdownSummary/One_Failure_and_One_Violation - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 0 | :x: |
| Failures | 1 | :x: |
| Warnings | 1 | :x: |
| Result | | :x: |

---

[Test_GenerateMarkdownSummary/Multiple_Failure_and_One_Violation - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 0 | :x: |
| Failures | 3 | :x: |
| Warnings | 2 | :x: |
| Result | | :x: |

---

[Test_GenerateMarkdownSummary/With_success - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 3 | :white_check_mark: |
| Failures | 0 | :white_check_mark: |
| Warnings | 0 | :white_check_mark: |
| Result | | :white_check_mark: |

---

[Test_GenerateMarkdownSummary/With_Snapshot - 1]
| Field | Value |Status|
|-----------|-------|-------|
| Time | 1970-01-01 00:00:00 | |
| Successes | 0 | :x: |
| Failures | 2 | :x: |
| Warnings | 2 | :x: |
| Result | | :x: |

---
42 changes: 39 additions & 3 deletions internal/applicationsnapshot/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ type TestReport struct {

// Possible formats the report can be written as.
const (
JSON = "json"
YAML = "yaml"
APPSTUDIO = "appstudio"
SummaryMarkdown = "summary-markdown"
JSON = "json"
YAML = "yaml"
APPSTUDIO = "appstudio"
// Deprecated. Remove when hacbs output is removed
HACBS = "hacbs"
Summary = "summary"
Expand Down Expand Up @@ -162,6 +163,8 @@ func (r Report) WriteAll(targets []string, p format.TargetParser) (allErrors err
// toFormat converts the report into the given format.
func (r *Report) toFormat(format string) (data []byte, err error) {
switch format {
case SummaryMarkdown:
data, err = generateMarkdownSummary(r)
case JSON:
data, err = json.Marshal(r)
case YAML:
Expand Down Expand Up @@ -240,6 +243,39 @@ func condensedMsg(results []evaluator.Result) map[string][]string {
return shortNames
}

func generateMarkdownSummary(r *Report) ([]byte, error) {
var markdownBuffer bytes.Buffer
markdownBuffer.WriteString("| Field | Value |Status|\n")
markdownBuffer.WriteString("|-----------|-------|-------|\n")

var totalViolations, totalWarnings, totalSuccesses int
pr := r.toSummary()
for _, component := range pr.Components {
totalViolations += component.TotalViolations
totalWarnings += component.TotalWarnings
totalSuccesses += component.TotalSuccesses
}

writeIcon := func(condition bool) string {
if condition {
return ":white_check_mark:"
}
return ":x:"
}

writeMarkdownField(&markdownBuffer, "Time", r.created.UTC().Format("2006-01-02 15:04:05"), "")
writeMarkdownField(&markdownBuffer, "Successes", totalSuccesses, writeIcon(totalSuccesses >= 1 && totalViolations == 0))
writeMarkdownField(&markdownBuffer, "Failures", totalViolations, writeIcon(totalViolations == 0))
writeMarkdownField(&markdownBuffer, "Warnings", totalWarnings, writeIcon(totalWarnings == 0))
writeMarkdownField(&markdownBuffer, "Result", "", writeIcon(r.Success))
return markdownBuffer.Bytes(), nil
}

func writeMarkdownField(buffer *bytes.Buffer, name string, value any, icon string) {
valueStr := fmt.Sprintf("%v", value)
buffer.WriteString(fmt.Sprintf("| %s | %s | %s |\n", name, valueStr, icon))
}

// toAppstudioReport returns a version of the report that conforms to the
// TEST_OUTPUT format, usually written to the TEST_OUTPUT Tekton task result
func (r *Report) toAppstudioReport() TestReport {
Expand Down
116 changes: 116 additions & 0 deletions internal/applicationsnapshot/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"testing"
"time"

"github.com/gkampitakis/go-snaps/snaps"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -152,6 +153,121 @@ policy:
assert.False(t, report.Success)
}

func Test_GenerateMarkdownSummary(t *testing.T) {
cases := []struct {
name string
snapshot string
components []Component
}{
{
name: "One Warning and One Success",
components: []Component{
{
Successes: []evaluator.Result{
{Message: "Success1"},
},
SuccessCount: 1,
Warnings: []evaluator.Result{
{Message: "Warning1"},
},
Success: true,
},
},
},
{
name: "One failure and One Success",
components: []Component{
{
Successes: []evaluator.Result{
{Message: "Success1"},
},
SuccessCount: 1,
Violations: []evaluator.Result{
{Message: "faulure1"},
},
Success: true,
},
},
},
{
name: "One Failure and One Violation",
components: []Component{
{
Violations: []evaluator.Result{
{Message: "failure1"},
},
Warnings: []evaluator.Result{
{Message: "Warning1"},
},
Success: false,
},
},
},
{
name: "Multiple Failure and One Violation",
components: []Component{
{
Violations: []evaluator.Result{
{Message: "failure1"},
{Message: "failure2"},
{Message: "failure3"},
},
Warnings: []evaluator.Result{
{Message: "Warning1"},
{Message: "Warning2"},
},
Success: false,
},
},
},
{
name: "With success",
components: []Component{
{
Successes: []evaluator.Result{
{Message: "Success1"},
{Message: "Success2"},
{Message: "Success3"},
},
SuccessCount: 3,
Success: true,
},
},
},
{
name: "With Snapshot",
snapshot: "snappy",
components: []Component{
{
Violations: []evaluator.Result{
{Message: "failure1"},
{Message: "failure2"},
},
Warnings: []evaluator.Result{
{Message: "Warning1"},
{Message: "Warning2"},
},
Success: false,
},
},
},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {

ctx := context.Background()
report, err := NewReport(c.snapshot, c.components, createTestPolicy(t, ctx), nil, nil)
assert.NoError(t, err)
report.created = time.Unix(0, 0).UTC()

markdownSummary, err := generateMarkdownSummary(&report)
assert.NoError(t, err)
snaps.MatchSnapshot(t, string(markdownSummary))
})
}
}

func Test_ReportSummary(t *testing.T) {
tests := []struct {
name string
Expand Down

0 comments on commit c6741e6

Please sign in to comment.