-
-
Notifications
You must be signed in to change notification settings - Fork 217
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
feat: add api-linter (powered by buf CLI) #665
base: master
Are you sure you want to change the base?
Conversation
062453d
to
fd2d074
Compare
01ebfcf
to
71e2d73
Compare
2f4dbb4
to
b29420d
Compare
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.
Is this common to generate the descriptor-set-in file like this?
Looking at the other integrations mentioned in googleapis/api-linter#764 they don't appear to be doing anything like this as far as I can tell.
@mfussenegger I can't speak for those other IDE plugins but you have to somehow tell api-linter where it can find all imports that might be used by the proto file that you are linting, or api-linter will simply fail linting. $ api-linter gomicroservice/v1/user_service.proto
2024/09/26 14:19:02 proto/gomicroservice/v1/user_service.proto:5:8: open buf/validate/validate.proto: no such file or directory Here's the user_service.proto used in the command above. The command is failing because it doesn't find the protos from https://github.com/bufbuild/protoc-gen-validate. But if I instead use the built descriptor file (which knows about the validate dependency since it's specified in my buf.yaml config), it will succeed: $ buf build -o d.pb
$ api-linter --descriptor-set-in=d.pb gomicroservice/v1/user_service.proto
- file_path: gomicroservice/v1/user_service.proto
problems:
- message: Proto files must set `option java_package`.
location:
start_position:
line_number: 3
column_number: 1
end_position:
line_number: 3
column_number: 26
path: gomicroservice/v1/user_service.proto
rule_id: core::0191::java-package
rule_doc_uri: https://linter.aip.dev/191/java-package
- message: Proto files must set `option java_multiple_files = true;`
location:
start_position:
line_number: 3
column_number: 1
end_position:
line_number: 3
column_number: 26
path: gomicroservice/v1/user_service.proto
rule_id: core::0191::java-multiple-files
rule_doc_uri: https://linter.aip.dev/191/java-multiple-files
- message: Proto files should set `option java_outer_classname = "UserServiceProto"`.
location:
start_position:
line_number: 3
column_number: 1
end_position:
line_number: 3
column_number: 26
path: gomicroservice/v1/user_service.proto
rule_id: core::0191::java-outer-classname
rule_doc_uri: https://linter.aip.dev/191/java-outer-classname ... and in this case it will complain about the I believe you can also do it via So, one may traverse the current project for protos to solve that, but where would I traverse or look for imports from protovalidate (and other downloaded buf dependencies)? But by building this descriptor file, all such dependencies are sucked in (by buf itself) and redefined in the descriptor file, making it a lot easier to point api-linter to this derivative file. This basically leverages whatever buf does to perform the codegen based on the protos. As a bonus here, buf will adhere to the buf lockfile, using the versions of the protos you intend. So in my opinion I'm doing the right thing here. And obviously you can override the arguments and provide different logic if you don't think this suits your needs. This is ❯ api-linter --help
Usage of api-linter:
--config string The linter config file.
--debug Run in debug mode. Panics will print stack.
--descriptor-set-in stringArray The file containing a FileDescriptorSet for searching proto imports.
May be specified multiple times.
--disable-rule stringArray Disable a rule with the given name.
May be specified multiple times.
--enable-rule stringArray Enable a rule with the given name.
May be specified multiple times.
--ignore-comment-disables If set to true, disable comments will be ignored.
This is helpful when strict enforcement of AIPs are necessary and
proto definitions should not be able to disable checks.
--list-rules Print the rules and exit. Honors the output-format flag.
--output-format string The format of the linting results.
Supported formats include "yaml", "json","github" and "summary" table.
YAML is the default.
-o, --output-path string The output file path.
If not given, the linting results will be printed out to STDOUT.
-I, --proto-path stringArray The folder for searching proto imports.
May be specified multiple times; directories will be searched in order.
The current working directory is always used.
--set-exit-status Return exit status 1 when lint errors are found.
--version Print version and exit. |
@mfussenegger I guess you can argue that this is solution is geared towards I use this almost everyday and it's super helpful when working with "AIP-driven" APIs: https://github.com/fredrikaverpil/dotfiles/blob/main/nvim-fredrik/lua/lang/protobuf.lua |
@mfussenegger would you like me to implement two strategies?
Then I guess we can support (mostly) what the other IDEs are doing too. Strategy 2 will be slower and inferior in the sense that it won't support knowledge of protos which reside outside your git repo project and if it encounters an import it cannot resolve, the api-linter will simply not lint and error. But at least you will get something that looks similar to what other IDEs are doing in case you don't use I personally feel having these two strategies would be fine and then let someone who is a non-buf user extend this functionality to perhaps even better fit that use case. |
No strong opinion on this. I don't use api-linter. But it is highly unusual that a linter requires to run another tool beforehand. I kinda think that whatever The If the buf setup is common, would it make sense to create a |
This turned out to be a long post/reply. Sorry for that. I'm just trying to give as nuanced and honest picture of this as I can, so to help out in being able to take good decisions here. Maybe grab a cup or keg of your favorite beverage before reading. 😄
I can only agree it is not common behavior for a linter. I searched the api-linter repo to see if I could get some answers on this myself (🕳️ 🐇). If you are inclined to skim through this GitHub issue, it may bring a little light to this topic as Googlers are here discussing how to make api-linter aware of imports (as it seems to be more akin to an LSP) and finally landing on a descriptor file (which you indeed have to generate beforehand). My point is only that api-linter clearly need this input and won't work without it. The input being all your protos; either one by one or in the form of this binary descriptor file representation. To be clear, you don't have to use the buf CLI to generate this descriptor file. But you somehow need to supply api-linter with all protos (even from imports made in the proto you wish to lint). Where I work, we've done this since beginning of 2022. Alternatives to using the buf CLI could be (although I wouldn't consider them for nvim-lint):
I can change this code into supporting an older nvim version of your choice. Let me know which version I need to support or if you have a reference implementation in mind from another linter. No problem.
Let me quickly just mention we use the buf CLI where I work because it enables an ecosystem of tooling around working with protos. They market themselves as being an "all-in-one protobuf toolchain" here. You can specify your dependencies, download them, upgrade them, create a lockfile etc, all using the buf CLI. And buf knows exactly which versions of your third-party dependencies you have in your lock file and reads those when building the descriptor file. I've worked at companies that "were not yet on buf" but wanted to go there but had blocking issues letting them do so. So I'd say buf might be somewhat common but definitively desirable over previous solutions in my opinion. The buf CLI is free by the way, which I guess contributes to its popularity (~9k stars): https://github.com/bufbuild/buf To be super clear, you need third-party dependencies to e.g. generate python/java/go/etc code. It's not really feasible scenario that you don't use any third-party dependencies.
Sure, I guess that's one option, but in that case how would the "regular" nvim-lint api-linter would work by default? However, I personally think it would be totally fine to require users to append additional filepaths to the "regular" api-linter args in that case. I'd be happy to update the PR with a I would have personally just assumed most people (want to) use buf - and if not, they can overide the arguments themselves. This is one of the strengths of nvim-lint I've come to love! |
Yes I'd prefer that, plus the |
437780f
to
5e64563
Compare
I think for most users, a "bare-bones" api-linter which wouldn't take any third-party plugins into account wouldn't be usable, really. So I opted for just adding a I also swapped out some newer functions for older and custom approaches. I'm not sure what you think about that. Anyway, I tested these changes out here on a couple of projects and it works fine for me. |
I think there was a bit of a misunderstanding. What I meant was not only changing this to buf_api_linter but also create a dedicated buf-api-linter project with an executable that combines Then this integration could define the This would have the advantage that integration in other editors would make use of it too. |
Aha okay. Yes, I think I misunderstood you there. So |
bump |
@mfussenegger please have a look at what I did now. I broke apart the logic into two linters. I know the interface doesn't specify supplying an example autocmd, but I felt I had to do this to show the usage intent due to the lack of cwd-as-a-function. |
6615709
to
a7aa437
Compare
ed0cf82
to
cc52843
Compare
cc52843
to
4bf5094
Compare
This adds the excellent "api-linter" from Google, which lints for so-called AIPs in
.proto
files: https://github.com/googleapis/api-linterNotes
buf
on$PATH
.--descriptor-set-in
argument) which attempts to search for abuf.yaml
(orbuf.yml
) file. This search upwards from the opened buffer (the .proto file) until hitting$HOME
, where it stops and fails. But this function may not be sufficient for everyone's use case. It's important that for such users, this function can be overridden and right now it seems like the only way is to fully replace all arguments withopts.linters["api-linter"] = { args = {...} }
, which is totally fine I guess.--disable-rule
directives as otherwise you'll get these java warnings (and you may not even be using java). See below: