Skip to content

Commit

Permalink
Fixes #33: Non-zero exit code if one or more tests failed
Browse files Browse the repository at this point in the history
  • Loading branch information
Janos Bonic committed Feb 13, 2022
1 parent b92e541 commit ae608d0
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
3 changes: 2 additions & 1 deletion cmd/gotestfmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,6 @@ func main() {
input = fh
}

format.FormatWithConfig(input, os.Stdout, cfg)
exitCode := format.FormatWithConfigAndExitCode(input, os.Stdout, cfg)
os.Exit(exitCode)
}
30 changes: 26 additions & 4 deletions gotestfmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var fs embed.FS

func New(
templateDirs []string,
) (Combined, error) {
) (CombinedExitCode, error) {
downloadsTpl := findTemplate(templateDirs, "downloads.gotpl")

packageTpl := findTemplate(templateDirs, "package.gotpl")
Expand Down Expand Up @@ -55,6 +55,12 @@ type Combined interface {
Formatter
}

// CombinedExitCode contains Combined and adds a function to format with exit code.
type CombinedExitCode interface {
Combined
FormatterExitCode
}

// GoTestFmt implements the classic Format instruction. This is no longer in use.
//
// Deprecated: please use the Formatter interface instead.
Expand All @@ -68,24 +74,40 @@ type Formatter interface {
FormatWithConfig(input io.Reader, target io.WriteCloser, cfg renderer.RenderSettings)
}

// FormatterExitCode contains an extended format function to accept render settings and returns an exit code
type FormatterExitCode interface {
FormatWithConfigAndExitCode(input io.Reader, target io.WriteCloser, cfg renderer.RenderSettings) int
}

type goTestFmt struct {
packageTpl []byte
downloadsTpl []byte
}

func (g *goTestFmt) Format(input io.Reader, target io.WriteCloser) {
g.FormatWithConfig(input, target, renderer.RenderSettings{})
g.FormatWithConfigAndExitCode(input, target, renderer.RenderSettings{})
}

func (g *goTestFmt) FormatWithConfig(input io.Reader, target io.WriteCloser, cfg renderer.RenderSettings) {
_ = g.FormatWithConfigAndExitCode(input, target, cfg)
}

func (g *goTestFmt) FormatWithConfigAndExitCode(input io.Reader, target io.WriteCloser, cfg renderer.RenderSettings) int {
tokenizerOutput := tokenizer.Tokenize(input)
prefixes, downloads, packages := parser.Parse(tokenizerOutput)
result := renderer.RenderWithSettings(prefixes, downloads, packages, g.downloadsTpl, g.packageTpl, cfg)
result, exitCodeChan := renderer.RenderWithSettingsAndExitCode(
prefixes,
downloads,
packages,
g.downloadsTpl,
g.packageTpl,
cfg,
)

for {
fragment, ok := <-result
if !ok {
return
return <-exitCodeChan
}
if _, err := target.Write(fragment); err != nil {
panic(fmt.Errorf("failed to write to output: %w", err))
Expand Down
66 changes: 66 additions & 0 deletions renderer/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,72 @@ func RenderWithSettings(
return result
}

// RenderWithSettingsAndExitCode takes the two input channels from the parser and renders them into text output
// fragments as well as an exit code.
func RenderWithSettingsAndExitCode(
prefixes <-chan string,
downloadsChannel <-chan *parser.Downloads,
packagesChannel <-chan *parser.Package,
downloadsTemplate []byte,
packagesTemplate []byte,
settings RenderSettings,
) (<-chan []byte, <-chan int) {
result := make(chan []byte)
exitCodeChan := make(chan int)
go func() {
exitCode := 0
defer func() {
close(result)
exitCodeChan <- exitCode
close(exitCodeChan)
}()
for {
prefix, ok := <-prefixes
if !ok {
break
}
result <- []byte(fmt.Sprintf("%s\n", prefix))
}

for {
downloads, ok := <-downloadsChannel
if !ok {
break
}
if downloads.Failed {
exitCode = 1
}
result <- renderTemplate(
"downloads.gotpl",
downloadsTemplate,
Downloads{
downloads,
settings,
},
)
}

for {
pkg, ok := <-packagesChannel
if !ok {
break
}
if pkg.Result == parser.ResultFail {
exitCode = 1
}
result <- renderTemplate(
"package.gotpl",
packagesTemplate,
Package{
pkg,
settings,
},
)
}
}()
return result, exitCodeChan
}

// Downloads contains the downloads for rendering.
type Downloads struct {
*parser.Downloads
Expand Down

0 comments on commit ae608d0

Please sign in to comment.