From 4abc311f1055fca5be5cf29ccb5a4d2a69f9f416 Mon Sep 17 00:00:00 2001 From: "Kazuma (Pakio) Arimura" Date: Mon, 30 Dec 2024 22:51:46 +0000 Subject: [PATCH] feat: add new output type: json Signed-off-by: Kazuma (Pakio) Arimura --- cmd/argo/commands/lint.go | 2 +- cmd/argo/lint/formatter_json.go | 56 ++++++++++++++++++++++++++++ cmd/argo/lint/formatter_json_test.go | 50 +++++++++++++++++++++++++ cmd/argo/lint/lint.go | 1 + cmd/argo/lint/lint_test.go | 5 +++ docs/cli/argo_lint.md | 2 +- 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 cmd/argo/lint/formatter_json.go create mode 100644 cmd/argo/lint/formatter_json_test.go diff --git a/cmd/argo/commands/lint.go b/cmd/argo/commands/lint.go index 643c4a39f6e9..792382d6cf13 100644 --- a/cmd/argo/commands/lint.go +++ b/cmd/argo/commands/lint.go @@ -21,7 +21,7 @@ func NewLintCommand() *cobra.Command { strict bool lintKinds []string output = common.EnumFlagValue{ - AllowedValues: []string{"pretty", "simple"}, + AllowedValues: []string{"pretty", "simple", "json"}, Value: "pretty", } offline bool diff --git a/cmd/argo/lint/formatter_json.go b/cmd/argo/lint/formatter_json.go new file mode 100644 index 000000000000..0d8b2d69da96 --- /dev/null +++ b/cmd/argo/lint/formatter_json.go @@ -0,0 +1,56 @@ +package lint + +import ( + "encoding/json" + "fmt" +) + +// JsonLintResult is the intermediate struct to convert result to json +type JsonLintResult struct { + File string `json:"file"` + ErrsStr []string `json:"errors"` + Linted bool `json:"linted"` +} + +// JsonLintResults is the intermediate struct to convert results to json +type JsonLintResults struct { + Results []*JsonLintResult `json:"results"` + Success bool `json:"success"` + AnythingLinted bool `json:"anything_linted"` +} + +type formatterJson struct{} + +func (f formatterJson) Format(l *LintResult) string { + return "" +} + +func (f formatterJson) Summarize(l *LintResults) string { + b, err := json.Marshal(toJsonResultStruct(l)) + if err != nil { + return fmt.Sprintf("Failed to marshal results to JSON: %e", err) + } + return string(b) +} + +func toJsonResultStruct(l *LintResults) *JsonLintResults { + jsonLintResults := &JsonLintResults{ + Results: make([]*JsonLintResult, len(l.Results)), + Success: l.Success, + AnythingLinted: l.anythingLinted, + } + + for i, lr := range l.Results { + errStrs := make([]string, len(lr.Errs)) + for j, err := range lr.Errs { + errStrs[j] = err.Error() + } + jsonLintResults.Results[i] = &JsonLintResult{ + File: lr.File, + Linted: lr.Linted, + ErrsStr: errStrs, + } + } + + return jsonLintResults +} diff --git a/cmd/argo/lint/formatter_json_test.go b/cmd/argo/lint/formatter_json_test.go new file mode 100644 index 000000000000..7b3d20053b71 --- /dev/null +++ b/cmd/argo/lint/formatter_json_test.go @@ -0,0 +1,50 @@ +package lint + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestJsonSummarize(t *testing.T) { + t.Run("Success", func(t *testing.T) { + msg := formatterJson{}.Summarize(&LintResults{ + Success: true, + Results: []*LintResult{ + { + File: "test1", + Errs: []error{ + fmt.Errorf("some error"), + }, + Linted: true, + }, + }, + }) + expected := "{\"results\":[{\"file\":\"test1\",\"errors\":[\"some error\"],\"linted\":true}],\"success\":true,\"anything_linted\":false}" + assert.Equal(t, expected, msg) + }) + t.Run("Nothing linted", func(t *testing.T) { + msg := formatterJson{}.Summarize(&LintResults{ + anythingLinted: false, + Success: false, + }) + expected := "{\"results\":[],\"success\":false,\"anything_linted\":false}" + assert.Equal(t, expected, msg) + }) +} + +func TestJsonFormat(t *testing.T) { + t.Run("Error Exists", func(t *testing.T) { + msg := formatterJson{}.Format(&LintResult{ + File: "test1", + Errs: []error{ + fmt.Errorf("some error"), + fmt.Errorf("some error2"), + }, + Linted: true, + }) + expected := "" + assert.Equal(t, expected, msg) + }) +} diff --git a/cmd/argo/lint/lint.go b/cmd/argo/lint/lint.go index dc7c9c8d9d32..10b4f6782287 100644 --- a/cmd/argo/lint/lint.go +++ b/cmd/argo/lint/lint.go @@ -66,6 +66,7 @@ var ( formatters = map[string]Formatter{ "pretty": formatterPretty{}, "simple": formatterSimple{}, + "json": formatterJson{}, } ) diff --git a/cmd/argo/lint/lint_test.go b/cmd/argo/lint/lint_test.go index 71fda3c4101f..d4a1bb386241 100644 --- a/cmd/argo/lint/lint_test.go +++ b/cmd/argo/lint/lint_test.go @@ -271,6 +271,11 @@ func TestGetFormatter(t *testing.T) { expectedErr: nil, expectedOutput: (&LintResults{fmtr: formatterSimple{}}).buildMsg(), }, + "json": { + formatterName: "json", + expectedErr: nil, + expectedOutput: (&LintResults{fmtr: formatterJson{}}).buildMsg(), + }, "unknown name": { formatterName: "foo", expectedErr: fmt.Errorf("unknown formatter: foo"), diff --git a/docs/cli/argo_lint.md b/docs/cli/argo_lint.md index 0a3bed86fd61..60730423a135 100644 --- a/docs/cli/argo_lint.md +++ b/docs/cli/argo_lint.md @@ -26,7 +26,7 @@ argo lint FILE... [flags] --kinds strings Which kinds will be linted. Can be: workflows|workflowtemplates|cronworkflows|clusterworkflowtemplates (default [all]) --no-color Disable colorized output --offline perform offline linting. For resources referencing other resources, the references will be resolved from the provided args - -o, --output string Linting results output format. One of: pretty|simple (default "pretty") + -o, --output string Linting results output format. One of: pretty|simple|json (default "pretty") --strict Perform strict workflow validation (default true) ```