Skip to content

Commit b86206d

Browse files
authored
fix: support duplicate reporter outputs (#481)
1 parent 60bc076 commit b86206d

5 files changed

Lines changed: 41 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
### Fixed
2424

25+
- Repeating the same `--reporter` type with different output paths now writes each requested output.
2526
- KnownFiles now take priority over extension matching in the finder, so `tsconfig.json` resolves to JSONC (not JSON)
2627
- Extension exclusion cache no longer prevents known files from being found
2728
- Linguist known files that conflict with dedicated validators are automatically excluded (e.g. `.editorconfig` stays with EditorConfig, not INI)

cmd/validator/testdata/reporters.txtar

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ exec validator --reporter=json:multi.json --reporter=standard:- good.json
2626
stdout '✓'
2727
exists multi.json
2828

29+
# Duplicate reporter type to separate files
30+
exec validator --reporter=json:first.json --reporter=json:second.json good.json
31+
exists first.json
32+
exists second.json
33+
34+
# Duplicate reporter type to the same file leaves one valid report
35+
exec validator --reporter=json:same.json --reporter=json:same.json good.json
36+
exists same.json
37+
exec validator same.json
38+
stdout '✓'
39+
2940
# Invalid reporter
3041
! exec validator --reporter=bad good.json
3142

cmd/validator/validator.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ type validatorConfig struct {
6464
excludeDirs *string
6565
excludeFileTypes *string
6666
fileTypes *string
67-
reportType map[string]string
67+
reportType []reporterConfig
6868
depth *int
6969
versionQuery *bool
7070
groupOutput *string
@@ -83,6 +83,11 @@ type validatorConfig struct {
8383

8484
type reporterFlags []string
8585

86+
type reporterConfig struct {
87+
reportType string
88+
outputDest string
89+
}
90+
8691
func (rf *reporterFlags) String() string {
8792
return fmt.Sprint(*rf)
8893
}
@@ -286,7 +291,7 @@ func getFlags(args []string) (validatorConfig, error) {
286291
return config, nil
287292
}
288293

289-
func validateFlagValues(excludeFileTypesPtr, fileTypesPtr *string, depthPtr *int, reporterConf map[string]string, groupOutputPtr *string) error {
294+
func validateFlagValues(excludeFileTypesPtr, fileTypesPtr *string, depthPtr *int, reporterConf []reporterConfig, groupOutputPtr *string) error {
290295
if err := validateReporterConf(reporterConf, groupOutputPtr); err != nil {
291296
return err
292297
}
@@ -321,17 +326,17 @@ func validateFileTypeFlags(excludeFileTypesPtr, fileTypesPtr *string) error {
321326
return nil
322327
}
323328

324-
func validateReporterConf(conf map[string]string, groupBy *string) error {
329+
func validateReporterConf(conf []reporterConfig, groupBy *string) error {
325330
acceptedReportTypes := map[string]bool{"standard": true, "json": true, "junit": true, "sarif": true, "github": true}
326331
groupOutputReportTypes := map[string]bool{"standard": true, "json": true}
327332

328-
for reportType := range conf {
329-
_, ok := acceptedReportTypes[reportType]
333+
for _, reporterConf := range conf {
334+
_, ok := acceptedReportTypes[reporterConf.reportType]
330335
if !ok {
331336
return errors.New("wrong parameter value for reporter, only supports standard, json, junit, sarif, or github")
332337
}
333338

334-
if !groupOutputReportTypes[reportType] && groupBy != nil && *groupBy != "" {
339+
if !groupOutputReportTypes[reporterConf.reportType] && groupBy != nil && *groupBy != "" {
335340
return errors.New("wrong parameter value for reporter, groupby is only supported for standard and JSON reports")
336341
}
337342
}
@@ -397,26 +402,26 @@ func handleGlobbing(searchPaths []string) ([]string, error) {
397402
return searchPaths, nil
398403
}
399404

400-
func parseReporterFlags(flags reporterFlags) (map[string]string, error) {
401-
conf := make(map[string]string)
405+
func parseReporterFlags(flags reporterFlags) ([]reporterConfig, error) {
406+
conf := make([]reporterConfig, 0, len(flags))
402407
for _, reportFlag := range flags {
403-
parts := strings.Split(reportFlag, ":")
408+
parts := strings.SplitN(reportFlag, ":", 2)
404409
switch len(parts) {
405410
case 1:
406-
conf[parts[0]] = ""
411+
conf = append(conf, reporterConfig{reportType: parts[0]})
407412
case 2:
408413
if parts[1] == "-" {
409-
conf[parts[0]] = ""
414+
conf = append(conf, reporterConfig{reportType: parts[0]})
410415
} else {
411-
conf[parts[0]] = parts[1]
416+
conf = append(conf, reporterConfig{reportType: parts[0], outputDest: parts[1]})
412417
}
413418
default:
414419
return nil, errors.New("wrong parameter value format for reporter, expected format is `report_type:optional_file_path`")
415420
}
416421
}
417422

418423
if len(conf) == 0 {
419-
conf["standard"] = ""
424+
conf = append(conf, reporterConfig{reportType: "standard"})
420425
}
421426

422427
return conf, nil
@@ -642,10 +647,10 @@ func buildCLI(rc *resolvedConfig) *cli.CLI {
642647
return cli.Init(opts...)
643648
}
644649

645-
func buildReporters(reportType map[string]string) ([]reporter.Reporter, error) {
646-
reporters := make([]reporter.Reporter, 0, len(reportType))
647-
for rt, of := range reportType {
648-
reporters = append(reporters, getReporter(rt, of))
650+
func buildReporters(reporterConfigs []reporterConfig) ([]reporter.Reporter, error) {
651+
reporters := make([]reporter.Reporter, 0, len(reporterConfigs))
652+
for _, rc := range reporterConfigs {
653+
reporters = append(reporters, getReporter(rc.reportType, rc.outputDest))
649654
}
650655
return reporters, nil
651656
}

cmd/validator/validator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func Test_getFlags(t *testing.T) {
3333
// Invalid flag combinations
3434
{"negative depth", []string{"-depth=-1", "."}, true},
3535
{"wrong reporter", []string{"--reporter=wrong", "."}, true},
36-
{"bad reporter format", []string{"--reporter", "json:/a:/b", "."}, true},
36+
{"reporter output path with colon", []string{"--reporter", "json:/a:/b", "."}, false},
3737
{"invalid groupby", []string{"-groupby=badgroup", "."}, true},
3838
{"groupby duplicate", []string{"--groupby=directory,directory", "."}, true},
3939
{"grouped junit", []string{"-groupby=directory", "--reporter=junit", "."}, true},

website/docs/guides/output-reporters.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ Append `:<path>` to the reporter name to write results to a file:
2828
validator --reporter=json:output.json .
2929
```
3030

31+
Repeat the same reporter type with different paths to write the same format to more than one file:
32+
33+
```shell
34+
validator --reporter=json:summary.json --reporter=json:artifacts/summary.json .
35+
```
36+
3137
Use `:-` to explicitly direct output to stdout (useful when combining reporters):
3238

3339
```shell

0 commit comments

Comments
 (0)