buf
buf copied to clipboard
Consider adding auto-commenting option for lint to add lint ignores
Basically, in addition to --error-format=config-ignore-yaml
, add something like an --auto-comment
flag that automatically adds // buf:lint:ignore
lines. My intuition is that this would naturally require us to be able to consume the AST and rewrite the whole file, i.e. the formatter, but a customer came up with a solution that might just be generic enough (we need to go through edge cases though):
fileContent := ""
for lineNumber, l := range fileLines {
for i < len(lps) && lineNumber+1 == lps[i].StartLine {
var prefix string
runes := []rune(l)
for i, c := range runes {
if c != ' ' && c != '\t' {
prefix = string(runes[0:i])
break
}
}
fileContent += fmt.Sprintf("%s// buf:lint:ignore %s %s\n", prefix, lps[i].RuleType, lps[i].Message)
i++
}
fileContent += l
fileContent += "\n"
}
if err := ioutil.WriteFile(path, []byte(fileContent), 0644); err != nil {
panic(err)
}
I'm the said customer, here's the full version:
package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
)
type lintProblem struct {
Path string `json:"path"`
StartLine int `json:"start_line"`
RuleType string `json:"type"`
Message string `json:"message"`
}
func file2lines(filePath string) ([]string, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer func(f *os.File) {
err := f.Close()
if err != nil {
panic(err)
}
}(f)
return linesFromReader(f)
}
func linesFromReader(r io.Reader) ([]string, error) {
var lines []string
scanner := bufio.NewScanner(r)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return lines, nil
}
type lintProblems []lintProblem
func (es lintProblems) Len() int {
return len(es)
}
func (es lintProblems) Less(i, j int) bool {
return es[i].StartLine < es[j].StartLine
}
func (es lintProblems) Swap(i, j int) {
es[i], es[j] = es[j], es[i]
}
func main() {
var lines []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
var problems []lintProblem
for _, line := range lines {
var lp lintProblem
err := json.Unmarshal([]byte(line), &lp)
if err != nil {
panic(err)
}
problems = append(problems, lp)
}
grouped := map[string]lintProblems{}
for _, e := range problems {
grouped[e.Path] = append(grouped[e.Path], e)
}
for path, lps := range grouped {
sort.Sort(lps)
fileLines, err := file2lines(path)
if err != nil {
panic(err)
}
i := 0
fileContent := ""
for lineNumber, l := range fileLines {
for i < len(lps) && lineNumber+1 == lps[i].StartLine {
var prefix string
runes := []rune(l)
for i, c := range runes {
if c != ' ' && c != '\t' {
prefix = string(runes[0:i])
break
}
}
fileContent += fmt.Sprintf("%s// buf:lint:ignore %s %s\n", prefix, lps[i].RuleType, lps[i].Message)
i++
}
fileContent += l
fileContent += "\n"
}
if err := ioutil.WriteFile(path, []byte(fileContent), 0644); err != nil {
panic(err)
}
}
}
Took 2 functions from https://siongui.github.io/2017/01/30/go-insert-line-or-string-to-file/
This can be cleaned up, e.g. prefix
is calculated multiple times for the same line sometimes. This is literally the first Go I ever wrote so ... low expectations :)
Invocation:
go build -o lint_commenter .
buf lint --error-format=json | ./lint_commenter
@Enrico2 I know that the issue has been stale for quite some time, but I would like to give you a huge thanks ❤️ You are my saviour who spared my so much tedious work 👍🏻 Throwing in my five cents, it would be really cool if this could be added to buf.