Skip to content

Pants incorrectly identifies cyclic dependencies between a module and its tests for Go #17236

@fiffeek

Description

@fiffeek

Describe the bug

Currently, I am using Bazel to manage a Go monorepo, and I wanted to migrate to pants for more effortless operability and maintenance
(have been successfully using Pants with python for side projects for a while now). However, as simple as it might have been,
the project does not build due to pants incorrectly identifying circular dependencies between packages.

In a simple setup where we have one file, one test file in the same folder, and a shared utils package for the test, pants does not build
due to identifying these as circular imports (while they are not). In short, in the following setup:

/src
---- /example  
-------- /testutils  
------------ BUILD  
------------ testutils.go  
-------- BUILD
-------- example.go
-------- example_test.go

Where example_test.go imports something from example.go and from testutils.go, and testutils.go imports something from example.go,
while keeping the standardized package naming conventions (for example.go -> example, and for example_test.go -> example_test)
Pants identifies the structure as cyclic (which should not be the case).

The dependencies in play here are:

  • example.go (example package) - no deps
  • example_test.go (example_test package) - depends on: example and testutils package
  • testutils.go (testutils package) - depends on: example package

Thus, clearly, there is no cycle. While I understand possibly why it's a tricky situation, keeping go test files next to the actual code
gives the benefit of getting the coverage right when running it locally (as I tried to fix the above situation by moving test code from src to tests, but then the coverage information is lost). Moreover, bazel correctly identifies this situation and resolves the imports without the error, while pants results in:

@rule(pants.backend.go.util_rules.build_pkg_target.setup_build_go_package_target_request(src/example:example)) <-
@rule(pants.backend.go.util_rules.build_pkg_target.setup_build_go_package_target_request(src/example/testutils:testutils))
@rule(pants.backend.go.util_rules.build_pkg_target.setup_build_go_package_target_request(src/example:example)) <-

Which is a hint that test files are possibly bundled together with the actual code? (There is no way of defining go_tests goal as in python).

A complete example is available in my repository.

Splitting the rule in two will not work as mentioned:

go_package(
    sources = ["*.go", "!*_test.go"]
)

go_package(
    name = "example_test",
    sources = ["*_test.go"]
)

Will lead to ambiguous imports:

13:43:25.02 [WARN] Ambiguous mapping for import path ...

Pants version
2.13.0, 2.14.x*rc

OS
Linux/Macos

Additional info
One workaround that I tried was to manually split the package into two (with tests and without), but then the import is ambiguous and so it does not work correctly either.

My guess is that the desired behaviour here is to resolve the dependencies per test/non_test module in the same package, or split the go_package goal as is done with python. I am open to pick this up and work on it, just need a couple of pointers and set the right direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions