Skip to content

fix(cli): resolve import path resolution#1545

Merged
quirogas merged 6 commits into
v2from
fix-resolve-import-path
Oct 1, 2025
Merged

fix(cli): resolve import path resolution#1545
quirogas merged 6 commits into
v2from
fix-resolve-import-path

Conversation

@quirogas

Copy link
Copy Markdown
Contributor

This PR fixes an issue where the linter failed to resolve proto imports correctly, particularly in two key scenarios.

Fix

The underlying issue was that the compiler attempted to process all proto files at once, which led to errors when dependencies were located in different paths. The fix is to compile each proto file individually, allowing the compiler to correctly resolve the distinct import paths for each file.

Additionally, the resolveImports function was updated to correctly handle relative paths, ensuring they are preserved and passed to the compiler.


Scenarios Covered

1. Imports from Mixed Roots (Relative and -I flag) ( #1519)

The linter can now correctly resolve imports when one dependency is relative to the current working directory and another is located in a path specified by the -I flag.

Testing Structure:

.
├── api
│   ├── common
│   │   └── common.proto
│   └── v1
│       └── test.proto
└── third_party
    └── google
        └── api
            └── field_behavior.proto

File Contents:

api/common/common.proto

syntax = "proto3";
package api.common;
message Foo {}

api/v1/test.proto

syntax = "proto3";
package api.v1;
import "google/api/field_behavior.proto";
import "api/common/common.proto";
message Test {
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];
  api.common.Foo foo = 2;
}

third_party/google/api/field_behavior.proto

syntax = "proto3";
package google.api;
// ... content

Command:

The following command now works as expected, resolving both the third_party import and the local api/common import:

api-linter -I third_party api/v1/test.proto

