Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
bufdev opened this issue Sep 15, 2021 · 2 comments
Open

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

bufdev opened this issue Sep 15, 2021 · 2 comments
Labels
Feature New feature or request

Comments

@bufdev
Copy link
Member

bufdev commented Sep 15, 2021

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 bufdev added Feature New feature or request P3 labels Sep 15, 2021
@Enrico2
Copy link

Enrico2 commented Sep 15, 2021

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

@nick-lehmann
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants