Skip to content

Commit

Permalink
Print all results in JSON regardless of -a setting
Browse files Browse the repository at this point in the history
  • Loading branch information
ribbybibby committed Mar 30, 2023
1 parent eb2c506 commit 0754a15
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 154 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ $ tally -o json bom.json | jq -r .

Not all packages will have a Scorecard score.

By default, `tally` will remove results without a score from the output.
By default, `tally` will remove results without a score from the output when
using `-o short` or `-o wide`.

You can include all results, regardless of whether they have a score or not, by
specifying the `-a/--all` flag.
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var rootCmd = &cobra.Command{

// Configure the output writer
out, err := output.NewOutput(
output.WithFormat(output.Format(ro.Output)),
output.Format(ro.Output),
output.WithAll(ro.All),
)
if err != nil {
Expand Down
100 changes: 0 additions & 100 deletions internal/output/format.go

This file was deleted.

32 changes: 0 additions & 32 deletions internal/output/options.go

This file was deleted.

131 changes: 111 additions & 20 deletions internal/output/output.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,87 @@
package output

import (
"encoding/json"
"errors"
"fmt"
"io"
"sort"
"text/tabwriter"

"github.com/jetstack/tally/internal/types"
)

// ErrUnsupportedOutputFormat is returned when an output is requested by string that
// this package doesn't implement.
var ErrUnsupportedFormat = errors.New("unsupported output")

// Format is a supported output format
type Format string

const (
// FormatShort prints the repositories and their scores.
FormatShort Format = "short"

// FormatWide prints the package version information, as well as
// the repositories and their scores.
FormatWide Format = "wide"

// FormatJSON prints the report as a JSON document
FormatJSON Format = "json"
)

// Formats are the supported output formats
var Formats = []Format{
FormatShort,
FormatWide,
FormatJSON,
}

// Option is a functional option that configures the output behaviour
type Option func(*output)

// WithAll is a functional option that configures outputs to return all
// packages, even if they don't have a scorecard score
func WithAll(all bool) Option {
return func(o *output) {
o.all = all
}
}

// Output writes output for tally
type Output interface {
WriteReport(io.Writer, types.Report) error
}

// NewOutput returns a new output, configured by the provided options
func NewOutput(opts ...Option) (Output, error) {
o := &output{
writer: writeShort,
}
func NewOutput(format Format, opts ...Option) (Output, error) {
o := &output{}
for _, opt := range opts {
if err := opt(o); err != nil {
return nil, err
}
opt(o)
}

switch format {
case FormatShort:
o.writer = o.writeShort
case FormatWide:
o.writer = o.writeWide
case FormatJSON:
o.writer = o.writeJSON
default:
return nil, fmt.Errorf("%s: %w", format, ErrUnsupportedFormat)
}

return o, nil
}

type output struct {
all bool
writer writer
writer func(io.Writer, types.Report) error
}

// WriteReport writes the report to the given io.Writer in the
// configured output format
func (o *output) WriteReport(w io.Writer, report types.Report) error {
// Unless -a is configured, ignore packages without a score
if !o.all {
r := []types.Result{}
for _, result := range report.Results {
if result.Result == nil {
continue
}
r = append(r, result)
}
report.Results = r
}

// Sort the results by score
sort.Slice(report.Results, func(i, j int) bool {
var (
Expand All @@ -70,3 +106,58 @@ func (o *output) WriteReport(w io.Writer, report types.Report) error {

return o.writer(w, report)
}

func (o *output) writeShort(w io.Writer, report types.Report) error {
tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
defer tw.Flush()
fmt.Fprintf(tw, "REPOSITORY\tSCORE\n")

printed := map[string]struct{}{}
for _, result := range report.Results {
if result.Repository.Name == "" {
continue
}
if _, ok := printed[result.Repository.Name]; ok {
continue
}
if result.Result != nil {
fmt.Fprintf(tw, "%s\t%.1f\n", result.Repository.Name, result.Result.Score)
} else if o.all {
fmt.Fprintf(tw, "%s\t%s\n", result.Repository.Name, " ")
}
printed[result.Repository.Name] = struct{}{}
}

return nil
}

func (o *output) writeWide(w io.Writer, report types.Report) error {
tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
defer tw.Flush()
fmt.Fprintf(tw, "TYPE\tPACKAGE\tREPOSITORY\tSCORE\n")

for _, result := range report.Results {
for _, pkg := range result.Packages {
if result.Result != nil {
fmt.Fprintf(tw, "%s\t%s\t%s\t%.1f\n", pkg.Type, pkg.Name, result.Repository.Name, result.Result.Score)
} else if o.all {
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", pkg.Type, pkg.Name, result.Repository.Name, " ")
}
}
}

return nil
}

func (o *output) writeJSON(w io.Writer, report types.Report) error {
data, err := json.Marshal(report)
if err != nil {
return nil
}

if _, err := w.Write(data); err != nil {
return err
}

return nil
}

0 comments on commit 0754a15

Please sign in to comment.