Skip to content

Commit 73827dd

Browse files
authored
Merge pull request #315 from gotestyourself/github-actions-format
GitHub actions format
2 parents e7c9840 + 2913209 commit 73827dd

File tree

14 files changed

+344
-27
lines changed

14 files changed

+344
-27
lines changed

.github/workflows/ci.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: ci
2+
3+
on:
4+
pull_request:
5+
push:
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-go@v3
13+
with:
14+
go-version: '1.20'
15+
cache: true
16+
- run: go build .
17+
- run: ./gotestsum -f testname

.project/golangci-lint.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ linters:
3131
- deadcode
3232
- depguard
3333
- errcheck
34-
- gocognit
3534
- goconst
3635
- gofmt
3736
- goimports

cmd/handler_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ func (bufferCloser) Close() error { return nil }
7171
func (bufferCloser) Sync() error { return nil }
7272

7373
func TestEventHandler_Event_WithMissingActionFail(t *testing.T) {
74+
t.Setenv("GITHUB_ACTIONS", "no")
75+
7476
buf := new(bufferCloser)
7577
errBuf := new(bytes.Buffer)
7678
format := testjson.NewEventFormatter(errBuf, "testname", testjson.FormatOptions{})

cmd/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ func setupFlags(name string) (*pflag.FlagSet, *options) {
5656
flags.Usage = func() {
5757
usage(os.Stdout, name, flags)
5858
}
59+
5960
flags.StringVarP(&opts.format, "format", "f",
60-
lookEnvWithDefault("GOTESTSUM_FORMAT", "short"),
61+
lookEnvWithDefault("GOTESTSUM_FORMAT", "pkgname"),
6162
"print format of test input")
6263
flags.BoolVar(&opts.formatOptions.HideEmptyPackages, "format-hide-empty-pkg",
6364
false, "do not print empty packages in compact formats")
@@ -139,6 +140,7 @@ Formats:
139140
pkgname print a line for each package
140141
pkgname-and-test-fails print a line for each package and failed test output
141142
testname print a line for each test and package
143+
github-actions testname format with github actions log grouping
142144
standard-quiet standard go test format
143145
standard-verbose standard go test -v format
144146

cmd/main_e2e_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func TestE2E_RerunFails(t *testing.T) {
3131
if testing.Short() {
3232
t.Skip("too slow for short run")
3333
}
34+
t.Setenv("GITHUB_ACTIONS", "no")
3435

3536
type testCase struct {
3637
name string
@@ -220,6 +221,7 @@ func TestE2E_MaxFails_EndTestRun(t *testing.T) {
220221
envVars["TEST_SEEDFILE"] = tmpFile.Path()
221222
env.PatchAll(t, envVars)
222223

224+
t.Setenv("GOTESTSUM_FORMAT", "pkgname")
223225
flags, opts := setupFlags("gotestsum")
224226
args := []string{"--max-fails=2", "--packages=./testdata/e2e/flaky/", "--", "-tags=testdata"}
225227
assert.NilError(t, flags.Parse(args))
@@ -244,6 +246,7 @@ func TestE2E_IgnoresWarnings(t *testing.T) {
244246
if testing.Short() {
245247
t.Skip("too slow for short run")
246248
}
249+
t.Setenv("GITHUB_ACTIONS", "no")
247250

248251
flags, opts := setupFlags("gotestsum")
249252
args := []string{

cmd/testdata/gotestsum-help-text

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ See https://pkg.go.dev/gotest.tools/gotestsum#section-readme for detailed docume
66

77
Flags:
88
--debug enabled debug logging
9-
-f, --format string print format of test input (default "short")
9+
-f, --format string print format of test input (default "pkgname")
1010
--format-hide-empty-pkg do not print empty packages in compact formats
1111
--format-hivis use high visibility characters in some formats
1212
--hide-summary summary hide sections of the summary: skipped,failed,errors,output (default none)
@@ -36,6 +36,7 @@ Formats:
3636
pkgname print a line for each package
3737
pkgname-and-test-fails print a line for each package and failed test output
3838
testname print a line for each test and package
39+
github-actions testname format with github actions log grouping
3940
standard-quiet standard go test format
4041
standard-verbose standard go test -v format
4142

testjson/execution.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,6 @@ func (e TestEvent) PackageEvent() bool {
6363
return e.Test == ""
6464
}
6565

66-
// ElapsedFormatted returns Elapsed formatted in the go test format, ex (0.00s).
67-
func (e TestEvent) ElapsedFormatted() string {
68-
return fmt.Sprintf("(%.2fs)", e.Elapsed)
69-
}
70-
7166
// Bytes returns the serialized JSON bytes that were parsed to create the event.
7267
func (e TestEvent) Bytes() []byte {
7368
return e.raw
@@ -199,7 +194,6 @@ func (p *Package) addOutput(id int, output string) {
199194
if strings.HasPrefix(output, "panic: ") {
200195
p.panicked = true
201196
}
202-
// TODO: limit size of buffered test output
203197
p.output[id] = append(p.output[id], output)
204198
}
205199

testjson/format.go

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"fmt"
66
"io"
7+
"os"
78
"strings"
89

910
"github.com/fatih/color"
@@ -73,18 +74,22 @@ func standardJSONFormat(out io.Writer) EventFormatter {
7374
})
7475
}
7576

77+
func testNameFormatTestEvent(out io.Writer, event TestEvent) {
78+
pkgPath := RelativePackagePath(event.Package)
79+
80+
fmt.Fprintf(out, "%s %s%s %s\n",
81+
colorEvent(event)(strings.ToUpper(string(event.Action))),
82+
joinPkgToTestName(pkgPath, event.Test),
83+
formatRunID(event.RunID),
84+
fmt.Sprintf("(%.2fs)", event.Elapsed))
85+
}
86+
7687
func testNameFormat(out io.Writer) EventFormatter {
7788
buf := bufio.NewWriter(out)
7889
// nolint:errcheck
7990
return eventFormatterFunc(func(event TestEvent, exec *Execution) error {
8091
formatTest := func() error {
81-
pkgPath := RelativePackagePath(event.Package)
82-
83-
fmt.Fprintf(buf, "%s %s%s %s\n",
84-
colorEvent(event)(strings.ToUpper(string(event.Action))),
85-
joinPkgToTestName(pkgPath, event.Test),
86-
formatRunID(event.RunID),
87-
event.ElapsedFormatted())
92+
testNameFormatTestEvent(buf, event)
8893
return buf.Flush()
8994
}
9095

@@ -101,6 +106,7 @@ func testNameFormat(out io.Writer) EventFormatter {
101106
result := colorEvent(event)(strings.ToUpper(string(event.Action)))
102107
pkg := exec.Package(event.Package)
103108
if event.Action == ActionSkip || (event.Action == ActionPass && pkg.Total == 0) {
109+
event.Action = ActionSkip // always color these as skip actions
104110
result = colorEvent(event)("EMPTY")
105111
}
106112

@@ -116,7 +122,7 @@ func testNameFormat(out io.Writer) EventFormatter {
116122
pkg.WriteOutputTo(buf, tc.ID)
117123
return formatTest()
118124

119-
case event.Action == ActionPass:
125+
case event.Action == ActionPass || event.Action == ActionSkip:
120126
return formatTest()
121127
}
122128
return nil
@@ -307,12 +313,77 @@ func NewEventFormatter(out io.Writer, format string, formatOpts FormatOptions) E
307313
case "dots-v2":
308314
return newDotFormatter(out, formatOpts)
309315
case "testname", "short-verbose":
316+
if os.Getenv("GITHUB_ACTIONS") == "true" {
317+
return githubActionsFormat(out)
318+
}
310319
return testNameFormat(out)
311320
case "pkgname", "short":
312321
return pkgNameFormat(out, formatOpts)
313322
case "pkgname-and-test-fails", "short-with-failures":
314323
return pkgNameWithFailuresFormat(out, formatOpts)
324+
case "github-actions", "github-action":
325+
return githubActionsFormat(out)
315326
default:
316327
return nil
317328
}
318329
}
330+
331+
func githubActionsFormat(out io.Writer) EventFormatter {
332+
buf := bufio.NewWriter(out)
333+
334+
type name struct {
335+
Package string
336+
Test string
337+
}
338+
output := map[name][]string{}
339+
340+
return eventFormatterFunc(func(event TestEvent, exec *Execution) error {
341+
key := name{Package: event.Package, Test: event.Test}
342+
343+
// test case output
344+
if event.Test != "" && event.Action == ActionOutput {
345+
if !isFramingLine(event.Output, event.Test) {
346+
output[key] = append(output[key], event.Output)
347+
}
348+
return nil
349+
}
350+
351+
// test case end event
352+
if event.Test != "" && event.Action.IsTerminal() {
353+
if len(output[key]) > 0 {
354+
buf.WriteString("::group::")
355+
} else {
356+
buf.WriteString(" ")
357+
}
358+
testNameFormatTestEvent(buf, event)
359+
360+
for _, item := range output[key] {
361+
buf.WriteString(item)
362+
}
363+
if len(output[key]) > 0 {
364+
buf.WriteString("\n::endgroup::\n")
365+
}
366+
delete(output, key)
367+
return buf.Flush()
368+
}
369+
370+
// package event
371+
if !event.Action.IsTerminal() {
372+
return nil
373+
}
374+
375+
result := colorEvent(event)(strings.ToUpper(string(event.Action)))
376+
pkg := exec.Package(event.Package)
377+
if event.Action == ActionSkip || (event.Action == ActionPass && pkg.Total == 0) {
378+
event.Action = ActionSkip // always color these as skip actions
379+
result = colorEvent(event)("EMPTY")
380+
}
381+
382+
buf.WriteString(" ")
383+
buf.WriteString(result)
384+
buf.WriteString(" Package ")
385+
buf.WriteString(packageLine(event, exec.Package(event.Package)))
386+
buf.WriteString("\n")
387+
return buf.Flush()
388+
})
389+
}

testjson/format_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ func TestFormats_DefaultGoTestJson(t *testing.T) {
132132
format: standardJSONFormat,
133133
expectedOut: "input/go-test-json.out",
134134
},
135+
{
136+
name: "github-actions",
137+
format: githubActionsFormat,
138+
expectedOut: "format/github-actions.out",
139+
},
135140
}
136141

137142
for _, tc := range testCases {

testjson/summary.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func writeTestCaseSummary(out io.Writer, execution executionSummary, conf testCa
178178
formatRunID(tc.RunID),
179179
FormatDurationAsSeconds(tc.Elapsed, 2))
180180
for _, line := range execution.OutputLines(tc) {
181-
if isFramingLine(line) || conf.filter(tc.Test.Name(), line) {
181+
if isFramingLine(line, tc.Test.Name()) {
182182
continue
183183
}
184184
fmt.Fprint(out, line)
@@ -192,7 +192,6 @@ func writeTestCaseSummary(out io.Writer, execution executionSummary, conf testCa
192192
type testCaseFormatConfig struct {
193193
header string
194194
prefix string
195-
filter func(testName string, line string) bool
196195
getter func(executionSummary) []TestCase
197196
}
198197

@@ -201,9 +200,6 @@ func formatFailed() testCaseFormatConfig {
201200
return testCaseFormatConfig{
202201
header: withColor("Failed"),
203202
prefix: withColor("FAIL"),
204-
filter: func(testName string, line string) bool {
205-
return strings.HasPrefix(line, "--- FAIL: "+testName+" ")
206-
},
207203
getter: func(execution executionSummary) []TestCase {
208204
return execution.Failed()
209205
},
@@ -215,17 +211,17 @@ func formatSkipped() testCaseFormatConfig {
215211
return testCaseFormatConfig{
216212
header: withColor("Skipped"),
217213
prefix: withColor("SKIP"),
218-
filter: func(testName string, line string) bool {
219-
return strings.HasPrefix(line, "--- SKIP: "+testName+" ")
220-
},
221214
getter: func(execution executionSummary) []TestCase {
222215
return execution.Skipped()
223216
},
224217
}
225218
}
226219

227-
func isFramingLine(line string) bool {
220+
func isFramingLine(line string, testName string) bool {
228221
return strings.HasPrefix(line, "=== RUN Test") ||
229222
strings.HasPrefix(line, "=== PAUSE Test") ||
230-
strings.HasPrefix(line, "=== CONT Test")
223+
strings.HasPrefix(line, "=== CONT Test") ||
224+
strings.HasPrefix(line, "--- FAIL: "+testName+" ") ||
225+
strings.HasPrefix(line, "--- SKIP: "+testName+" ") ||
226+
strings.HasPrefix(line, "--- PASS: "+testName+" ")
231227
}

0 commit comments

Comments
 (0)