bazel-contrib / bazel-gazelle

Gazelle is a Bazel build file generator for Bazel projects. It natively supports Go and protobuf, and it may be extended to support new languages and custom rule sets.
Apache License 2.0
1.19k stars 379 forks source link

Gazelle resolving v3 import as a dir of v1 #1108

Open sluongng opened 3 years ago

sluongng commented 3 years ago

What version of gazelle are you using?

v0.23.0

What version of rules_go are you using?

v0.28.0

What version of Bazel are you using?

4.2.1

Does this issue reproduce with the latest releases of all the above?

Yes, all of the above are latest

What operating system and processor architecture are you using?

MacOS Darwin AMD64

What did you do?

I have a setup where all go_dependencies in WORKSPACE are loaded from third_party/golang_deps.bzl via go_dependencies() macro. The content of the macro is like this

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
load("@com_github_ericnorris_rules_nfpm//nfpm:go_repositories.bzl", "rules_nfpm_go_dependencies")

def go_dependencies():
    _go_dependencies()
    gazelle_dependencies()
    rules_nfpm_go_dependencies()

def _go_dependencies():
    ...
    go_repository(
        name = "com_github_masterminds_semver",
        importpath = "github.com/Masterminds/semver",
        sum = "h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=",
        version = "v1.5.0",
    )

Note that in rules_nfpm_go_dependencies() there are declarations like this

load("//nfpm/internal:maybe_go_repository.bzl", go_repository = "maybe_go_repository")

def rules_nfpm_go_dependencies():
    _rules_nfpm_go_repositories()

def _rules_nfpm_go_repositories():
    ...
    go_repository(
        name = "com_github_masterminds_semver",
        build_directives = ["gazelle:go_naming_convention_external go_default_library"],
        importpath = "github.com/Masterminds/semver",
        sum = "h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=",
        version = "v1.5.0",
    )
    go_repository(
        name = "com_github_masterminds_semver_v3",
        build_directives = ["gazelle:go_naming_convention_external go_default_library"],
        importpath = "github.com/Masterminds/semver/v3",
        sum = "h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=",
        version = "v3.1.1",
    )

What did you expect to see?

When workspace is built, I expect gazelle to resolve all imports of "github.com/Masterminds/semver/v3" as com_github_masterminds_semver_v3

What did you see instead?

/private/var/tmp/_bazel_sluongngoc/50317ee82639d4cb75051b8d113f0508/external/com_github_goreleaser_nfpm_v2/BUILD.bazel:5:11: no such package '@com_github_masterminds_semver//v3': BUILD file not found in directory 'v3' of external repository @com_github_masterminds_semver. Add a BUILD file to a directory to mark it as a package. and referenced by '@com_github_goreleaser_nfpm_v2//:nfpm'

The actual BUILD.bazel file generated

> cat /private/var/tmp/_bazel_sluongngoc/50317ee82639d4cb75051b8d113f0508/external/com_github_goreleaser_nfpm_v2/BUILD.bazel
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

# gazelle:go_naming_convention_external go_default_library

go_library(
    name = "nfpm",
    srcs = ["nfpm.go"],
    importpath = "github.com/goreleaser/nfpm/v2",
    importpath_aliases = ["github.com/goreleaser/nfpm"],
    visibility = ["//visibility:public"],
    deps = [
        "//files",
        "@com_github_goreleaser_chglog//:go_default_library",
        "@com_github_imdario_mergo//:go_default_library",
        "@com_github_masterminds_semver//v3:go_default_library",
        "@in_gopkg_yaml_v3//:go_default_library",
    ],
)

alias(
    name = "go_default_library",
    actual = ":nfpm",
    visibility = ["//visibility:public"],
)

go_test(
    name = "nfpm_test",
    srcs = ["nfpm_test.go"],
    deps = [
        ":nfpm",
        "//files",
        "@com_github_stretchr_testify//require:go_default_library",
    ],
)

This confuses me as for certain that I do have the go_repository downloaded

> bazel query @com_github_masterminds_semver_v3//...
INFO: Invocation ID: bb50c166-bc90-429e-a64b-2109b6494736
go_test rule @com_github_masterminds_semver_v3//:semver_test
alias rule @com_github_masterminds_semver_v3//:go_default_library
go_library rule @com_github_masterminds_semver_v3//:semver
Loading: 1 packages loaded

After playing with this a bit more, I found out that if I were to take com_github_masterminds_semver_v3 and put it into my workspace's _go_dependencies() macro, the issue is fixed.

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
load("@com_github_ericnorris_rules_nfpm//nfpm:go_repositories.bzl", "rules_nfpm_go_dependencies")

def go_dependencies():
    _go_dependencies()
    gazelle_dependencies()
    rules_nfpm_go_dependencies()

def _go_dependencies():
    ...
    go_repository(
        name = "com_github_masterminds_semver_v3",
        build_directives = ["gazelle:go_naming_convention_external go_default_library"],
        importpath = "github.com/Masterminds/semver/v3",
        sum = "h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=",
        version = "v3.1.1",
    )
    go_repository(
        name = "com_github_masterminds_semver",
        importpath = "github.com/Masterminds/semver",
        sum = "h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=",
        version = "v1.5.0",
    )

This works as long as com_github_masterminds_semver_v3 is defined within _go_dependencies(), disregarding it's order(before/after) relative to com_github_masterminds_semver.

However if I were to load it in go_dependencies() macro

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
load("@com_github_ericnorris_rules_nfpm//nfpm:go_repositories.bzl", "rules_nfpm_go_dependencies")

def go_dependencies():
    go_repository(
        name = "com_github_masterminds_semver_v3",
        build_directives = ["gazelle:go_naming_convention_external go_default_library"],
        importpath = "github.com/Masterminds/semver/v3",
        sum = "h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=",
        version = "v3.1.1",
    )    
    _go_dependencies()
    gazelle_dependencies()
    rules_nfpm_go_dependencies()

def _go_dependencies():
    ...
    go_repository(
        name = "com_github_masterminds_semver",
        importpath = "github.com/Masterminds/semver",
        sum = "h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=",
        version = "v1.5.0",
    )

Then the issue occurred again.

sluongng commented 3 years ago

The current workaround that I decided to go with, is to add com_github_masterminds_semver_v3 inside _go_dependencies() with a # keep comment on top of the repo declaration. It's not the cleanest solution and it's screw around with how Gazelle is managing the macro, but it's working.

If somebody can give me a pointer to Gazelle resolve logic of a go_repository target, I will do a deep dive to see how could I get this fixed so that the generated BUILD file will always have the correct deps target

robfig commented 3 years ago

Hm, I'm not sure, I haven't seen this behavior before. The relevant code should be language/go/resolve.go:ResolveGo -> resolveExternal. One workaround would be to use explicit resolve directives, although that shouldn't be necessary in this case..

# gazelle:resolve go github.com/Masterminds/semver/v3 @com_github_masterminds_semver_v3//:go_default_library