github.com/googleapis/api-linter@v1.65.2/cmd/api-linter/github_actions.go (about) 1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "bytes" 19 "fmt" 20 "strings" 21 22 "github.com/googleapis/api-linter/lint" 23 ) 24 25 // formatGitHubActionOutput returns lint errors in GitHub actions format. 26 func formatGitHubActionOutput(responses []lint.Response) []byte { 27 var buf bytes.Buffer 28 for _, response := range responses { 29 for _, problem := range response.Problems { 30 // lint example: 31 // ::error file={name},line={line},endLine={endLine},title={title}::{message} 32 // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message 33 34 fmt.Fprintf(&buf, "::error file=%s", response.FilePath) 35 if problem.Location != nil { 36 // Some findings are *line level* and only have start positions but no 37 // starting column. Construct a switch fallthrough to emit as many of 38 // the location indicators are included. 39 switch len(problem.Location.Span) { 40 case 4: 41 fmt.Fprintf(&buf, ",endColumn=%d", problem.Location.Span[3]) 42 fallthrough 43 case 3: 44 fmt.Fprintf(&buf, ",endLine=%d", problem.Location.Span[2]) 45 fallthrough 46 case 2: 47 fmt.Fprintf(&buf, ",col=%d", problem.Location.Span[1]) 48 fallthrough 49 case 1: 50 fmt.Fprintf(&buf, ",line=%d", problem.Location.Span[0]) 51 } 52 } 53 54 // GitHub uses :: as control characters (which are also used to delimit 55 // linter rules. In order to prevent confusion, replace the double colon 56 // with two Armenian full stops which are indistinguishable to my eye. 57 runeThatLooksLikeTwoColonsButIsActuallyTwoArmenianFullStops := "։։" 58 title := strings.ReplaceAll(string(problem.RuleID), "::", runeThatLooksLikeTwoColonsButIsActuallyTwoArmenianFullStops) 59 message := strings.ReplaceAll(problem.Message, "\n", "\\n") 60 uri := problem.GetRuleURI() 61 if uri != "" { 62 message += "\\n\\n" + uri 63 } 64 fmt.Fprintf(&buf, ",title=%s::%s\n", title, message) 65 } 66 } 67 68 return buf.Bytes() 69 }