Skip to content

Commit 0e08516

Browse files
authored
Add File in Output (#44)
1 parent 69cc216 commit 0e08516

5 files changed

Lines changed: 107 additions & 90 deletions

File tree

checker.go

Lines changed: 2 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -35,78 +35,6 @@ func RegisterChecker(name string, checker Checker) error {
3535
return nil
3636
}
3737

38-
// ValidatorOptions provide input arguments for checkers to use
39-
type ValidatorOptions struct {
40-
Directory string
41-
CodeownersFileLocation string
42-
GithubTokenType string
43-
GithubToken string
44-
}
45-
46-
// Checker provides tools for validating CODEOWNER file contents
47-
type Checker interface {
48-
NewValidator(options ValidatorOptions) Validator
49-
}
50-
51-
// Validator provides tools for validating CODEOWNER file contents
52-
type Validator interface {
53-
ValidateLine(lineNo int, line string) []CheckResult
54-
}
55-
56-
// SeverityLevel exposes all possible levels of severity check results
57-
type SeverityLevel int
58-
59-
// All possible severiy levels
60-
const (
61-
Error SeverityLevel = iota // Error serverity level
62-
Warning // Warning serverity level
63-
)
64-
65-
// String returns the string representation of this severity level
66-
func (l SeverityLevel) String() string {
67-
return [...]string{"Error", "Warning"}[l]
68-
}
69-
70-
// Position provides structured way to evaluate where a given validation result is located in the CODEOWNERs file
71-
type Position struct {
72-
FilePath string
73-
StartLine int
74-
StartColumn int
75-
EndLine int
76-
EndColumn int
77-
}
78-
79-
// String formats the position data
80-
func (p Position) String() string {
81-
output := fmt.Sprintf("%d", p.StartLine)
82-
if p.StartColumn >= 1 {
83-
output = fmt.Sprintf("%s:%d", output, p.StartColumn)
84-
}
85-
if p.EndLine > p.StartLine {
86-
output = fmt.Sprintf("%s-%d:%d", output, p.EndLine, p.EndColumn)
87-
} else if p.StartColumn >= 1 && p.EndColumn > p.StartColumn {
88-
output = fmt.Sprintf("%s-%d", output, p.EndColumn)
89-
}
90-
91-
return output
92-
}
93-
94-
// CheckResult provides structured way to evaluate results of a CODEOWNERS validation check
95-
type CheckResult struct {
96-
Position Position
97-
Message string
98-
Severity SeverityLevel
99-
CheckName string
100-
}
101-
102-
// CheckOptions provides parameters for running a list of checks
103-
type CheckOptions struct {
104-
Directory string
105-
Checkers []string
106-
GithubTokenType string
107-
GithubToken string
108-
}
109-
11038
// Check evaluates the file contents against the checkers and return the results back.
11139
func Check(options CheckOptions) ([]CheckResult, error) {
11240

@@ -177,11 +105,11 @@ func findCodeownersFile(dir string) (string, *CheckResult) {
177105
}
178106

179107
if len(filesFound) == 0 {
180-
return "", &CheckResult{Message: "No CODEOWNERS file found", Severity: Error, CheckName: "NoCodeowners"}
108+
return "", &CheckResult{Position: Position{FilePath: "CODEOWNERS"}, Message: "No CODEOWNERS file found", Severity: Error, CheckName: "NoCodeowners"}
181109
}
182110

183111
if len(filesFound) > 1 {
184-
return "", &CheckResult{Message: fmt.Sprintf("Multiple CODEOWNERS files found (%s)", strings.Join(filesFound, ", ")), Severity: Warning, CheckName: "MultipleCodeowners"}
112+
return "", &CheckResult{Position: Position{FilePath: codeownersLocation}, Message: fmt.Sprintf("Multiple CODEOWNERS files found (%s)", strings.Join(filesFound, ", ")), Severity: Warning, CheckName: "MultipleCodeowners"}
185113
}
186114

187115
return codeownersLocation, nil

checker_test.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,77 +65,83 @@ func TestRegisterCheckerAgain(t *testing.T) {
6565
}
6666

6767
func TestSeverityLevelLabels(t *testing.T) {
68-
if codeowners.Error.String() != "Error" {
68+
if codeowners.Error.Name() != "Error" {
6969
t.Errorf("codeowners.Error.String() should evaluate to 'Error'")
7070
}
71-
if codeowners.Warning.String() != "Warning" {
71+
if codeowners.Warning.Name() != "Warning" {
7272
t.Errorf("codeowners.Warning.String() should evaluate to 'Warning'")
7373
}
7474
}
7575

76-
func TestPositionString(t *testing.T) {
76+
func TestPositionFormat(t *testing.T) {
7777
testCases := []struct {
7878
input codeowners.Position
7979
want string
8080
}{
8181
{
8282
input: codeowners.Position{
83+
FilePath: "CODEOWNERS",
8384
StartLine: 1,
8485
StartColumn: 1,
8586
EndLine: 2,
8687
EndColumn: 2,
8788
},
88-
want: "1:1-2:2",
89+
want: "CODEOWNERS 1:1-2:2",
8990
},
9091
{
9192
input: codeowners.Position{
93+
FilePath: "CODEOWNERS",
9294
StartLine: 1,
9395
StartColumn: 1,
9496
EndLine: 1,
9597
EndColumn: 2,
9698
},
97-
want: "1:1-2",
99+
want: "CODEOWNERS 1:1-2",
98100
},
99101
{
100102
input: codeowners.Position{
103+
FilePath: "CODEOWNERS",
101104
StartLine: 1,
102105
StartColumn: 1,
103106
EndLine: 1,
104107
EndColumn: 1,
105108
},
106-
want: "1:1",
109+
want: "CODEOWNERS 1:1",
107110
},
108111
{
109112
input: codeowners.Position{
113+
FilePath: "CODEOWNERS",
110114
StartLine: 1,
111115
StartColumn: 0,
112116
EndLine: 1,
113117
EndColumn: 0,
114118
},
115-
want: "1",
119+
want: "CODEOWNERS 1",
116120
},
117121
{
118122
input: codeowners.Position{
123+
FilePath: "CODEOWNERS",
119124
StartLine: 1,
120125
StartColumn: 0,
121126
EndLine: 0,
122127
EndColumn: 0,
123128
},
124-
want: "1",
129+
want: "CODEOWNERS 1",
125130
},
126131
{
127132
input: codeowners.Position{
133+
FilePath: "CODEOWNERS",
128134
StartLine: 0,
129135
StartColumn: 0,
130136
EndLine: 0,
131137
EndColumn: 0,
132138
},
133-
want: "0",
139+
want: "CODEOWNERS 0",
134140
},
135141
}
136142

137143
for _, testCase := range testCases {
138-
got := testCase.input.String()
144+
got := testCase.input.Format()
139145
if got != testCase.want {
140146
t.Errorf("Input: %v, Want: %v, Got: %v", testCase.input, testCase.want, got)
141147
}
@@ -200,6 +206,9 @@ func TestNoCodeownersCheck(t *testing.T) {
200206
input := "./test/data"
201207
want := []codeowners.CheckResult{
202208
{
209+
Position: codeowners.Position{
210+
FilePath: "CODEOWNERS",
211+
},
203212
Message: "No CODEOWNERS file found",
204213
Severity: codeowners.Error,
205214
CheckName: "NoCodeowners",
@@ -222,6 +231,9 @@ func TestMultipleCodeownersCheck(t *testing.T) {
222231
input := "./test/data/multiple_codeowners"
223232
want := []codeowners.CheckResult{
224233
{
234+
Position: codeowners.Position{
235+
FilePath: "CODEOWNERS",
236+
},
225237
Message: "Multiple CODEOWNERS files found (CODEOWNERS, docs/CODEOWNERS)",
226238
Severity: codeowners.Warning,
227239
CheckName: "MultipleCodeowners",
@@ -249,8 +261,8 @@ func ExampleCheck() {
249261
panic(err)
250262
}
251263
for _, check := range checks {
252-
fmt.Printf("%s ::%s:: %s [%s]\n", check.Position, check.Severity, check.Message, check.CheckName)
264+
fmt.Printf("%s ::%s:: %s [%s]\n", check.Position.Format(), check.Severity.Name(), check.Message, check.CheckName)
253265
}
254266
//Output:
255-
//0 ::Error:: No CODEOWNERS file found [NoCodeowners]
267+
//CODEOWNERS 0 ::Error:: No CODEOWNERS file found [NoCodeowners]
256268
}

cmd/codeownerslint/linter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func run(wr io.Writer, opt options) exitCode {
3333
return unexpectedErrorCode
3434
}
3535

36-
format := "{{ .Position }} ::{{ .Severity }}:: {{ .Message }} [{{ .CheckName }}]"
36+
format := "{{ .Position.Format }} ::{{ .Severity.Name }}:: {{ .Message }} [{{ .CheckName }}]"
3737
if len(opt.format) > 0 {
3838
format = opt.format
3939
}

cmd/codeownerslint/linter_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestNoOwners(t *testing.T) {
3838
assert(t, options{
3939
directory: "../../test/data/no_owners",
4040
format: "",
41-
}, errorCode, `1 ::Error:: No owners specified [NoOwner]
41+
}, errorCode, `CODEOWNERS 1 ::Error:: No owners specified [NoOwner]
4242
`)
4343
}
4444

@@ -68,14 +68,14 @@ func TestInvalidDirectory(t *testing.T) {
6868
assert(t, options{
6969
directory: "'",
7070
format: "",
71-
}, errorCode, `0 ::Error:: No CODEOWNERS file found [NoCodeowners]
71+
}, errorCode, `CODEOWNERS 0 ::Error:: No CODEOWNERS file found [NoCodeowners]
7272
`)
7373
}
7474

7575
func TestMultipleCodeOwners(t *testing.T) {
7676
assert(t, options{
7777
directory: "../../test/data/multiple_codeowners",
7878
format: "",
79-
}, warningCode, `0 ::Warning:: Multiple CODEOWNERS files found (CODEOWNERS, docs/CODEOWNERS) [MultipleCodeowners]
79+
}, warningCode, `CODEOWNERS 0 ::Warning:: Multiple CODEOWNERS files found (CODEOWNERS, docs/CODEOWNERS) [MultipleCodeowners]
8080
`)
8181
}

types.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package codeowners
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// ValidatorOptions provide input arguments for checkers to use
8+
type ValidatorOptions struct {
9+
Directory string
10+
CodeownersFileLocation string
11+
GithubTokenType string
12+
GithubToken string
13+
}
14+
15+
// Checker provides tools for validating CODEOWNER file contents
16+
type Checker interface {
17+
NewValidator(options ValidatorOptions) Validator
18+
}
19+
20+
// Validator provides tools for validating CODEOWNER file contents
21+
type Validator interface {
22+
ValidateLine(lineNo int, line string) []CheckResult
23+
}
24+
25+
// SeverityLevel exposes all possible levels of severity check results
26+
type SeverityLevel int
27+
28+
// All possible severiy levels
29+
const (
30+
Error SeverityLevel = iota // Error serverity level
31+
Warning // Warning serverity level
32+
)
33+
34+
// Name returns the string representation of this severity level
35+
func (l SeverityLevel) Name() string {
36+
return [...]string{"Error", "Warning"}[l]
37+
}
38+
39+
// Position provides structured way to evaluate where a given validation result is located in the CODEOWNERs file
40+
type Position struct {
41+
FilePath string
42+
StartLine int
43+
StartColumn int
44+
EndLine int
45+
EndColumn int
46+
}
47+
48+
// Format converts the position data into a string
49+
func (p Position) Format() string {
50+
output := fmt.Sprintf("%s %d", p.FilePath, p.StartLine)
51+
if p.StartColumn >= 1 {
52+
output = fmt.Sprintf("%s:%d", output, p.StartColumn)
53+
}
54+
if p.EndLine > p.StartLine {
55+
output = fmt.Sprintf("%s-%d:%d", output, p.EndLine, p.EndColumn)
56+
} else if p.StartColumn >= 1 && p.EndColumn > p.StartColumn {
57+
output = fmt.Sprintf("%s-%d", output, p.EndColumn)
58+
}
59+
60+
return output
61+
}
62+
63+
// CheckResult provides structured way to evaluate results of a CODEOWNERS validation check
64+
type CheckResult struct {
65+
Position Position
66+
Message string
67+
Severity SeverityLevel
68+
CheckName string
69+
}
70+
71+
// CheckOptions provides parameters for running a list of checks
72+
type CheckOptions struct {
73+
Directory string
74+
Checkers []string
75+
GithubTokenType string
76+
GithubToken string
77+
}

0 commit comments

Comments
 (0)