Repository: googleapis/api-linter
Pull request #1002 (2022-08-19 22:05:36)

fix: not all findings have column info
Turns out that real lint errors can come in many forms. This now only
prints out the information that is present instead of out of bounds
`panic`ing.


Patch:
diff --git a/cmd/api-linter/github_actions.go b/cmd/api-linter/github_actions.go
index 2edaf1a..da667f9 100644
--- a/cmd/api-linter/github_actions.go
+++ b/cmd/api-linter/github_actions.go
@@ -33,10 +33,22 @@ func formatGitHubActionOutput(responses []lint.Response) []byte {
 
 			fmt.Fprintf(&buf, "::error file=%s", response.FilePath)
 			if problem.Location != nil {
-				fmt.Fprintf(&buf, " line=%d", problem.Location.Span[0])
-				fmt.Fprintf(&buf, " col=%d", problem.Location.Span[1])
-				fmt.Fprintf(&buf, " endLine=%d", problem.Location.Span[2])
-				fmt.Fprintf(&buf, " endColumn=%d", problem.Location.Span[3])
+				// Some findings are *line level* and only have start positions but no
+				// starting column. Construct a switch fallthrough to emit as many of
+				// the location indicators are included.
+				switch len(problem.Location.Span) {
+				case 4:
+					fmt.Fprintf(&buf, " endColumn=%d", problem.Location.Span[3])
+					fallthrough
+				case 3:
+					fmt.Fprintf(&buf, " endLine=%d", problem.Location.Span[2])
+					fallthrough
+				case 2:
+					fmt.Fprintf(&buf, " col=%d", problem.Location.Span[1])
+					fallthrough
+				case 1:
+					fmt.Fprintf(&buf, " line=%d", problem.Location.Span[0])
+				}
 			}
 
 			// GitHub uses :: as control characters (which are also used to delimit


Test patch:
diff --git a/cmd/api-linter/github_actions_test.go b/cmd/api-linter/github_actions_test.go
index 6d6206e..3134ab6 100644
--- a/cmd/api-linter/github_actions_test.go
+++ b/cmd/api-linter/github_actions_test.go
@@ -33,6 +33,49 @@ func TestFormatGitHubActionOutput(t *testing.T) {
 			data: []lint.Response{},
 			want: "",
 		},
+		{
+			name: "Example with partial location specifics",
+			data: []lint.Response{
+				{
+					FilePath: "example.proto",
+					Problems: []lint.Problem{
+						{
+							RuleID:  "line::col::endLine::endColumn",
+							Message: "line, column, endline, and endColumn",
+							Location: &descriptorpb.SourceCodeInfo_Location{
+								Span: []int32{5, 6, 7, 8},
+							},
+						},
+						{
+							RuleID:  "line::col::endLine",
+							Message: "Line, column, and endline",
+							Location: &descriptorpb.SourceCodeInfo_Location{
+								Span: []int32{5, 6, 7},
+							},
+						},
+						{
+							RuleID:  "line::col",
+							Message: "Line and column",
+							Location: &descriptorpb.SourceCodeInfo_Location{
+								Span: []int32{5, 6},
+							},
+						},
+						{
+							RuleID:  "line",
+							Message: "Line only",
+							Location: &descriptorpb.SourceCodeInfo_Location{
+								Span: []int32{5, 6, 7, 8},
+							},
+						},
+					},
+				},
+			},
+			want: `::error file=example.proto endColumn=8 endLine=7 col=6 line=5 title=line։։col։։endLine։։endColumn::line, column, endline, and endColumn
+::error file=example.proto endLine=7 col=6 line=5 title=line։։col։։endLine::Line, column, and endline
+::error file=example.proto col=6 line=5 title=line։։col::Line and column
+::error file=example.proto endColumn=8 endLine=7 col=6 line=5 title=line::Line only
+`,
+		},
 		{
 			name: "Example with location specifics",
 			data: []lint.Response{
@@ -55,8 +98,8 @@ func TestFormatGitHubActionOutput(t *testing.T) {
 					},
 				},
 			},
-			want: `::error file=example.proto line=1 col=2 endLine=3 endColumn=4 title=core։։naming_formats։։field_names::
-::error file=example.proto line=5 col=6 endLine=7 endColumn=8 title=core։։naming_formats։։field_names::multi\nline\ncomment
+			want: `::error file=example.proto endColumn=4 endLine=3 col=2 line=1 title=core։։naming_formats։։field_names::
+::error file=example.proto endColumn=8 endLine=7 col=6 line=5 title=core։։naming_formats։։field_names::multi\nline\ncomment
 `,
 		},
 		{
@@ -101,9 +144,11 @@ func TestFormatGitHubActionOutput(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		got := formatGitHubActionOutput(test.data)
-		if diff := cmp.Diff(string(test.want), string(got)); diff != "" {
-			t.Errorf("formatGitHubActionOutput() mismatch (-want +got):\n%s", diff)
-		}
+		t.Run(test.name, func(t *testing.T) {
+			got := formatGitHubActionOutput(test.data)
+			if diff := cmp.Diff(string(test.want), string(got)); diff != "" {
+				t.Errorf("formatGitHubActionOutput() mismatch (-want +got):\n%s", diff)
+			}
+		})
 	}
 }