Skip to content
Open
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
98 changes: 98 additions & 0 deletions cobrax/reportx/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package reportx

import (
"fmt"
"io"
"os"

"github.com/cerberauth/reportx/format"
"github.com/cerberauth/reportx/transport"
"github.com/spf13/cobra"
)

// RegisterFormatFlags binds --format, --output, and --no-color to cmd.
func RegisterFormatFlags(cmd *cobra.Command) {
cmd.Flags().String("format", string(format.FormatTerminal),
fmt.Sprintf("output format: %s", formatChoices()))
cmd.Flags().String("output", "",
"file path to write the report (stdout if empty)")
cmd.Flags().Bool("no-color", false,
"disable ANSI colors in terminal output")
}

// RegisterTransportFlags binds --report-url and --report-header to cmd.
func RegisterTransportFlags(cmd *cobra.Command) {
cmd.Flags().String("report-url", "",
"HTTP endpoint to POST the report to")
cmd.Flags().StringToString("report-header", nil,
"additional HTTP headers for the report transport (key=value)")
}

// FormatterFromFlags reads --format and --no-color and returns a Formatter.
func FormatterFromFlags(cmd *cobra.Command) (format.Formatter, error) {
f, err := cmd.Flags().GetString("format")
if err != nil {
return nil, err
}
noColor, err := cmd.Flags().GetBool("no-color")
if err != nil {
return nil, err
}
if (format.FormatName(f) == format.FormatTerminal || f == "text" || f == "plain") && noColor {
return format.NewTerminalFormatterNoColor(), nil
}
return format.NewFormatter(f)
}

// WriterFromFlags opens the destination specified by --output (stdout if empty).
// The caller must invoke the returned cleanup func when done.
func WriterFromFlags(cmd *cobra.Command) (io.Writer, func(), error) {
path, err := cmd.Flags().GetString("output")
if err != nil {
return nil, nil, err
}
if path == "" {
return os.Stdout, func() {}, nil
}
file, err := os.Create(path)
if err != nil {
return nil, nil, fmt.Errorf("reportx: create output file: %w", err)
}
return file, func() { file.Close() }, nil
}

// HTTPTransportFromFlags builds an HTTPTransport from --report-url and --report-header.
// Returns nil, nil when --report-url is not set.
func HTTPTransportFromFlags(cmd *cobra.Command) (*transport.HTTPTransport, error) {
url, err := cmd.Flags().GetString("report-url")
if err != nil {
return nil, err
}
if url == "" {
return nil, nil
}
headers, err := cmd.Flags().GetStringToString("report-header")
if err != nil {
return nil, err
}
t := transport.NewHTTPTransport(url)
if len(headers) > 0 {
t.Headers = headers
}
return t, nil
}

func formatChoices() string {
names := make([]string, len(format.FormatNames))
for i, n := range format.FormatNames {
names[i] = string(n)
}
result := ""
for i, n := range names {
if i > 0 {
result += " | "
}
result += n
}
return result
}
129 changes: 129 additions & 0 deletions cobrax/reportx/flags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package reportx_test

import (
"testing"

"github.com/cerberauth/reportx/format"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

cobrareportx "github.com/cerberauth/x/cobrax/reportx"
)

func newCmd() *cobra.Command {
cmd := &cobra.Command{Use: "test"}
cobrareportx.RegisterFormatFlags(cmd)
cobrareportx.RegisterTransportFlags(cmd)
return cmd
}

func TestFormatterFromFlags_DefaultTerminal(t *testing.T) {
cmd := newCmd()
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "text/plain", f.MediaType())
}

func TestFormatterFromFlags_JSON(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("format", "json"))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "application/json", f.MediaType())
}

func TestFormatterFromFlags_SARIF(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("format", "sarif"))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "application/sarif+json", f.MediaType())
}

func TestFormatterFromFlags_Markdown(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("format", "markdown"))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "text/markdown", f.MediaType())
}

func TestFormatterFromFlags_HTML(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("format", "html"))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "text/html", f.MediaType())
}

func TestFormatterFromFlags_NoColor(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("no-color", "true"))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err)
assert.Equal(t, "text/plain", f.MediaType())
}

func TestFormatterFromFlags_Unknown(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("format", "bogus"))
_, err := cobrareportx.FormatterFromFlags(cmd)
assert.Error(t, err)
}

func TestWriterFromFlags_Stdout(t *testing.T) {
cmd := newCmd()
w, cleanup, err := cobrareportx.WriterFromFlags(cmd)
require.NoError(t, err)
defer cleanup()
assert.NotNil(t, w)
}

func TestWriterFromFlags_File(t *testing.T) {
cmd := newCmd()
path := t.TempDir() + "/report.json"
require.NoError(t, cmd.Flags().Set("output", path))
w, cleanup, err := cobrareportx.WriterFromFlags(cmd)
require.NoError(t, err)
defer cleanup()
assert.NotNil(t, w)
}

func TestHTTPTransportFromFlags_NoURL(t *testing.T) {
cmd := newCmd()
tr, err := cobrareportx.HTTPTransportFromFlags(cmd)
require.NoError(t, err)
assert.Nil(t, tr)
}

func TestHTTPTransportFromFlags_WithURL(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("report-url", "https://example.com/reports"))
tr, err := cobrareportx.HTTPTransportFromFlags(cmd)
require.NoError(t, err)
require.NotNil(t, tr)
assert.Equal(t, "https://example.com/reports", tr.URL)
}

func TestHTTPTransportFromFlags_WithHeaders(t *testing.T) {
cmd := newCmd()
require.NoError(t, cmd.Flags().Set("report-url", "https://example.com/reports"))
require.NoError(t, cmd.Flags().Set("report-header", "Authorization=Bearer tok"))
tr, err := cobrareportx.HTTPTransportFromFlags(cmd)
require.NoError(t, err)
require.NotNil(t, tr)
assert.Equal(t, "Bearer tok", tr.Headers["Authorization"])
}

func TestRegisterFormatFlags_AllFormatsRegistered(t *testing.T) {
cmd := newCmd()
flag := cmd.Flags().Lookup("format")
require.NotNil(t, flag)
for _, name := range format.FormatNames {
require.NoError(t, cmd.Flags().Set("format", string(name)))
f, err := cobrareportx.FormatterFromFlags(cmd)
require.NoError(t, err, "format %s should be valid", name)
assert.NotNil(t, f)
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.26.0

require (
github.com/cerberauth/harnessx v0.1.1
github.com/cerberauth/reportx v0.0.0-00010101000000-000000000000
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
go.opentelemetry.io/otel v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.20.0
Expand All @@ -26,6 +28,7 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
Expand Down
Loading