diff --git a/CHANGELOG.md b/CHANGELOG.md index e5885d25..8672010c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Repeating the same `--reporter` type with different output paths now writes each requested output. - KnownFiles now take priority over extension matching in the finder, so `tsconfig.json` resolves to JSONC (not JSON) - Extension exclusion cache no longer prevents known files from being found - Linguist known files that conflict with dedicated validators are automatically excluded (e.g. `.editorconfig` stays with EditorConfig, not INI) diff --git a/cmd/validator/testdata/reporters.txtar b/cmd/validator/testdata/reporters.txtar index 38b6e389..45258044 100644 --- a/cmd/validator/testdata/reporters.txtar +++ b/cmd/validator/testdata/reporters.txtar @@ -26,6 +26,17 @@ exec validator --reporter=json:multi.json --reporter=standard:- good.json stdout '✓' exists multi.json +# Duplicate reporter type to separate files +exec validator --reporter=json:first.json --reporter=json:second.json good.json +exists first.json +exists second.json + +# Duplicate reporter type to the same file leaves one valid report +exec validator --reporter=json:same.json --reporter=json:same.json good.json +exists same.json +exec validator same.json +stdout '✓' + # Invalid reporter ! exec validator --reporter=bad good.json diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 6598618b..45679082 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -64,7 +64,7 @@ type validatorConfig struct { excludeDirs *string excludeFileTypes *string fileTypes *string - reportType map[string]string + reportType []reporterConfig depth *int versionQuery *bool groupOutput *string @@ -83,6 +83,11 @@ type validatorConfig struct { type reporterFlags []string +type reporterConfig struct { + reportType string + outputDest string +} + func (rf *reporterFlags) String() string { return fmt.Sprint(*rf) } @@ -286,7 +291,7 @@ func getFlags(args []string) (validatorConfig, error) { return config, nil } -func validateFlagValues(excludeFileTypesPtr, fileTypesPtr *string, depthPtr *int, reporterConf map[string]string, groupOutputPtr *string) error { +func validateFlagValues(excludeFileTypesPtr, fileTypesPtr *string, depthPtr *int, reporterConf []reporterConfig, groupOutputPtr *string) error { if err := validateReporterConf(reporterConf, groupOutputPtr); err != nil { return err } @@ -321,17 +326,17 @@ func validateFileTypeFlags(excludeFileTypesPtr, fileTypesPtr *string) error { return nil } -func validateReporterConf(conf map[string]string, groupBy *string) error { +func validateReporterConf(conf []reporterConfig, groupBy *string) error { acceptedReportTypes := map[string]bool{"standard": true, "json": true, "junit": true, "sarif": true, "github": true} groupOutputReportTypes := map[string]bool{"standard": true, "json": true} - for reportType := range conf { - _, ok := acceptedReportTypes[reportType] + for _, reporterConf := range conf { + _, ok := acceptedReportTypes[reporterConf.reportType] if !ok { return errors.New("wrong parameter value for reporter, only supports standard, json, junit, sarif, or github") } - if !groupOutputReportTypes[reportType] && groupBy != nil && *groupBy != "" { + if !groupOutputReportTypes[reporterConf.reportType] && groupBy != nil && *groupBy != "" { return errors.New("wrong parameter value for reporter, groupby is only supported for standard and JSON reports") } } @@ -397,18 +402,18 @@ func handleGlobbing(searchPaths []string) ([]string, error) { return searchPaths, nil } -func parseReporterFlags(flags reporterFlags) (map[string]string, error) { - conf := make(map[string]string) +func parseReporterFlags(flags reporterFlags) ([]reporterConfig, error) { + conf := make([]reporterConfig, 0, len(flags)) for _, reportFlag := range flags { - parts := strings.Split(reportFlag, ":") + parts := strings.SplitN(reportFlag, ":", 2) switch len(parts) { case 1: - conf[parts[0]] = "" + conf = append(conf, reporterConfig{reportType: parts[0]}) case 2: if parts[1] == "-" { - conf[parts[0]] = "" + conf = append(conf, reporterConfig{reportType: parts[0]}) } else { - conf[parts[0]] = parts[1] + conf = append(conf, reporterConfig{reportType: parts[0], outputDest: parts[1]}) } default: return nil, errors.New("wrong parameter value format for reporter, expected format is `report_type:optional_file_path`") @@ -416,7 +421,7 @@ func parseReporterFlags(flags reporterFlags) (map[string]string, error) { } if len(conf) == 0 { - conf["standard"] = "" + conf = append(conf, reporterConfig{reportType: "standard"}) } return conf, nil @@ -642,10 +647,10 @@ func buildCLI(rc *resolvedConfig) *cli.CLI { return cli.Init(opts...) } -func buildReporters(reportType map[string]string) ([]reporter.Reporter, error) { - reporters := make([]reporter.Reporter, 0, len(reportType)) - for rt, of := range reportType { - reporters = append(reporters, getReporter(rt, of)) +func buildReporters(reporterConfigs []reporterConfig) ([]reporter.Reporter, error) { + reporters := make([]reporter.Reporter, 0, len(reporterConfigs)) + for _, rc := range reporterConfigs { + reporters = append(reporters, getReporter(rc.reportType, rc.outputDest)) } return reporters, nil } diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go index 27eaa38c..53595e8f 100644 --- a/cmd/validator/validator_test.go +++ b/cmd/validator/validator_test.go @@ -33,7 +33,7 @@ func Test_getFlags(t *testing.T) { // Invalid flag combinations {"negative depth", []string{"-depth=-1", "."}, true}, {"wrong reporter", []string{"--reporter=wrong", "."}, true}, - {"bad reporter format", []string{"--reporter", "json:/a:/b", "."}, true}, + {"reporter output path with colon", []string{"--reporter", "json:/a:/b", "."}, false}, {"invalid groupby", []string{"-groupby=badgroup", "."}, true}, {"groupby duplicate", []string{"--groupby=directory,directory", "."}, true}, {"grouped junit", []string{"-groupby=directory", "--reporter=junit", "."}, true}, diff --git a/website/docs/guides/output-reporters.md b/website/docs/guides/output-reporters.md index 483a221a..8bf3fbc7 100644 --- a/website/docs/guides/output-reporters.md +++ b/website/docs/guides/output-reporters.md @@ -28,6 +28,12 @@ Append `:` to the reporter name to write results to a file: validator --reporter=json:output.json . ``` +Repeat the same reporter type with different paths to write the same format to more than one file: + +```shell +validator --reporter=json:summary.json --reporter=json:artifacts/summary.json . +``` + Use `:-` to explicitly direct output to stdout (useful when combining reporters): ```shell