/* Copyright 2017 The Bazel Authors. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // This file contains integration tests for all of Gazelle. It's meant to test // common usage patterns and check for errors that are difficult to test in // unit tests. package main import ( "bytes" "flag" "log" "os" "path/filepath" "strings" "testing" "github.com/bazelbuild/bazel-gazelle/config" "github.com/bazelbuild/bazel-gazelle/internal/wspace" "github.com/bazelbuild/bazel-gazelle/testtools" "github.com/google/go-cmp/cmp" ) // skipIfWorkspaceVisible skips the test if the WORKSPACE file for the // repository is visible. This happens in newer Bazel versions when tests // are run without sandboxing, since temp directories may be inside the // exec root. func skipIfWorkspaceVisible(t *testing.T, dir string) { if parent, err := wspace.FindRepoRoot(dir); err == nil { t.Skipf("WORKSPACE visible in parent %q of tmp %q", parent, dir) } } func runGazelle(wd string, args []string) error { return run(wd, args) } // TestHelp checks that help commands do not panic due to nil flag values. // Verifies #256. func TestHelp(t *testing.T) { for _, args := range [][]string{ {"help"}, {"fix", "-h"}, {"update", "-h"}, {"update-repos", "-h"}, } { t.Run(args[0], func(t *testing.T) { if err := runGazelle(".", args); err == nil { t.Errorf("%s: got success, want flag.ErrHelp", args[0]) } else if err != flag.ErrHelp { t.Errorf("%s: got %v, want flag.ErrHelp", args[0], err) } }) } } func TestNoRepoRootOrWorkspace(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, nil) defer cleanup() skipIfWorkspaceVisible(t, dir) want := "-repo_root not specified" if err := runGazelle(dir, nil); err == nil { t.Fatalf("got success; want %q", want) } else if !strings.Contains(err.Error(), want) { t.Fatalf("got %q; want %q", err, want) } } func TestNoGoPrefixArgOrRule(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE", Content: ""}, {Path: "hello.go", Content: "package hello"}, }) defer cleanup() buf := new(bytes.Buffer) log.SetOutput(buf) defer log.SetOutput(os.Stderr) if err := runGazelle(dir, nil); err != nil { t.Fatalf("got %#v; want success", err) } want := "go prefix is not set" if !strings.Contains(buf.String(), want) { t.Errorf("log does not contain %q\n--begin--\n%s--end--\n", want, buf.String()) } } // TestSelectLabelsSorted checks that string lists in srcs and deps are sorted // using buildifier order, even if they are inside select expressions. // This applies to both new and existing lists and should preserve comments. // buildifier does not do this yet bazelbuild/buildtools#122, so we do this // in addition to calling build.Rewrite. func TestSelectLabelsSorted(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "BUILD", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = select({ "@io_bazel_rules_go//go/platform:linux": [ # foo comment "foo.go", # side comment # bar comment "bar.go", ], "//conditions:default": [], }), importpath = "example.com/foo", ) `, }, { Path: "foo.go", Content: ` // +build linux package foo import ( _ "example.com/foo/outer" _ "example.com/foo/outer/inner" _ "github.com/jr_hacker/tools" ) `, }, { Path: "foo_android_build_tag.go", Content: ` // +build android package foo import ( _ "example.com/foo/outer_android_build_tag" ) `, }, { Path: "foo_android.go", Content: ` package foo import ( _ "example.com/foo/outer_android_suffix" ) `, }, { Path: "bar.go", Content: `// +build linux package foo `, }, {Path: "outer/outer.go", Content: "package outer"}, {Path: "outer_android_build_tag/outer.go", Content: "package outer_android_build_tag"}, {Path: "outer_android_suffix/outer.go", Content: "package outer_android_suffix"}, {Path: "outer/inner/inner.go", Content: "package inner"}, }) want := `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = [ # bar comment "bar.go", # foo comment "foo.go", # side comment "foo_android.go", "foo_android_build_tag.go", ], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = select({ "@io_bazel_rules_go//go/platform:android": [ "//outer:go_default_library", "//outer/inner:go_default_library", "//outer_android_build_tag:go_default_library", "//outer_android_suffix:go_default_library", "@com_github_jr_hacker_tools//:go_default_library", ], "@io_bazel_rules_go//go/platform:linux": [ "//outer:go_default_library", "//outer/inner:go_default_library", "@com_github_jr_hacker_tools//:go_default_library", ], "//conditions:default": [], }), ) ` defer cleanup() if err := runGazelle(dir, []string{"-go_prefix", "example.com/foo"}); err != nil { t.Fatal(err) } if got, err := os.ReadFile(filepath.Join(dir, "BUILD")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s", string(got), want) } } func TestFixAndUpdateChanges(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "BUILD", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_prefix") load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_test") go_prefix("example.com/foo") go_library( name = "go_default_library", srcs = [ "extra.go", "pure.go", ], library = ":cgo_default_library", visibility = ["//visibility:default"], ) cgo_library( name = "cgo_default_library", srcs = ["cgo.go"], ) `, }, { Path: "pure.go", Content: "package foo", }, { Path: "cgo.go", Content: `package foo import "C" `, }, } cases := []struct { cmd, want string }{ { cmd: "update", want: `load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_library", "go_prefix") go_prefix("example.com/foo") go_library( name = "go_default_library", srcs = [ "cgo.go", "pure.go", ], cgo = True, importpath = "example.com/foo", visibility = ["//visibility:default"], ) cgo_library( name = "cgo_default_library", srcs = ["cgo.go"], ) `, }, { cmd: "fix", want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_prefix") go_prefix("example.com/foo") go_library( name = "go_default_library", srcs = [ "cgo.go", "pure.go", ], cgo = True, importpath = "example.com/foo", visibility = ["//visibility:default"], ) `, }, } for _, c := range cases { t.Run(c.cmd, func(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{c.cmd}); err != nil { t.Fatal(err) } if got, err := os.ReadFile(filepath.Join(dir, "BUILD")); err != nil { t.Fatal(err) } else if string(got) != c.want { t.Fatalf("got %s ; want %s", string(got), c.want) } }) } } func TestFixUnlinkedCgoLibrary(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "BUILD", Content: `load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_library") cgo_library( name = "cgo_default_library", srcs = ["cgo.go"], ) go_library( name = "go_default_library", srcs = ["pure.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], ) `, }, { Path: "pure.go", Content: "package foo", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() want := `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["pure.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], ) ` if err := runGazelle(dir, []string{"fix", "-go_prefix", "example.com/foo"}); err != nil { t.Fatal(err) } if got, err := os.ReadFile(filepath.Join(dir, "BUILD")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s", string(got), want) } } // TestMultipleDirectories checks that all directories in a repository are // indexed but only directories listed on the command line are updated. func TestMultipleDirectories(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "a/BUILD.bazel", Content: `# This file shouldn't be modified. load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["a.go"], importpath = "example.com/foo/x", ) `, }, { Path: "a/a.go", Content: "package a", }, { Path: "b/b.go", Content: ` package b import _ "example.com/foo/x" `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/foo", "b"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ files[1], // should not change { Path: "b/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["b.go"], importpath = "example.com/foo/b", visibility = ["//visibility:public"], deps = ["//a:go_default_library"], ) `, }, }) } func TestErrorOutsideWorkspace(t *testing.T) { files := []testtools.FileSpec{ {Path: "a/"}, {Path: "b/"}, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() skipIfWorkspaceVisible(t, dir) cases := []struct { name, dir, want string args []string }{ { name: "outside workspace", dir: dir, args: nil, want: "WORKSPACE cannot be found", }, { name: "outside repo_root", dir: filepath.Join(dir, "a"), args: []string{"-repo_root", filepath.Join(dir, "b")}, want: "not a subdirectory of repo root", }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if err := runGazelle(c.dir, c.args); err == nil { t.Fatalf("got success; want %q", c.want) } else if !strings.Contains(err.Error(), c.want) { t.Fatalf("got %q; want %q", err, c.want) } }) } } func TestBuildFileNameIgnoresBuild(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, {Path: "BUILD/"}, { Path: "a/BUILD", Content: "!!! parse error", }, { Path: "a.go", Content: "package a", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/foo", "-build_file_name", "BUILD.bazel"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } if _, err := os.Stat(filepath.Join(dir, "BUILD.bazel")); err != nil { t.Errorf("BUILD.bazel not created: %v", err) } } func TestExternalVendor(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: `workspace(name = "banana")`, }, { Path: "a.go", Content: `package foo import _ "golang.org/x/bar" `, }, { Path: "vendor/golang.org/x/bar/bar.go", Content: `package bar import _ "golang.org/x/baz" `, }, { Path: "vendor/golang.org/x/baz/baz.go", Content: "package baz", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/foo", "-external", "vendored"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: config.DefaultValidBuildFileNames[0], Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["a.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = ["//vendor/golang.org/x/bar"], ) `, }, { Path: "vendor/golang.org/x/bar/" + config.DefaultValidBuildFileNames[0], Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importmap = "example.com/foo/vendor/golang.org/x/bar", importpath = "golang.org/x/bar", visibility = ["//visibility:public"], deps = ["//vendor/golang.org/x/baz"], ) `, }, }) } func TestMigrateProtoRules(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//proto:go_proto_library.bzl", "go_proto_library") filegroup( name = "go_default_library_protos", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "go_default_library", srcs = [":go_default_library_protos"], ) `, }, { Path: "foo.proto", Content: `syntax = "proto3"; option go_package = "example.com/repo"; `, }, { Path: "foo.pb.go", Content: `package repo`, }, } for _, tc := range []struct { args []string want string }{ { args: []string{"update", "-go_prefix", "example.com/repo"}, want: ` load("@io_bazel_rules_go//proto:go_proto_library.bzl", "go_proto_library") filegroup( name = "go_default_library_protos", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "go_default_library", srcs = [":go_default_library_protos"], ) `, }, { args: []string{"fix", "-go_prefix", "example.com/repo"}, want: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "repo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", importpath = "example.com/repo", proto = ":repo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }, } { t.Run(tc.args[0], func(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, tc.args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: config.DefaultValidBuildFileNames[0], Content: tc.want, }}) }) } } func TestRemoveProtoDeletesRules(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: config.DefaultValidBuildFileNames[0], Content: ` load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") filegroup( name = "go_default_library_protos", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) proto_library( name = "repo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", importpath = "example.com/repo", proto = ":repo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", srcs = ["extra.go"], embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }, { Path: "extra.go", Content: `package repo`, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"fix", "-go_prefix", "example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["extra.go"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }}) } func TestAddServiceConvertsToGrpc(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "repo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", importpath = "example.com/repo", proto = ":repo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }, { Path: "foo.proto", Content: `syntax = "proto3"; option go_package = "example.com/repo"; service TestService {} `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "repo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "example.com/repo", proto = ":repo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }}) } func TestProtoImportPrefix(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "foo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", importpath = "example.com/repo", proto = ":foo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }, { Path: "foo.proto", Content: `syntax = "proto3";`, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{ "update", "-go_prefix", "example.com/repo", "-proto_import_prefix", "/bar", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: config.DefaultValidBuildFileNames[0], Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "foo_proto", srcs = ["foo.proto"], import_prefix = "/bar", visibility = ["//visibility:public"], ) go_proto_library( name = "repo_go_proto", importpath = "example.com/repo", proto = ":foo_proto", visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":repo_go_proto"], importpath = "example.com/repo", visibility = ["//visibility:public"], ) `, }}) } func TestEmptyGoPrefix(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/foo.go", Content: "package foo", }, { Path: "bar/bar.go", Content: ` package bar import ( _ "fmt" _ "foo" ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", ""} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: filepath.Join("bar", config.DefaultValidBuildFileNames[0]), Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importpath = "bar", visibility = ["//visibility:public"], deps = ["//foo"], ) `, }}) } // TestResolveKeptImportpath checks that Gazelle can resolve dependencies // against a library with a '# keep' comment on its importpath attribute // when the importpath doesn't match what Gazelle would infer. func TestResolveKeptImportpath(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/foo.go", Content: ` package foo import _ "example.com/alt/baz" `, }, { Path: "bar/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["bar.go"], importpath = "example.com/alt/baz", # keep visibility = ["//visibility:public"], ) `, }, { Path: "bar/bar.go", Content: "package bar", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "foo/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["foo.go"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], deps = ["//bar:go_default_library"], ) `, }, { Path: "bar/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["bar.go"], importpath = "example.com/alt/baz", # keep visibility = ["//visibility:public"], ) `, }, }) } // TestResolveVendorSubdirectory checks that Gazelle can resolve libraries // in a vendor directory which is not at the repository root. func TestResolveVendorSubdirectory(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "sub/vendor/example.com/foo/foo.go", Content: "package foo", }, { Path: "sub/bar/bar.go", Content: ` package bar import _ "example.com/foo" `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "sub/vendor/example.com/foo/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importmap = "example.com/repo/sub/vendor/example.com/foo", importpath = "example.com/foo", visibility = ["//visibility:public"], ) `, }, { Path: "sub/bar/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importpath = "example.com/repo/sub/bar", visibility = ["//visibility:public"], deps = ["//sub/vendor/example.com/foo"], ) `, }, }) } // TestDeleteProtoWithDeps checks that Gazelle will delete proto rules with // dependencies after the proto sources are removed. func TestDeleteProtoWithDeps(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/BUILD.bazel", Content: ` load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["extra.go"], embed = [":scratch_go_proto"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], ) proto_library( name = "foo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], deps = ["//foo/bar:bar_proto"], ) go_proto_library( name = "foo_go_proto", importpath = "example.com/repo/foo", proto = ":foo_proto", visibility = ["//visibility:public"], deps = ["//foo/bar:go_default_library"], ) `, }, { Path: "foo/extra.go", Content: "package foo", }, { Path: "foo/bar/bar.proto", Content: ` syntax = "proto3"; option go_package = "example.com/repo/foo/bar"; message Bar {}; `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "foo/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["extra.go"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], ) `, }, }) } func TestCustomRepoNamesMain(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` go_repository( name = "custom_repo", importpath = "example.com/bar", commit = "123456", ) `, }, { Path: "foo.go", Content: ` package foo import _ "example.com/bar" `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix", "example.com/foo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = ["@custom_repo//:bar"], ) `, }, }) } func TestCustomRepoNamesExternal(t *testing.T) { files := []testtools.FileSpec{ { Path: "main/WORKSPACE", Content: `go_repository( name = "custom_repo", importpath = "example.com/bar", commit = "123456", ) `, }, { Path: "ext/WORKSPACE", Content: "", }, { Path: "ext/foo.go", Content: ` package foo import _ "example.com/bar" `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() extDir := filepath.Join(dir, "ext") args := []string{ "-go_prefix=example.com/foo", "-go_naming_convention=import_alias", "-mode=fix", "-repo_root=" + extDir, "-repo_config=" + filepath.Join(dir, "main", "WORKSPACE"), } if err := runGazelle(extDir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "ext/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = ["@custom_repo//:bar"], ) alias( name = "go_default_library", actual = ":foo", visibility = ["//visibility:public"], ) `, }, }) } func TestUpdateReposWithQueryToWorkspace(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "8df59f11fb697743cbb3f26cfb8750395f30471e9eabde0d174c3aebc7a1cd39", urls = [ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b", urls = [ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(nogo = "@bazel_gazelle//:nogo") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "github.com/sirupsen/logrus@v1.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "8df59f11fb697743cbb3f26cfb8750395f30471e9eabde0d174c3aebc7a1cd39", urls = [ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b", urls = [ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(nogo = "@bazel_gazelle//:nogo") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") go_repository( name = "com_github_sirupsen_logrus", importpath = "github.com/sirupsen/logrus", sum = "h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=", version = "v1.3.0", ) gazelle_dependencies() `, }, }) } func TestDeleteRulesInEmptyDir(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_binary") go_library( name = "go_default_library", srcs = [ "bar.go", "foo.go", ], importpath = "example.com/repo", visibility = ["//visibility:private"], ) go_binary( name = "cmd", embed = [":go_default_library"], visibility = ["//visibility:public"], ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-go_prefix=example.com/repo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: "", }, }) } func TestFixWorkspaceWithoutGazelle(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_repository") go_repository( name = "com_example_repo", importpath = "example.com/repo", tag = "1.2.3", ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"fix", "-go_prefix="}); err == nil { t.Error("got success; want error") } else if want := "bazel_gazelle is not declared"; !strings.Contains(err.Error(), want) { t.Errorf("got error %v; want error containing %q", err, want) } } // TestFixGazelle checks that loads of the gazelle macro from the old location // in rules_go are replaced with the new location in @bazel_gazelle. func TestFixGazelle(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "gazelle", "go_library") gazelle(name = "gazelle") # keep go_library(name = "go_default_library") `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, nil); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@bazel_gazelle//:def.bzl", "gazelle") load("@io_bazel_rules_go//go:def.bzl", "go_library") gazelle(name = "gazelle") # keep go_library(name = "go_default_library") `, }, }) } // TestKeepDeps checks rules with keep comments on the rule or on the deps // attribute will not be modified during dependency resolution. Verifies #212. func TestKeepDeps(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") # gazelle:prefix example.com/repo # keep go_library( name = "go_default_library", srcs = ["lib.go"], importpath = "example.com/repo", deps = [":dont_remove"], ) go_test( name = "go_default_test", # keep srcs = ["lib_test.go"], # keep embed = [":go_default_library"], # keep deps = [":dont_remove"], ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, nil); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, files) } func TestDontCreateBuildFileInEmptyDir(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, {Path: "sub/"}, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, nil); err != nil { t.Error(err) } for _, f := range []string{"BUILD.bazel", "sub/BUILD.bazel"} { path := filepath.Join(dir, filepath.FromSlash(f)) _, err := os.Stat(path) if err == nil { t.Errorf("%s: build file was created", f) } } } // TestNoIndex checks that gazelle does not index existing or generated // library rules with the flag -index=false. Verifies #384. func TestNoIndex(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/foo.go", Content: ` package foo import _ "example.com/bar" `, }, { Path: "third_party/example.com/bar/bar.go", Content: "package bar", }, { Path: "third_party/BUILD.bazel", Content: "# gazelle:prefix", }, { Path: "third_party/example.com/bar/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importpath = "example.com/bar", visibility = ["//visibility:public"], ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{ "-go_prefix=example.com/repo", "-external=vendored", "-index=false", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: "foo/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], deps = ["//vendor/example.com/bar"], ) `, }}) } // TestNoIndexNoRecurse checks that gazelle behaves correctly with the flags // -r=false -index=false. Gazelle should not generate build files in // subdirectories and should not resolve dependencies to local libraries. func TestNoIndexNoRecurse(t *testing.T) { barBuildFile := testtools.FileSpec{ Path: "foo/bar/BUILD.bazel", Content: "# this should not be updated because -r=false", } files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/foo.go", Content: `package foo import ( _ "example.com/dep/baz" ) `, }, barBuildFile, { Path: "foo/bar/bar.go", Content: "package bar", }, { Path: "third_party/baz/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") # this should be ignored because -index=false go_library( name = "baz", srcs = ["baz.go"], importpath = "example.com/dep/baz", visibility = ["//visibility:public"], ) `, }, { Path: "third_party/baz/baz.go", Content: "package baz", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{ "-go_prefix=example.com/repo", "-external=vendored", "-r=false", "-index=false", "foo", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "foo/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], deps = ["//vendor/example.com/dep/baz"], ) `, }, barBuildFile, }) } // TestNoIndexRecurse checks that gazelle behaves correctly with the flags // -r=true -index=false. Gazelle should generate build files in directories // and subdirectories, but should not resolve dependencies to local libraries. func TestNoIndexRecurse(t *testing.T) { files := []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "foo/foo.go", Content: `package foo import ( _ "example.com/dep/baz" ) `, }, { Path: "foo/bar/bar.go", Content: "package bar", }, { Path: "third_party/baz/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") # this should be ignored because -index=false go_library( name = "baz", srcs = ["baz.go"], importpath = "example.com/dep/baz", visibility = ["//visibility:public"], ) `, }, { Path: "third_party/baz/baz.go", Content: "package baz", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{ "-go_prefix=example.com/repo", "-external=vendored", "-r=true", "-index=false", "foo", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "foo/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], deps = ["//vendor/example.com/dep/baz"], ) `, }, { Path: "foo/bar/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importpath = "example.com/repo/foo/bar", visibility = ["//visibility:public"], ) `, }, }) } // TestSubdirectoryPrefixExternal checks that directives set in subdirectories // may be used in dependency resolution. Verifies #412. func TestSubdirectoryPrefixExternal(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: "# gazelle:prefix", }, { Path: "sub/BUILD.bazel", Content: "# gazelle:prefix example.com/sub", }, { Path: "sub/sub.go", Content: ` package sub import ( _ "example.com/sub/missing" _ "example.com/external" ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"-external=vendored", "-index=false"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "sub/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix example.com/sub go_library( name = "sub", srcs = ["sub.go"], importpath = "example.com/sub", visibility = ["//visibility:public"], deps = [ "//sub/missing", "//vendor/example.com/external", ], ) `, }, }) } func TestGoGrpcProtoFlag(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@rules_proto//proto:defs.bzl", "proto_library") go_proto_library( name = "foo_go_proto", importpath = "example.com/repo/foo", proto = ":foo_proto", visibility = ["//visibility:public"], ) proto_library( name = "foo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":foo_go_proto"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], ) `, }, { Path: "foo.proto", Content: ` syntax = "proto3"; option go_package = "example.com/repo/foo"; message Bar {}; `, }, { Path: "service/BUILD.bazel", Content: ` load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") go_proto_library( name = "service_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "example.com/repo/service", proto = ":service_proto", visibility = ["//visibility:public"], ) proto_library( name = "service_proto", srcs = ["service.proto"], visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":service_go_proto"], importpath = "example.com/repo/service", visibility = ["//visibility:public"], ) `, }, { Path: "service/service.proto", Content: ` syntax = "proto3"; option go_package = "example.com/repo/service"; service TestService {} `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update", "-go_grpc_compiler", "//foo", "-go_proto_compiler", "//bar"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") go_proto_library( name = "foo_go_proto", compilers = ["//bar"], importpath = "example.com/repo/foo", proto = ":foo_proto", visibility = ["//visibility:public"], ) proto_library( name = "foo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":foo_go_proto"], importpath = "example.com/repo/foo", visibility = ["//visibility:public"], ) `, }, { Path: "service/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") go_proto_library( name = "service_go_proto", compilers = ["//foo"], importpath = "example.com/repo/service", proto = ":service_proto", visibility = ["//visibility:public"], ) proto_library( name = "service_proto", srcs = ["service.proto"], visibility = ["//visibility:public"], ) go_library( name = "go_default_library", embed = [":service_go_proto"], importpath = "example.com/repo/service", visibility = ["//visibility:public"], ) `, }, }) } // TestMapKind tests the gazelle:map_kind directive. // Verifies #448 func TestMapKind(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` # gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library `, }, { Path: "root_lib.go", Content: `package mapkind`, }, { Path: "enabled/BUILD.bazel", Content: "# gazelle:map_kind go_library my_library //tools/go:def.bzl", }, { Path: "enabled/enabled_lib.go", Content: `package enabled`, }, { Path: "enabled/inherited/BUILD.bazel", }, { Path: "enabled/inherited/inherited_lib.go", Content: `package inherited`, }, { Path: "enabled/existing_rules/mapped/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") # An existing rule with a mapped type is updated my_library( name = "go_default_library", srcs = ["deleted_file.go", "mapped_lib.go"], importpath = "example.com/mapkind/enabled/existing_rules/mapped", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/mapped/mapped_lib.go", Content: `package mapped`, }, { Path: "enabled/existing_rules/mapped/mapped_lib2.go", Content: `package mapped`, }, { Path: "enabled/existing_rules/unmapped/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # An existing rule with an unmapped type is updated go_library( name = "go_default_library", srcs = ["unmapped_lib.go"], importpath = "example.com/mapkind/enabled/existing_rules/unmapped", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/unmapped/unmapped_lib.go", Content: `package unmapped`, }, { Path: "enabled/existing_rules/clean/BUILD.bazel", Content: `load("//tools/go:def.bzl", "my_go_library") # gazelle:go_naming_convention import # gazelle:map_kind go_library my_go_library //tools/go:def.bzl my_go_library( name = "clean", srcs = [ "foo.go", "bar.go", "buz.go", ], importpath = "example.com/mapkind/enabled/existing_rules/clean", visibility = ["//visibility:private"], ) `, }, { Path: "enabled/existing_rules/clean_binary/BUILD.bazel", Content: `load("//tools/go:def.bzl", "my_go_binary", "my_go_library") # gazelle:go_naming_convention import # gazelle:map_kind go_binary my_go_binary //tools/go:def.bzl # gazelle:map_kind go_library my_go_library //tools/go:def.bzl my_go_library( name = "clean_binary_lib", srcs = ["main.go"], importpath = "example.com/mapkind/enabled/existing_rules/clean_binary", visibility = ["//visibility:private"], ) my_go_binary( name = "clean_binary", embed = [":clean_binary_lib"], visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/nobuild/nobuild_lib.go", Content: `package nobuild`, }, { Path: "enabled/overridden/BUILD.bazel", Content: "# gazelle:map_kind go_library overridden_library //tools/overridden:def.bzl", }, { Path: "enabled/overridden/overridden_lib.go", Content: `package overridden`, }, { Path: "disabled/BUILD.bazel", }, { Path: "disabled/disabled_lib.go", Content: `package disabled`, }, { Path: "enabled/multiple_mappings/BUILD.bazel", Content: ` # gazelle:map_kind go_binary go_binary //tools/go:def.bzl # gazelle:map_kind go_library go_library //tools/go:def.bzl `, }, { Path: "enabled/multiple_mappings/multiple_mappings.go", Content: ` package main func main() {}`, }, { Path: "depend_on_mapped_kind/lib.go", Content: `package depend_on_mapped_kind import ( _ "example.com/mapkind/disabled" _ "example.com/mapkind/enabled" _ "example.com/mapkind/enabled/existing_rules/mapped" _ "example.com/mapkind/enabled/existing_rules/unmapped" _ "example.com/mapkind/enabled/overridden" )`, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"-external=vendored"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library go_library( name = "go_default_library", srcs = ["root_lib.go"], importpath = "example.com/mapkind", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") # gazelle:map_kind go_library my_library //tools/go:def.bzl my_library( name = "go_default_library", srcs = ["enabled_lib.go"], importpath = "example.com/mapkind/enabled", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/inherited/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") my_library( name = "go_default_library", srcs = ["inherited_lib.go"], importpath = "example.com/mapkind/enabled/inherited", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/overridden/BUILD.bazel", Content: ` load("//tools/overridden:def.bzl", "overridden_library") # gazelle:map_kind go_library overridden_library //tools/overridden:def.bzl overridden_library( name = "go_default_library", srcs = ["overridden_lib.go"], importpath = "example.com/mapkind/enabled/overridden", visibility = ["//visibility:public"], ) `, }, { Path: "disabled/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["disabled_lib.go"], importpath = "example.com/mapkind/disabled", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/mapped/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") # An existing rule with a mapped type is updated my_library( name = "go_default_library", srcs = [ "mapped_lib.go", "mapped_lib2.go", ], importpath = "example.com/mapkind/enabled/existing_rules/mapped", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/unmapped/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") # An existing rule with an unmapped type is updated my_library( name = "go_default_library", srcs = ["unmapped_lib.go"], importpath = "example.com/mapkind/enabled/existing_rules/unmapped", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/existing_rules/clean/BUILD.bazel", Content: ` # gazelle:go_naming_convention import # gazelle:map_kind go_library my_go_library //tools/go:def.bzl `, }, { Path: "enabled/existing_rules/clean_binary/BUILD.bazel", Content: ` # gazelle:go_naming_convention import # gazelle:map_kind go_binary my_go_binary //tools/go:def.bzl # gazelle:map_kind go_library my_go_library //tools/go:def.bzl `, }, { Path: "enabled/existing_rules/nobuild/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "my_library") my_library( name = "go_default_library", srcs = ["nobuild_lib.go"], importpath = "example.com/mapkind/enabled/existing_rules/nobuild", visibility = ["//visibility:public"], ) `, }, { Path: "enabled/multiple_mappings/BUILD.bazel", Content: ` load("//tools/go:def.bzl", "go_binary", "go_library") # gazelle:map_kind go_binary go_binary //tools/go:def.bzl # gazelle:map_kind go_library go_library //tools/go:def.bzl go_library( name = "go_default_library", srcs = ["multiple_mappings.go"], importpath = "example.com/mapkind/enabled/multiple_mappings", visibility = ["//visibility:private"], ) go_binary( name = "multiple_mappings", embed = [":go_default_library"], visibility = ["//visibility:public"], ) `, }, { Path: "depend_on_mapped_kind/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["lib.go"], importpath = "example.com/mapkind/depend_on_mapped_kind", visibility = ["//visibility:public"], deps = [ "//disabled:go_default_library", "//enabled:go_default_library", "//enabled/existing_rules/mapped:go_default_library", "//enabled/existing_rules/unmapped:go_default_library", "//enabled/overridden:go_default_library", ], ) `, }, }) } func TestMapKindEdgeCases(t *testing.T) { for name, tc := range map[string]struct { before []testtools.FileSpec after []testtools.FileSpec }{ "new generated rule applies map_kind": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "existing generated rule with non-renaming mapping applied applies map_kind": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl `, }, { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, { Path: "dir/file.go", Content: "package dir", }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "existing generated rule without non-renaming mapping applied applies map_kind": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl `, }, { Path: "dir/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, { Path: "dir/file.go", Content: "package dir", }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "existing generated rule without renaming mapping applied applies map_kind": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library custom_go_library //custom:def.bzl `, }, { Path: "dir/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, { Path: "dir/file.go", Content: "package dir", }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "custom_go_library") custom_go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "existing generated rule with renaming mapping applied preserves map_kind": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library custom_go_library //custom:def.bzl `, }, { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "custom_go_library") custom_go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, { Path: "dir/file.go", Content: "package dir", }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "custom_go_library") custom_go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "unrelated non-generated non-map_kind'd rule of same kind applies map_kind if other rule is generated": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "custom_lib", srcs = ["custom_lib.go"], ) `, }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "custom_lib", srcs = ["custom_lib.go"], ) go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "unrelated non-generated non-renaming map_kind'd rule of same kind keeps map_kind if other rule is generated": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "custom_lib", srcs = ["custom_lib.go"], ) `, }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library") go_library( name = "custom_lib", srcs = ["custom_lib.go"], ) go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "unrelated non-generated non-renaming map_kind'd rule keeps map_kind if other generated rule is newly generated": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl # gazelle:map_kind go_test go_test //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_test") go_test( name = "custom_test", srcs = ["custom_test.java"], ) `, }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library", "go_test") go_test( name = "custom_test", srcs = ["custom_test.java"], ) go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "unrelated non-generated non-renaming map_kind'd rule keeps map_kind if other generated rule already existed": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library go_library //custom:def.bzl # gazelle:map_kind go_test go_test //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library", "go_test") go_test( name = "custom_test", srcs = ["custom_test.java"], ) go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//custom:def.bzl", "go_library", "go_test") go_test( name = "custom_test", srcs = ["custom_test.java"], ) go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, "transitive remappings are applied": { before: []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library custom_go_library //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `# gazelle:map_kind custom_go_library other_custom_go_library //another/custom:def.bzl `, }, }, after: []testtools.FileSpec{ { Path: "dir/BUILD.bazel", Content: `load("//another/custom:def.bzl", "other_custom_go_library") # gazelle:map_kind custom_go_library other_custom_go_library //another/custom:def.bzl other_custom_go_library( name = "go_default_library", srcs = ["file.go"], importpath = "example.com/mapkind/dir", visibility = ["//visibility:public"], ) `, }, }, }, } { t.Run(name, func(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, tc.before) t.Cleanup(cleanup) if err := runGazelle(dir, []string{"-external=vendored"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, tc.after) }) } } func TestMapKindLoop(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: `# gazelle:prefix example.com/mapkind # gazelle:go_naming_convention go_default_library # gazelle:map_kind go_library custom_go_library //custom:def.bzl `, }, { Path: "dir/file.go", Content: "package dir", }, { Path: "dir/BUILD.bazel", Content: `# gazelle:map_kind custom_go_library go_library @io_bazel_rules_go//go:def.bzl `, }, }) t.Cleanup(cleanup) err := runGazelle(dir, []string{"-external=vendored"}) if err == nil { t.Fatal("Expected error running gazelle with map_kind loop") } msg := err.Error() if !strings.Contains(msg, "looking up mapped kind: found loop of map_kind replacements: go_library -> custom_go_library -> go_library") { t.Fatalf("Expected error to contain useful descriptors but was %q", msg) } } // TestMapKindEmbeddedResolve tests the gazelle:map_kind properly resolves // dependencies for embedded rules (see #1162). func TestMapKindEmbeddedResolve(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` # gazelle:prefix example.com/mapkind # gazelle:map_kind go_library my_go_library //:my.bzl `, }, { Path: "a/a.proto", Content: ` syntax = "proto3"; package test; option go_package = "example.com/mapkind/a"; `, }, { Path: "b/b.proto", Content: ` syntax = "proto3"; package test; option go_package = "example.com/mapkind/b"; import "a/a.proto"; `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"-external=vendored"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "a/BUILD.bazel", Content: ` load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") load("//:my.bzl", "my_go_library") proto_library( name = "a_proto", srcs = ["a.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "a_go_proto", importpath = "example.com/mapkind/a", proto = ":a_proto", visibility = ["//visibility:public"], ) my_go_library( name = "a", embed = [":a_go_proto"], importpath = "example.com/mapkind/a", visibility = ["//visibility:public"], ) `, }, { Path: "b/BUILD.bazel", Content: ` load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") load("//:my.bzl", "my_go_library") proto_library( name = "b_proto", srcs = ["b.proto"], visibility = ["//visibility:public"], deps = ["//a:a_proto"], ) go_proto_library( name = "b_go_proto", importpath = "example.com/mapkind/b", proto = ":b_proto", visibility = ["//visibility:public"], deps = ["//a"], ) my_go_library( name = "b", embed = [":b_go_proto"], importpath = "example.com/mapkind/b", visibility = ["//visibility:public"], ) `, }, }) } // TestMinimalModuleCompatibilityAliases checks that importpath_aliases // are emitted for go_libraries when needed. This can't easily be checked // in language/go because the generator tests don't support running at // the repository root or with additional flags, both of which are required. func TestMinimalModuleCompatibilityAliases(t *testing.T) { files := []testtools.FileSpec{ { Path: "go.mod", Content: "module example.com/foo/v2", }, { Path: "foo.go", Content: "package foo", }, { Path: "bar/bar.go", Content: "package bar", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update", "-repo_root", dir, "-go_prefix", "example.com/foo/v2", "-go_repository_mode", "-go_repository_module_mode"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/foo/v2", importpath_aliases = ["example.com/foo"], visibility = ["//visibility:public"], ) `, }, { Path: "bar/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "bar", srcs = ["bar.go"], importpath = "example.com/foo/v2/bar", importpath_aliases = ["example.com/foo/bar"], visibility = ["//visibility:public"], ) `, }, }) } // TestGoImportVisibility checks that submodules implicitly declared with // go_repository rules in the repo config file (WORKSPACE) have visibility // for rules generated in internal directories where appropriate. // Verifies #619. func TestGoImportVisibility(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` go_repository( name = "com_example_m_logging", importpath = "example.com/m/logging", ) `, }, { Path: "internal/version/version.go", Content: "package version", }, { Path: "internal/version/version_test.go", Content: "package version", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update", "-go_prefix", "example.com/m"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: "internal/version/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "version", srcs = ["version.go"], importpath = "example.com/m/internal/version", visibility = [ "//:__subpackages__", "@com_example_m_logging//:__subpackages__", ], ) go_test( name = "version_test", srcs = ["version_test.go"], embed = [":version"], ) `, }}) } // TestGoInternalVisibility_TopLevel checks that modules that are // named internal/ expand visibility to repos that have a sibling // importpath. // // Verifies #960 func TestGoInternalVisibility_TopLevel(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: `go_repository(name="org_modernc_ccgo", importpath="modernc.org/ccgo")`, }, { Path: "BUILD.bazel", Content: `# gazelle:prefix modernc.org/internal`, }, { Path: "internal.go", Content: "package internal", }, { Path: "buffer/buffer.go", Content: "package buffer", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix modernc.org/internal go_library( name = "internal", srcs = ["internal.go"], importpath = "modernc.org/internal", visibility = [ "//:__subpackages__", "@org_modernc_ccgo//:__subpackages__", ], ) `, }, { Path: "buffer/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "buffer", srcs = ["buffer.go"], importpath = "modernc.org/internal/buffer", visibility = [ "//:__subpackages__", "@org_modernc_ccgo//:__subpackages__", ], ) `, }, }) } func TestImportCollision(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "go.mod", Content: ` module example.com/importcases go 1.13 require ( github.com/Selvatico/go-mocket v1.0.7 github.com/selvatico/go-mocket v1.0.7 ) `, }, { Path: "go.sum", Content: ` github.com/Selvatico/go-mocket v1.0.7/go.mod h1:4gO2v+uQmsL+jzQgLANy3tyEFzaEzHlymVbZ3GP2Oes= github.com/selvatico/go-mocket v1.0.7/go.mod h1:7bSWzuNieCdUlanCVu3w0ppS0LvDtPAZmKBIlhoTcp8= `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "--from_file=go.mod"} errMsg := "imports github.com/Selvatico/go-mocket and github.com/selvatico/go-mocket resolve to the same repository rule name com_github_selvatico_go_mocket" if err := runGazelle(dir, args); err == nil { t.Fatal("expected error, got nil") } else if err.Error() != errMsg { t.Errorf("want %s, got %s", errMsg, err.Error()) } } func TestImportCollisionWithReplace(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: "# gazelle:repo bazel_gazelle", }, { Path: "go.mod", Content: ` module github.com/linzhp/go_examples/importcases go 1.13 require ( github.com/Selvatico/go-mocket v1.0.7 github.com/selvatico/go-mocket v0.0.0-00010101000000-000000000000 ) replace github.com/selvatico/go-mocket => github.com/Selvatico/go-mocket v1.0.7 `, }, { Path: "go.sum", Content: ` github.com/Selvatico/go-mocket v1.0.7/go.mod h1:4gO2v+uQmsL+jzQgLANy3tyEFzaEzHlymVbZ3GP2Oes= `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "--from_file=go.mod"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_gazelle//:deps.bzl", "go_repository") # gazelle:repo bazel_gazelle go_repository( name = "com_github_selvatico_go_mocket", importpath = "github.com/selvatico/go-mocket", replace = "github.com/Selvatico/go-mocket", sum = "h1:sXuFMnMfVL9b/Os8rGXPgbOFbr4HJm8aHsulD/uMTUk=", version = "v1.0.7", ) `, }, }) } // TestUpdateReposWithGlobalBuildTags is a regresion test for issue #711. // It also ensures that existings build_tags get merged with requested build_tags. func TestUpdateReposWithGlobalBuildTags(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_gazelle//:deps.bzl", "go_repository") # gazelle:repo bazel_gazelle go_repository( name = "com_github_selvatico_go_mocket", build_tags = [ "bar", ], importpath = "github.com/selvatico/go-mocket", replace = "github.com/Selvatico/go-mocket", sum = "h1:sXuFMnMfVL9b/Os8rGXPgbOFbr4HJm8aHsulD/uMTUk=", version = "v1.0.7", ) `, }, { Path: "go.mod", Content: ` module github.com/linzhp/go_examples/importcases go 1.13 require ( github.com/Selvatico/go-mocket v1.0.7 github.com/selvatico/go-mocket v0.0.0-00010101000000-000000000000 ) replace github.com/selvatico/go-mocket => github.com/Selvatico/go-mocket v1.0.7 `, }, { Path: "go.sum", Content: ` github.com/Selvatico/go-mocket v1.0.7/go.mod h1:4gO2v+uQmsL+jzQgLANy3tyEFzaEzHlymVbZ3GP2Oes= `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "--from_file=go.mod", "--build_tags=bar,foo"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_gazelle//:deps.bzl", "go_repository") # gazelle:repo bazel_gazelle go_repository( name = "com_github_selvatico_go_mocket", build_tags = [ "bar", "foo", ], importpath = "github.com/selvatico/go-mocket", replace = "github.com/Selvatico/go-mocket", sum = "h1:sXuFMnMfVL9b/Os8rGXPgbOFbr4HJm8aHsulD/uMTUk=", version = "v1.0.7", ) `, }, }) } func TestMatchProtoLibrary(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "proto/BUILD.bazel", Content: ` load("@rules_proto//proto:defs.bzl", "proto_library") # gazelle:prefix example.com/foo proto_library( name = "existing_proto", srcs = ["foo.proto"], ) `, }, { Path: "proto/foo.proto", Content: `syntax = "proto3";`, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "proto/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") # gazelle:prefix example.com/foo proto_library( name = "existing_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_proto_library( name = "foo_go_proto", importpath = "example.com/foo", proto = ":existing_proto", visibility = ["//visibility:public"], ) go_library( name = "foo", embed = [":foo_go_proto"], importpath = "example.com/foo", visibility = ["//visibility:public"], )`, }, }) } func TestConfigLang(t *testing.T) { // Gazelle is run with "-lang=proto". files := []testtools.FileSpec{ {Path: "WORKSPACE"}, // Verify that Gazelle does not create a BUILD file. {Path: "foo/foo.go", Content: "package foo"}, // Verify that Gazelle only creates the proto rule. {Path: "pb/pb.go", Content: "package pb"}, {Path: "pb/pb.proto", Content: `syntax = "proto3";`}, // Verify that Gazelle does create a BUILD file, because of the override. {Path: "bar/BUILD.bazel", Content: "# gazelle:lang"}, {Path: "bar/bar.go", Content: "package bar"}, {Path: "baz/BUILD.bazel", Content: "# gazelle:lang go,proto"}, {Path: "baz/baz.go", Content: "package baz"}, // Verify that Gazelle does not index go_library rules in // or //baz/protos. // In those directories, lang is set to proto by flag and directive, respectively. // Confirm it does index and resolve a rule in a directory where go is activated. {Path: "invisible1.go", Content: "package invisible1"}, {Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix root go_library( name = "go_default_library", srcs = ["invisible1.go"], importpath = "root", visibility = ["//visibility:public"], ) `}, {Path: "baz/protos/invisible2.go", Content: "package invisible2"}, {Path: "baz/protos/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:lang proto # gazelle:prefix github.com/rule_indexing/invisible2 go_library( name = "go_default_library", srcs = ["invisible2.go"], importpath = "github.com/rule_indexing/invisible2", visibility = ["//visibility:public"], ) `}, {Path: "visible/visible.go", Content: "package visible"}, {Path: "visible/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:lang go,proto # gazelle:prefix github.com/rule_indexing/visible go_library( name = "go_default_library", srcs = ["visible.go"], importpath = "github.com/rule_indexing/visible", visibility = ["//visibility:public"], ) `}, {Path: "baz/test_no_index/test_no_index.go", Content: ` package test_no_index import ( _ "github.com/rule_indexing/invisible1" _ "github.com/rule_indexing/invisible2" _ "github.com/rule_indexing/visible" ) `}, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"-lang", "proto"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: filepath.Join("foo", "BUILD.bazel"), NotExist: true, }, { Path: filepath.Join("pb", "BUILD.bazel"), Content: ` load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "pb_proto", srcs = ["pb.proto"], visibility = ["//visibility:public"], )`, }, { Path: filepath.Join("bar", "BUILD.bazel"), Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:lang go_library( name = "go_default_library", srcs = ["bar.go"], importpath = "root/bar", visibility = ["//visibility:public"], )`, }, { Path: filepath.Join("baz", "BUILD.bazel"), Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:lang go,proto go_library( name = "go_default_library", srcs = ["baz.go"], importpath = "root/baz", visibility = ["//visibility:public"], )`, }, {Path: "baz/test_no_index/BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["test_no_index.go"], importpath = "root/baz/test_no_index", visibility = ["//visibility:public"], deps = [ "//visible:go_default_library", "@com_github_rule_indexing_invisible1//:go_default_library", "@com_github_rule_indexing_invisible2//:go_default_library", ], ) `}, }) } func TestUpdateRepos_LangFilter(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, }) defer cleanup() args := []string{"update-repos", "-lang=proto", "github.com/sirupsen/logrus@v1.3.0"} err := runGazelle(dir, args) if err == nil { t.Fatal("expected an error, got none") } if !strings.Contains(err.Error(), "no languages can update repositories") { t.Fatalf("unexpected error: %+v", err) } } func TestGoGenerateProto(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "proto/BUILD.bazel", Content: `# gazelle:go_generate_proto false # gazelle:prefix example.com/proto `, }, { Path: "proto/foo.proto", Content: `syntax = "proto3";`, }, { Path: "proto/foo.pb.go", Content: "package proto", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "proto/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@rules_proto//proto:defs.bzl", "proto_library") # gazelle:go_generate_proto false # gazelle:prefix example.com/proto proto_library( name = "foo_proto", srcs = ["foo.proto"], visibility = ["//visibility:public"], ) go_library( name = "proto", srcs = ["foo.pb.go"], importpath = "example.com/proto", visibility = ["//visibility:public"], )`, }, }) } func TestGoMainLibraryRemoved(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` # gazelle:prefix example.com # gazelle:go_naming_convention import `, }, { Path: "cmd/foo/BUILD.bazel", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "foo_lib", srcs = ["foo.go"], importpath = "example.com/cmd/foo", visibility = ["//visibility:private"], ) go_binary( name = "foo", embed = [":foo_lib"], visibility = ["//visibility:public"], ) `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "cmd/foo/BUILD.bazel", Content: "", }, }) } func TestUpdateReposOldBoilerplateNewRepo(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "golang.org/x/mod@v0.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") go_repository( name = "org_golang_x_mod", importpath = "golang.org/x/mod", sum = "h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=", version = "v0.3.0", ) gazelle_dependencies() `, }, }) } func TestUpdateReposSkipsDirectiveRepo(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() # gazelle:repository go_repository name=org_golang_x_mod importpath=golang.org/x/mod `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "golang.org/x/mod@v0.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() # gazelle:repository go_repository name=org_golang_x_mod importpath=golang.org/x/mod `, }, }) } func TestUpdateReposOldBoilerplateNewMacro(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") gazelle_dependencies() `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "-to_macro=deps.bzl%deps", "golang.org/x/mod@v0.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains() load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") load("//:deps.bzl", "deps") # gazelle:repository_macro deps.bzl%deps deps() gazelle_dependencies() `, }, }) } func TestUpdateReposNewBoilerplateNewRepo(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains() gazelle_dependencies() `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "golang.org/x/mod@v0.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_repository( name = "org_golang_x_mod", importpath = "golang.org/x/mod", sum = "h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=", version = "v0.3.0", ) go_rules_dependencies() go_register_toolchains() gazelle_dependencies() `, }, }) } func TestUpdateReposNewBoilerplateNewMacro(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains() gazelle_dependencies() `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() args := []string{"update-repos", "-to_macro=deps.bzl%deps", "golang.org/x/mod@v0.3.0"} if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "2697f6bc7c529ee5e6a2d9799870b9ec9eaeb3ee7d70ed50b87a2c2c97e13d9e", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.23.8/rules_go-v0.23.8.tar.gz", ], ) http_archive( name = "bazel_gazelle", sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz", ], ) load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("//:deps.bzl", "deps") # gazelle:repository_macro deps.bzl%deps deps() go_rules_dependencies() go_register_toolchains() gazelle_dependencies() `, }, }) } func TestExternalOnly(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "foo/foo.go", Content: `package foo import _ "golang.org/x/baz" `, }, { Path: "foo/foo_test.go", Content: `package foo_test import _ "golang.org/x/baz" import _ "example.com/foo" `, }, { Path: "foo/BUILD.bazel", Content: `# gazelle:prefix example.com/foo load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = ["@org_golang_x_baz//:go_default_library"], ) go_test( name = "foo_test", srcs = ["foo_test.go"], embed = [":foo"], )`, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() var args []string if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "foo/BUILD.bazel", Content: `# gazelle:prefix example.com/foo load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "foo", srcs = ["foo.go"], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = ["@org_golang_x_baz//:go_default_library"], ) go_test( name = "foo_test", srcs = ["foo_test.go"], deps = [ ":foo", "@org_golang_x_baz//:go_default_library", ], )`, }, }) } func TestFindRulesGoVersionWithWORKSPACE(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: ` load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "7b9bbe3ea1fccb46dcfa6c3f3e29ba7ec740d8733370e21cdc8937467b4a4349", urls = [ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz", "https://github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz", ], ) `, }, { Path: "foo_illumos.go", Content: ` // illumos not supported in rules_go v0.22.4 package foo `, }, { Path: "BUILD.bazel", Content: ` # gazelle:prefix example.com/foo `, }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"update"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` # gazelle:prefix example.com/foo `, }, }) } func TestPlatformSpecificEmbedsrcs(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix example.com/foo go_library( name = "foo", embedsrcs = ["deleted.txt"], importpath = "example.com/foo", srcs = ["foo.go"], ) `, }, { Path: "foo.go", Content: ` // +build windows package foo import _ "embed" //go:embed windows.txt var s string `, }, { Path: "windows.txt", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"update"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix example.com/foo go_library( name = "foo", srcs = ["foo.go"], embedsrcs = select({ "@io_bazel_rules_go//go/platform:windows": [ "windows.txt", ], "//conditions:default": [], }), importpath = "example.com/foo", visibility = ["//visibility:public"], ) `, }, }) } // Checks that go:embed directives with spaces and quotes are parsed correctly. // This probably belongs in //language/go:go_test, but we need file names with // spaces, and Bazel doesn't allow those in runfiles, which that test depends // on. func TestQuotedEmbedsrcs(t *testing.T) { files := []testtools.FileSpec{ { Path: "WORKSPACE", }, { Path: "BUILD.bazel", Content: "# gazelle:prefix example.com/foo", }, { Path: "foo.go", Content: strings.Join([]string{ "package foo", "import \"embed\"", "//go:embed q1.txt q2.txt \"q 3.txt\" `q 4.txt`", "var fs embed.FS", }, "\n"), }, { Path: "q1.txt", }, { Path: "q2.txt", }, { Path: "q 3.txt", }, { Path: "q 4.txt", }, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"update"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{{ Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") # gazelle:prefix example.com/foo go_library( name = "foo", srcs = ["foo.go"], embedsrcs = [ "q 3.txt", "q 4.txt", "q1.txt", "q2.txt", ], importpath = "example.com/foo", visibility = ["//visibility:public"], ) `, }}) } // TestUpdateReposDoesNotModifyGoSum verifies that commands executed by // update-repos do not modify go.sum, particularly 'go mod download' when // a sum is missing. Verifies #990. // // This could also be tested in language/go/update_import_test.go, but that // test relies on stubs for speed, and it's important to run the real // go command here. func TestUpdateReposDoesNotModifyGoSum(t *testing.T) { if testing.Short() { // Test may download small files over network. t.Skip() } goSumFile := testtools.FileSpec{ // go.sum only contains the sum for the mod file, not the content. // This is common for transitive dependencies not needed by the main module. Path: "go.sum", Content: "golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\n", } files := []testtools.FileSpec{ { Path: "WORKSPACE", Content: "# gazelle:repo bazel_gazelle", }, { Path: "go.mod", Content: ` module test go 1.16 require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 `, }, goSumFile, } dir, cleanup := testtools.CreateFiles(t, files) defer cleanup() if err := runGazelle(dir, []string{"update-repos", "-from_file=go.mod"}); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{goSumFile}) } func TestResolveGoStaticFromGoMod(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "go.mod", Content: ` module example.com/use go 1.19 require example.com/dep v1.0.0 `, }, { Path: "use.go", Content: ` package use import _ "example.com/dep/pkg" `, }, }) defer cleanup() args := []string{ "-go_prefix=example.com/use", "-external=static", "-go_naming_convention_external=import", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } testtools.CheckFiles(t, dir, []testtools.FileSpec{ { Path: "BUILD.bazel", Content: ` load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "use", srcs = ["use.go"], importpath = "example.com/use", visibility = ["//visibility:public"], deps = ["@com_example_dep//pkg"], ) `, }, }) } func TestMigrateSelectFromWorkspaceToBzlmod(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "MODULE.bazel", Content: `bazel_dep(name = "rules_go", version = "0.39.1", repo_name = "my_rules_go")`, }, { Path: "BUILD", Content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = [ "bar.go", "foo.go", "foo_android.go", "foo_android_build_tag.go", ], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = select({ "@io_bazel_rules_go//go/platform:android": [ "//outer", "//outer/inner", "//outer_android_build_tag", "//outer_android_suffix", "@com_github_jr_hacker_tools//:go_default_library", ], "@io_bazel_rules_go//go/platform:linux": [ "//outer", "//outer/inner", "@com_github_jr_hacker_tools//:go_default_library", ], "//conditions:default": [], }), ) `, }, { Path: "foo.go", Content: ` // +build linux package foo import ( _ "example.com/foo/outer" _ "example.com/foo/outer/inner" _ "github.com/jr_hacker/tools" ) `, }, { Path: "foo_android_build_tag.go", Content: ` // +build android package foo import ( _ "example.com/foo/outer_android_build_tag" ) `, }, { Path: "foo_android.go", Content: ` package foo import ( _ "example.com/foo/outer_android_suffix" ) `, }, { Path: "bar.go", Content: `// +build linux package foo `, }, {Path: "outer/outer.go", Content: "package outer"}, {Path: "outer_android_build_tag/outer.go", Content: "package outer_android_build_tag"}, {Path: "outer_android_suffix/outer.go", Content: "package outer_android_suffix"}, {Path: "outer/inner/inner.go", Content: "package inner"}, }) want := `load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "foo", srcs = [ "bar.go", "foo.go", "foo_android.go", "foo_android_build_tag.go", ], importpath = "example.com/foo", visibility = ["//visibility:public"], deps = select({ "@my_rules_go//go/platform:android": [ "//outer", "//outer/inner", "//outer_android_build_tag", "//outer_android_suffix", "@com_github_jr_hacker_tools//:go_default_library", ], "@my_rules_go//go/platform:linux": [ "//outer", "//outer/inner", "@com_github_jr_hacker_tools//:go_default_library", ], "//conditions:default": [], }), ) ` defer cleanup() if err := runGazelle(dir, []string{"-go_prefix", "example.com/foo"}); err != nil { t.Fatal(err) } if got, err := os.ReadFile(filepath.Join(dir, "BUILD")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s; diff %s", string(got), want, cmp.Diff(string(got), want)) } } func TestUpdateReposWithBzlmodWithToMacro(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "go.mod", Content: ` module example.com/foo/v2 go 1.19 require ( github.com/stretchr/testify v1.8.4 ) `, }, }) t.Cleanup(cleanup) args := []string{ "update-repos", "-from_file=go.mod", "-to_macro=go_deps.bzl%my_go_deps", "-bzlmod", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } // Confirm that the WORKSPACE is still empty want := "" if got, err := os.ReadFile(filepath.Join(dir, "WORKSPACE")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s; diff %s", string(got), want, cmp.Diff(string(got), want)) } // Confirm that the macro file was written want = `load("@bazel_gazelle//:deps.bzl", "go_repository") def my_go_deps(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", sum = "h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=", version = "v1.8.4", ) ` if got, err := os.ReadFile(filepath.Join(dir, "go_deps.bzl")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s; diff %s", string(got), want, cmp.Diff(string(got), want)) } } func TestUpdateReposWithBzlmodWithoutToMacro(t *testing.T) { dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ {Path: "WORKSPACE"}, { Path: "go.mod", Content: ` module example.com/foo/v2 go 1.19 require ( github.com/stretchr/testify v1.8.4 ) `, }, }) t.Cleanup(cleanup) args := []string{ "update-repos", "-from_file=go.mod", "-bzlmod", } if err := runGazelle(dir, args); err != nil { t.Fatal(err) } // Confirm that the WORKSPACE is still empty want := "" if got, err := os.ReadFile(filepath.Join(dir, "WORKSPACE")); err != nil { t.Fatal(err) } else if string(got) != want { t.Fatalf("got %s ; want %s; diff %s", string(got), want, cmp.Diff(string(got), want)) } }