2. Linting Multiple Files with a Common Root (#1465)

The linter now correctly handles cases where multiple files are passed as arguments and share a common import root that is not part of their package path. This avoids duplicate dependency errors.

Testing Structure:

.
└── proto
    ├── google
    │   └── api
    │       ├── annotations.proto
    │       └── http.proto
    └── ...

Command:

The following command correctly lints both files without issues:

api-linter -I proto proto/google/api/http.proto proto/google/api/annotations.proto

Important Usage Note

It is important to note that the following command will not work for the second scenario:

# This will fail
api-linter proto/google/api/http.proto proto/google/api/annotations.proto

The linter cannot automatically infer that proto is the intended import root for the dependencies between http.proto and annotations.proto. Adding the complexity to infer this is unnecessary.

Instead, users should follow one of two conventions:

  1. Run the api-linter from the root of the proto definitions (e.g., cd proto && api-linter google/api/http.proto ...).
  2. Use the -I flag to explicitly specify the import root, as shown in the working example above.

A new integration test has been added to cover these scenarios and prevent regressions.


fixes #1519

@quirogas
quirogas requested a review from a team September 30, 2025 18:38
@quirogas quirogas self-assigned this Sep 30, 2025
@quirogas
quirogas requested a review from noahdietz September 30, 2025 18:38
Comment thread cmd/api-linter/cli.go Outdated
errorStrings[i] = e.Error()
var compiledFiles linker.Files
for _, protoFile := range c.ProtoFiles {
// Compile each file individually.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Why? The code is self-explanatory as far as what it is doing, the comment should be providing rationale.

https://testing.googleblog.com/2017/07/code-health-to-comment-or-not-to-comment.html

Comment thread cmd/api-linter/integration_test.go Outdated
@quirogas
quirogas requested a review from noahdietz September 30, 2025 18:54
@noahdietz

Copy link
Copy Markdown
Contributor

Hey @CuriousStork would you be interested in testing this out ? We think it fixes the issue you reported and the one we were trying to fix when we broke this case - your repro was really helpful.

@CuriousStork

Copy link
Copy Markdown

@noahdietz Hello, I'd like to test it. However, I guess I need to compile a binary from the source code? I'm not familiar with Go, so this may take some time.

@noahdietz

Copy link
Copy Markdown
Contributor

@noahdietz Hello, I'd like to test it. However, I guess I need to compile a binary from the source code? I'm not familiar with Go, so this may take some time.

Ah apologies! If you have Go installed on your machine, you can compile/install in path by do the following go install github.com/googleapis/api-linter/v2/cmd/api-linter@fix-resolve-import-path. If your GOPATH is part of your PATH, it will be accessible from there.

If you don't mind trying, it would be great, but I understand not having the time to and waiting for us to push a pre-release.

@CuriousStork

Copy link
Copy Markdown

@noahdietz Thank you and @quirogas for fixing the issue.

In short, it seems to be fixed.

I've made a very quick smoke test on Ubuntu with my real project files.

api-linter --version output for the compiled binary:

api-linter 2.0.0-beta.4

Running with --proto-path=third_party was successful. The project root directory import was correctly inferred w/o explicitly adding the root to --proto-path. I've tested a couple of files: one from third_party and another from the main project API section. The latter imports both from third_party and another directory.

PS: I guess testing on Windows isn't necessary.

@quirogas
quirogas merged commit d426ca6 into v2 Oct 1, 2025
8 checks passed
@quirogas
quirogas deleted the fix-resolve-import-path branch October 1, 2025 19:30
@CuriousStork CuriousStork mentioned this pull request Oct 2, 2025
quirogas added a commit that referenced this pull request Oct 22, 2025
…1554)

* feat!: Migrate from jhump/protoreflect to google.golang.org/protobuf (#1513)

This commit migrates the entire codebase from the `jhump/protoreflect` and deprecated `github.com/golang/protobuf` libraries to the new `google.golang.org/protobuf` library. This is a significant change that modernizes the codebase and improves performance and maintainability.

BREAKING CHANGE: This migration introduces breaking changes to the public API. Users will need to update their code to use the new `google.golang.org/protobuf` types.
--- 
## Extended description

*   feat!(lint): migrate to protobuf-go
*   feat!(locations): migrate to protobuf-go
*   feat!(internal): migrate to protobuf-go
*   feat!(rules): migrate AIPs from protoreflect to protobuf-go
*   feat!(cli): migrate to protobuf-go

Co-authored-by: Noah Dietz <[email protected]>

---------

Co-authored-by: Noah Dietz <[email protected]>

* fix(cli): resolve linting errors related to incorrect positioning whe… (#1531)

* fix(cli): allow disabling all rules and then enabling a single rule, or multiple rules
* fix(cli): resolve linting errors related to incorrect positioning when working with descriptor sets without source info

* fix(cli): deduplicate descriptor sets on load (#1536)

* chore(v2): catch up with main (#1535)

* chore(v2): catch up with main

* chore(AIP-160): migrate recently added rules

* chore(rules/internal/utils): utilify extension parsing (#1537)

* chore(rules/internal/utils): utilify extension parsing

* chore: attempt using generics

* chore: change all to generic func

* chore: remove unused

* chore: use marshal/unmarshal instead of merge

* chore: export method add docs

* chore: clean up error modes

* chore(internal): add test util (#1538)

* chore(internal): add test util

* chore(internal): add helper mark

* chore(internal): bump version (#1542)

* fix(cli):  resolve import path resolution (#1545)

* fix(cli): fix import resolution

* chore(cli): fix integration test

* chore(cli): compile every proto file separatelly to avoid import and compilation collisions

* chore(cli): add integration test for thrid_party dir scenario

* chore(cli): simplify test

* chore(cli): expand comment

* chore(rules): allow AIP-157 View field in standard methods (#1548)

* feat(AIP-133): allow view field in create request

* feat(AIP-134): allow view field in update request

* feat(AIP-135): allow view field in delete request

* chore(rules): allow include _view suffixed fields

* docs(AIP-133): update docs for request-unknown-fields

* docs(AIP-134): update docs for request-unknown-fields

* docs(AIP-135): update docs for request-unknown-fields

* chore(rules): remove debug logic

* chore(v2): catch up with main (again) (#1549)

* fix(lint): linter config on windows (#1551)

* fix(lint): linter config on windows

* docs: update install command (#1553)

* chore: v2 catch up with main  (#1555)

Merge main into v2 before merging v2 into main

---------

Co-authored-by: Noah Dietz <[email protected]>
alethenorio added a commit to einride/sage that referenced this pull request Oct 30, 2025
This updates api-linter to version 2.0.0.

It is marked a breaking change in the repo but looking at the
[details](googleapis/api-linter#1513) for the
following reasons:

1. Any functions or rule definitions that previously exposed types from
   the jhump/protoreflect library (e.g., desc.MessageDescriptor,
   desc.FieldDescriptor) now expose the official
   protoreflect.MessageDescriptor, protoreflect.FieldDescriptor, etc.
   types from google.golang.org/protobuf.
2. Consumers who use the api-linter as a library and have written custom
   rules will need to update their code to use the new protoreflect
   types.

The first one feels like very niche and not a general concern at
Einride. The second is not a valid use case for Sage which is not used
as a library so this breaking change feels acceptable.

Also as per googleapis/api-linter#1545
api-linter can now correctly handle relative paths which solves some use
cases when proto files are spread across different places in a
repository so we switch to using relative paths to the buf.yaml rather
than aboslute.
alethenorio added a commit to einride/sage that referenced this pull request Oct 30, 2025
This updates api-linter to version 2.0.0.

It is marked a breaking change in the repo but looking at the
[details](googleapis/api-linter#1513) the
following reasons are stated:

1. Any functions or rule definitions that previously exposed types from
   the jhump/protoreflect library (e.g., desc.MessageDescriptor,
   desc.FieldDescriptor) now expose the official
   protoreflect.MessageDescriptor, protoreflect.FieldDescriptor, etc.
   types from google.golang.org/protobuf.
2. Consumers who use the api-linter as a library and have written custom
   rules will need to update their code to use the new protoreflect
   types.

The first one feels like very niche and not a general concern at
Einride. The second is not a valid use case for Sage which is not used
as a library so this breaking change feels acceptable.

Also as per googleapis/api-linter#1545
api-linter can now correctly handle relative paths which solves some use
cases when proto files are spread across different places in a
repository so we switch to using relative paths to the buf.yaml rather
than aboslute.
alethenorio added a commit to einride/sage that referenced this pull request Oct 31, 2025
This updates api-linter to version 2.0.0.

It is marked a breaking change in the repo but looking at the
[details](googleapis/api-linter#1513) the
following reasons are stated:

1. Any functions or rule definitions that previously exposed types from
   the jhump/protoreflect library (e.g., desc.MessageDescriptor,
   desc.FieldDescriptor) now expose the official
   protoreflect.MessageDescriptor, protoreflect.FieldDescriptor, etc.
   types from google.golang.org/protobuf.
2. Consumers who use the api-linter as a library and have written custom
   rules will need to update their code to use the new protoreflect
   types.

The first one feels like very niche and not a general concern at
Einride. The second is not a valid use case for Sage which is not used
as a library so this breaking change feels acceptable.

Also as per googleapis/api-linter#1545
api-linter can now correctly handle relative paths which solves some use
cases when proto files are spread across different places in a
repository so we switch to using relative paths to the buf.yaml rather
than aboslute.
alethenorio added a commit to einride/sage that referenced this pull request Oct 31, 2025
This updates api-linter to version 2.0.0.

It is marked a breaking change in the repo but looking at the
[details](googleapis/api-linter#1513) the
following reasons are stated:

1. Any functions or rule definitions that previously exposed types from
   the jhump/protoreflect library (e.g., desc.MessageDescriptor,
   desc.FieldDescriptor) now expose the official
   protoreflect.MessageDescriptor, protoreflect.FieldDescriptor, etc.
   types from google.golang.org/protobuf.
2. Consumers who use the api-linter as a library and have written custom
   rules will need to update their code to use the new protoreflect
   types.

The first one feels like very niche and not a general concern at
Einride. The second is not a valid use case for Sage which is not used
as a library so this breaking change feels acceptable.

Also as per googleapis/api-linter#1545
api-linter can now correctly handle relative paths which solves some use
cases when proto files are spread across different places in a
repository so we switch to using relative paths to the buf.yaml rather
than aboslute.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants