Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add post-run-command hook #76

Merged
merged 3 commits into from
May 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions contrib/notify/notify-macos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
)

func main() {
total := envInt("TOTAL")
skipped := envInt("SKIPPED")
failed := envInt("FAILED")
errors := envInt("ERRORS")

emoji := "✅"
title := "Passed"
switch {
case errors > 0:
emoji = "⚠️"
title = "Errored"
case failed > 0:
emoji = "❌"
title = "Failed"
case skipped > 0:
title = "Passed with skipped"
}

subtitle := fmt.Sprintf("%d Tests Run", total)
if errors > 0 {
subtitle += fmt.Sprintf(", %d Errored", errors)
}
if failed > 0 {
subtitle += fmt.Sprintf(", %d Failed", failed)
}
if skipped > 0 {
subtitle += fmt.Sprintf(", %d Skipped", skipped)
}

args := []string{
"-title", emoji + " " + title,
"-group", "gotestsum",
"-subtitle", subtitle,
}
log.Printf("terminal-notifier %#v", args)
err := exec.Command("terminal-notifier", args...).Run()
if err != nil {
log.Fatalf("Failed to exec: %v", err)
}
}

func envInt(name string) int {
val := os.Getenv("TESTS_" + name)
n, err := strconv.Atoi(val)
if err != nil {
return 0
}
return n
}
28 changes: 28 additions & 0 deletions flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"path"
"strings"

"github.com/google/shlex"
"github.com/pkg/errors"
"gotest.tools/gotestsum/internal/junitxml"
"gotest.tools/gotestsum/testjson"
Expand Down Expand Up @@ -84,3 +85,30 @@ func (f *junitFieldFormatValue) Value() junitxml.FormatFunc {
}
return f.value
}

type commandValue struct {
original string
command []string
}

func (c *commandValue) String() string {
return c.original
}

func (c *commandValue) Set(raw string) error {
var err error
c.command, err = shlex.Split(raw)
c.original = raw
return err
}

func (c *commandValue) Type() string {
return "command"
}

func (c *commandValue) Value() []string {
if c == nil {
return nil
}
return c.command
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module gotest.tools/gotestsum
require (
github.com/fatih/color v1.9.0
github.com/google/go-cmp v0.3.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/jonboulle/clockwork v0.1.0
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
Expand Down
29 changes: 26 additions & 3 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"
"os"
"os/exec"

"github.com/pkg/errors"
"gotest.tools/gotestsum/internal/junitxml"
Expand Down Expand Up @@ -48,14 +49,14 @@ func (h *eventHandler) Close() error {

var _ testjson.EventHandler = &eventHandler{}

func newEventHandler(opts *options, stdout io.Writer, stderr io.Writer) (*eventHandler, error) {
formatter := testjson.NewEventFormatter(stdout, opts.format)
func newEventHandler(opts *options) (*eventHandler, error) {
formatter := testjson.NewEventFormatter(opts.stdout, opts.format)
if formatter == nil {
return nil, errors.Errorf("unknown format %s", opts.format)
}
handler := &eventHandler{
formatter: formatter,
err: stderr,
err: opts.stderr,
}
var err error
if opts.jsonFile != "" {
Expand Down Expand Up @@ -86,3 +87,25 @@ func writeJUnitFile(opts *options, execution *testjson.Execution) error {
FormatTestCaseClassname: opts.junitTestCaseClassnameFormat.Value(),
})
}

func postRunHook(opts *options, execution *testjson.Execution) error {
command := opts.postRunHookCmd.Value()
if len(command) == 0 {
return nil
}

cmd := exec.Command(command[0], command[1:]...)
cmd.Stdout = opts.stdout
cmd.Stderr = opts.stderr
cmd.Env = append(
os.Environ(),
"GOTESTSUM_JSONFILE="+opts.jsonFile,
"GOTESTSUM_JUNITFILE="+opts.junitFile,
fmt.Sprintf("TESTS_TOTAL=%d", execution.Total()),
fmt.Sprintf("TESTS_FAILED=%d", len(execution.Failed())),
fmt.Sprintf("TESTS_SKIPPED=%d", len(execution.Skipped())),
fmt.Sprintf("TESTS_ERRORS=%d", len(execution.Errors())),
)
// TODO: send a more detailed report to stdin?
return cmd.Run()
}
48 changes: 48 additions & 0 deletions handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"bytes"
"os"
"strings"
"testing"

"gotest.tools/gotestsum/testjson"
"gotest.tools/v3/assert"
"gotest.tools/v3/env"
"gotest.tools/v3/golden"
)

func TestPostRunHook(t *testing.T) {
command := &commandValue{}
err := command.Set("go run ./testdata/postrunhook/main.go")
assert.NilError(t, err)

buf := new(bytes.Buffer)
opts := &options{
postRunHookCmd: command,
jsonFile: "events.json",
junitFile: "junit.xml",
stdout: buf,
}

defer env.Patch(t, "GOTESTSUM_FORMAT", "short")()

exec := newExecFromTestData(t)
err = postRunHook(opts, exec)
assert.NilError(t, err)
golden.Assert(t, buf.String(), "post-run-hook-expected")
}

func newExecFromTestData(t *testing.T) *testjson.Execution {
t.Helper()
f, err := os.Open("testjson/testdata/go-test-json.out")
assert.NilError(t, err)
defer f.Close() // nolint: errcheck

exec, err := testjson.ScanTestOutput(testjson.ScanConfig{
Stdout: f,
Stderr: strings.NewReader(""),
})
assert.NilError(t, err)
return exec
}
18 changes: 15 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func setupFlags(name string) (*pflag.FlagSet, *options) {
noSummary: newNoSummaryValue(),
junitTestCaseClassnameFormat: &junitFieldFormatValue{},
junitTestSuiteNameFormat: &junitFieldFormatValue{},
postRunHookCmd: &commandValue{},
stdout: os.Stdout,
stderr: os.Stderr,
}
flags := pflag.NewFlagSet(name, pflag.ContinueOnError)
flags.SetInterspersed(false)
Expand Down Expand Up @@ -109,6 +112,8 @@ Formats:
"format the testsuite name field as: "+junitFieldFormatValues)
flags.Var(opts.junitTestCaseClassnameFormat, "junitfile-testcase-classname",
"format the testcase classname field as: "+junitFieldFormatValues)
flags.Var(opts.postRunHookCmd, "post-run-command",
"command to run after the tests have completed")
flags.BoolVar(&opts.version, "version", false, "show version and exit")
return flags, opts
}
Expand All @@ -127,11 +132,16 @@ type options struct {
rawCommand bool
jsonFile string
junitFile string
postRunHookCmd *commandValue
noColor bool
noSummary *noSummaryValue
junitTestSuiteNameFormat *junitFieldFormatValue
junitTestCaseClassnameFormat *junitFieldFormatValue
version bool

// shims for testing
stdout io.Writer
stderr io.Writer
}

func setupLogging(opts *options) {
Expand All @@ -151,8 +161,7 @@ func run(opts *options) error {
}
defer goTestProc.cancel()

out := os.Stdout
handler, err := newEventHandler(opts, out, os.Stderr)
handler, err := newEventHandler(opts)
if err != nil {
return err
}
Expand All @@ -165,10 +174,13 @@ func run(opts *options) error {
if err != nil {
return err
}
testjson.PrintSummary(out, exec, opts.noSummary.value)
testjson.PrintSummary(opts.stdout, exec, opts.noSummary.value)
if err := writeJUnitFile(opts, exec); err != nil {
return err
}
if err := postRunHook(opts, exec); err != nil {
return err
}
return goTestProc.cmd.Wait()
}

Expand Down
7 changes: 7 additions & 0 deletions testdata/post-run-hook-expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GOTESTSUM_FORMAT=short
GOTESTSUM_JSONFILE=events.json
GOTESTSUM_JUNITFILE=junit.xml
TESTS_ERRORS=0
TESTS_FAILED=5
TESTS_SKIPPED=4
TESTS_TOTAL=46
34 changes: 34 additions & 0 deletions testdata/postrunhook/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"errors"
"fmt"
"os"
"sort"
"strings"
)

func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
}

func run() error {
environ := os.Environ()
sort.Strings(environ)
for _, v := range environ {
for _, prefix := range []string{"TESTS_", "GOTESTSUM_"} {
if strings.HasPrefix(v, prefix) {
fmt.Println(v)
}
}
}

err := os.Getenv("TEST_STUB_ERROR")
if err != "" {
return errors.New(err)
}
return nil
}