diff --git a/README.md b/README.md index 616eb541..8b5544f0 100644 --- a/README.md +++ b/README.md @@ -160,9 +160,15 @@ package may be used to parse the JSON file output. First install the example notification command with `go get gotest.tools/gotestsum/contrib/notify`. The command will be downloaded to `$GOPATH/bin` as `notify`. Note that this -example `notify` command only works on macOS with +example `notify` command only works on Linux with `notify-send` and on macOS with [terminal-notifer](https://github.com/julienXX/terminal-notifier) installed. +On Linux, you need to have some "test-pass" and "test-fail" icons installed in your icon theme. +Some sample icons can be found in `contrib/notify`, and can be installed with `make install`. + +On Windows, you can install [notify-send.exe](https://github.com/vaskovsky/notify-send) +but it does not support custom icons so will have to use the basic "info" and "error". + ``` gotestsum --post-run-command notify ``` diff --git a/cmd/handler.go b/cmd/handler.go index c5159a53..0da218d5 100644 --- a/cmd/handler.go +++ b/cmd/handler.go @@ -161,6 +161,7 @@ func postRunHook(opts *options, execution *testjson.Execution) error { if len(command) == 0 { return nil } + log.Debugf("exec: %s", command) cmd := exec.Command(command[0], command[1:]...) cmd.Stdout = opts.stdout diff --git a/contrib/notify/.gitignore b/contrib/notify/.gitignore new file mode 100644 index 00000000..f3b695d3 --- /dev/null +++ b/contrib/notify/.gitignore @@ -0,0 +1 @@ +notify diff --git a/contrib/notify/Makefile b/contrib/notify/Makefile new file mode 100644 index 00000000..73771c64 --- /dev/null +++ b/contrib/notify/Makefile @@ -0,0 +1,13 @@ +GO = go +INSTALL = install + +ICONS = icons/test-pass.svg icons/test-fail.svg +ICONDIR = $(HOME)/.icons # or /usr/share/icons + +build: + $(GO) build + +install: $(ICONS) + $(GO) install + $(INSTALL) -d $(ICONDIR) + $(INSTALL) $^ $(ICONDIR) diff --git a/contrib/notify/icons/README.html b/contrib/notify/icons/README.html new file mode 100644 index 00000000..4512a24e --- /dev/null +++ b/contrib/notify/icons/README.html @@ -0,0 +1 @@ +Pass Fail Vectors by Vecteezy diff --git a/contrib/notify/icons/test-fail.svg b/contrib/notify/icons/test-fail.svg new file mode 100644 index 00000000..f6b97c74 --- /dev/null +++ b/contrib/notify/icons/test-fail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contrib/notify/icons/test-pass.svg b/contrib/notify/icons/test-pass.svg new file mode 100644 index 00000000..2e96bdaf --- /dev/null +++ b/contrib/notify/icons/test-pass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contrib/notify/notify-macos.go b/contrib/notify/notify_darwin.go similarity index 85% rename from contrib/notify/notify-macos.go rename to contrib/notify/notify_darwin.go index 3f6822ca..ad683898 100644 --- a/contrib/notify/notify-macos.go +++ b/contrib/notify/notify_darwin.go @@ -43,9 +43,11 @@ func main() { "-group", "gotestsum", "-subtitle", subtitle, } - log.Printf("terminal-notifier %#v", args) - err := exec.Command("terminal-notifier", args...).Run() - if err != nil { + cmd := exec.Command("terminal-notifier", args...) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { log.Fatalf("Failed to exec: %v", err) } } diff --git a/contrib/notify/notify_linux.go b/contrib/notify/notify_linux.go new file mode 100644 index 00000000..8da6c3e8 --- /dev/null +++ b/contrib/notify/notify_linux.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" +) + +func main() { + total := envInt("TOTAL") + skipped := envInt("SKIPPED") + failed := envInt("FAILED") + errors := envInt("ERRORS") + + icon := "test-pass" + title := "Passed" + switch { + case errors > 0: + icon = "dialog-warning" + title = "Errored" + case failed > 0: + icon = "test-fail" + 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) + } + + cmd := exec.Command("notify-send", "--icon", icon, title, subtitle) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); 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 +} diff --git a/contrib/notify/notify_windows.go b/contrib/notify/notify_windows.go new file mode 100644 index 00000000..f3d384d5 --- /dev/null +++ b/contrib/notify/notify_windows.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" +) + +func main() { + total := envInt("TOTAL") + skipped := envInt("SKIPPED") + failed := envInt("FAILED") + errors := envInt("ERRORS") + + icon := "info" // Info 🛈 + title := "Passed" + switch { + case errors > 0: + icon = "important" // Warning ⚠ + title = "Errored" + case failed > 0: + icon = "error" // Error ⮾ + 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) + } + + cmd := exec.Command("notify-send.exe", "-i", icon, title, subtitle) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); 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 +}