buf icon indicating copy to clipboard operation
buf copied to clipboard

Consider adding auto-commenting option for lint to add lint ignores

Open bufdev opened this issue 3 years ago • 2 comments

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)
		}

bufdev avatar Sep 15 '21 21:09 bufdev

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 avatar Sep 15 '21 22:09 Enrico2

@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.

nick-lehmann avatar Feb 03 '22 13:02 nick-lehmann