-
-
Couldn't load subscription status.
- Fork 1.5k
feat: apply formatters after the suggested fixes #5246
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
Conversation
8a76e20 to
8a0dd0c
Compare
|
Thanks for the clear status. It was indeed a problem to explain these behaviors |
636293c to
74f0e0c
Compare
Nothing to be sorry about, thank you for the details description and examples making it easy to understand 😃 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Sorry for the long description, but I want to be sure to provide all the information to understand the context.
Inside golangci-lint there are 4 "linters" that are not real linters/analyzers but "formatters":
gofmt,goimports,gofumpt, andgci.Their standard outputs are
[]byteand notDiagnostic, internally golangci-lint produces diff patches based on[]byteand converts them intoDiagnostic.Also
goimportsandgciare not "import formatters": they format all the code and not only imports.Problems
All those tools provide the same base functionality (format) with some variants but their changes could be incompatible (mainly on imports) unless they are run in a specific order and without incompatible settings.
Incompatibilities
gofmt+gci-> potential problem on importsgoimports+gci-> potential problem on importsgofumpt+gci-> potential problem on importsgofmt+goimports-> potential problem on importsgofumpt+goimports-> potential problem on importsgofmt+gofumpt-> potential problem on imports, and on function signaturesI solved the main problem on imports with the support of suggested fixes: if a conflict is detected, only the suggested fixes of one linter are applied and a warning is displayed for the others.
But this has some side effects, and it can be handled differently.
Identical but Different
The real problem is that each formatter has specificities, there is no "winner".
gofmtgoimportsgofumptgcigoimportsis a "variant" ofgofmtwithoutsimplifyandrewrite-rulesbut withlocal-prefixesto organize imports.gofumptis a "variant" ofgoimportswithextra-rules, andmodule-pathis more limited thanlocal-prefixes.gciis a "variant" ofgoimportswith options to customize import orders.Note:
gcihas a terrible name because this is an acronym of golangci(-lint) instead of something related to "imports". I think we should evaluate asking for a renaming.The PR
I don't want to recommend a formatter over another because each formatter has specificities.
With this PR, they will behave like a linter (reports) but suggested fixes will be skipped, be run after the fixing process, and be used in a specific order.
The specific order is:
gofmtgofumptgoimportsgciThis will allow applying all the changes, in one run, and without any conflicts.
Note, this doesn't mean I recommend using all those linters at the same time, it's the opposite, in the majority of cases, only one or two of those formatters is needed.
But golangci-lint should be able to provide a consistent output even in those unwanted situations.
Example
I will illustrate the topic with a terribly wrong configuration, nobody should do that: I will use, at the same time, all the options of all formatters even the conflicting options.
.golangci.yml
main.go
In this example, there are several rules that should be applied:
goimports,gofumpt,gci)interface{}should be replaced byany(gofmt)Barshould be changed to remove the "duplicate" type. (gofumpt)Currently (v1.62), you must run golangci-lint 2 times and hope to be lucky:
gofmtreplacements are applied but the imports are duplicated because of a "fight" between all linters. Also, this is a "lucky case" because in some cases some imports can disappear.gofumptappliesextra-rulesand the imports are fixed (by one of the linters).With the PR about suggested fixes, you must run golangci-lint 3 times but there are no unexpected changes (no import duplication or removal):
goimportswill be applied (no import duplication)gciandgofumptare appliedgofmtreplacements are applied.With this PR, you only need one run:
$ ./golangci-lint run --fix $