blob: ae4b005587d24d98bd03d927b59cf5a8c4b55093 [file] [log] [blame]
/* 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"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"testing"
"github.com/bazelbuild/bazel-gazelle/internal/config"
"github.com/bazelbuild/bazel-gazelle/internal/wspace"
)
type fileSpec struct {
path, content string
}
func createFiles(files []fileSpec) (string, error) {
dir, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "integration_test")
if err != nil {
return "", err
}
for _, f := range files {
path := filepath.Join(dir, filepath.FromSlash(f.path))
if strings.HasSuffix(f.path, "/") {
if err := os.MkdirAll(path, 0700); err != nil {
os.RemoveAll(dir)
return "", err
}
continue
}
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
os.RemoveAll(dir)
return "", err
}
if err := ioutil.WriteFile(path, []byte(f.content), 0600); err != nil {
os.RemoveAll(dir)
return "", err
}
}
return dir, nil
}
// 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.Find(dir); err == nil {
t.Skipf("WORKSPACE visible in parent %q of tmp %q", parent, dir)
}
}
func checkFiles(t *testing.T, dir string, files []fileSpec) {
for _, f := range files {
path := filepath.Join(dir, f.path)
if strings.HasSuffix(f.path, "/") {
if st, err := os.Stat(path); err != nil {
t.Errorf("could not stat %s: %v", f.path, err)
} else if !st.IsDir() {
t.Errorf("not a directory: %s", f.path)
}
} else {
want := f.content
if len(want) > 0 && want[0] == '\n' {
// Strip leading newline, added for readability.
want = want[1:]
}
gotBytes, err := ioutil.ReadFile(filepath.Join(dir, f.path))
if err != nil {
t.Errorf("could not read %s: %v", f.path, err)
continue
}
got := string(gotBytes)
if got != want {
t.Errorf("%s: got %s ; want %s", f.path, got, f.content)
}
}
}
}
func runGazelle(wd string, args []string) error {
oldWd, err := os.Getwd()
if err != nil {
return err
}
if err := os.Chdir(wd); err != nil {
return err
}
defer os.Chdir(oldWd)
return run(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.Error(err)
}
})
}
}
func TestNoRepoRootOrWorkspace(t *testing.T) {
dir, err := createFiles(nil)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
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, err := createFiles([]fileSpec{
{path: "WORKSPACE", content: ""},
{path: "hello.go", content: "package hello"},
})
if err != nil {
t.Fatal(err)
}
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, err := createFiles([]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: "bar.go",
content: `// +build linux
package foo
`,
},
{path: "outer/outer.go", content: "package outer"},
{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
],
importpath = "example.com/foo",
visibility = ["//visibility:public"],
deps = select({
"@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": [],
}),
)
`
if err != nil {
t.Fatal(err)
}
if err := runGazelle(dir, []string{"-go_prefix", "example.com/foo"}); err != nil {
t.Fatal(err)
}
if got, err := ioutil.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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
if err := runGazelle(dir, []string{c.cmd}); err != nil {
t.Fatal(err)
}
if got, err := ioutil.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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
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 := ioutil.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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/foo", "b"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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 := []fileSpec{
{path: "a/"},
{path: "b/"},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
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 := []fileSpec{
{path: "WORKSPACE"},
{path: "BUILD/"},
{
path: "a/BUILD",
content: "!!! parse error",
}, {
path: "a.go",
content: "package a",
},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/foo", "-external", "vendored"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{
{
path: config.DefaultValidBuildFileNames[0],
content: `load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["a.go"],
importpath = "example.com/foo",
visibility = ["//visibility:public"],
deps = ["//vendor/golang.org/x/bar:go_default_library"],
)
`,
}, {
path: "vendor/golang.org/x/bar/" + config.DefaultValidBuildFileNames[0],
content: `load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
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:go_default_library"],
)
`,
},
})
}
func TestMigrateProtoRules(t *testing.T) {
files := []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")
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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
if err := runGazelle(dir, tc.args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{{
path: config.DefaultValidBuildFileNames[0],
content: tc.want,
}})
})
}
}
func TestRemoveProtoDeletesRules(t *testing.T) {
files := []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")
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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"fix", "-go_prefix", "example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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 := []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")
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 {}
`,
},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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")
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 TestEmptyGoPrefix(t *testing.T) {
files := []fileSpec{
{path: "WORKSPACE"},
{
path: "foo/foo.go",
content: "package foo",
}, {
path: "bar/bar.go",
content: `
package bar
import (
_ "fmt"
_ "foo"
)
`,
},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", ""}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{{
path: filepath.Join("bar", config.DefaultValidBuildFileNames[0]),
content: `
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["bar.go"],
importpath = "bar",
visibility = ["//visibility:public"],
deps = ["//foo:go_default_library"],
)
`,
}})
}
// 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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{
{
path: "sub/vendor/example.com/foo/BUILD.bazel",
content: `
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
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 = "go_default_library",
srcs = ["bar.go"],
importpath = "example.com/repo/sub/bar",
visibility = ["//visibility:public"],
deps = ["//sub/vendor/example.com/foo:go_default_library"],
)
`,
},
})
}
// TestDeleteProtoWithDeps checks that Gazelle will delete proto rules with
// dependencies after the proto sources are removed.
func TestDeleteProtoWithDeps(t *testing.T) {
files := []fileSpec{
{path: "WORKSPACE"},
{
path: "foo/BUILD.bazel",
content: `
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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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 TestCustomRepoNames(t *testing.T) {
files := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix", "example.com/foo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{
{
path: "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/foo",
visibility = ["//visibility:public"],
deps = ["@custom_repo//:go_default_library"],
)
`,
},
})
}
func TestImportReposFromDep(t *testing.T) {
files := []fileSpec{
{
path: "WORKSPACE",
content: `
http_archive(
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.1/rules_go-0.10.1.tar.gz",
sha256 = "4b14d8dd31c6dbaf3ff871adcd03f28c3274e42abc855cb8fb4d01233c0154dc",
)
http_archive(
name = "bazel_gazelle",
url = "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.10.0/bazel-gazelle-0.10.0.tar.gz",
sha256 = "6228d9618ab9536892aa69082c063207c91e777e51bd3c5544c9c060cafe1bd8",
)
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains", "go_repository")
go_rules_dependencies()
go_register_toolchains()
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
gazelle_dependencies()
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
tag = "1.2",
)
# keep
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
remote = "https://github.com/golang/sys",
)
http_archive(
name = "com_github_go_yaml_yaml",
urls = ["https://example.com/yaml.tar.gz"],
sha256 = "1234",
)
`,
}, {
path: "Gopkg.lock",
content: `# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["context"]
revision = "66aacef3dd8a676686c7ae3716979581e8b03c47"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "bb24a47a89eac6c1227fbcb2ae37a8b9ed323366"
[[projects]]
branch = "v2"
name = "github.com/go-yaml/yaml"
packages = ["."]
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "05c1cd69be2c917c0cc4b32942830c2acfa044d8200fdc94716aae48a8083702"
solver-name = "gps-cdcl"
solver-version = 1
`,
},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"update-repos", "-from_file", "Gopkg.lock"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{
{
path: "WORKSPACE",
content: `
http_archive(
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.1/rules_go-0.10.1.tar.gz",
sha256 = "4b14d8dd31c6dbaf3ff871adcd03f28c3274e42abc855cb8fb4d01233c0154dc",
)
http_archive(
name = "bazel_gazelle",
url = "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.10.0/bazel-gazelle-0.10.0.tar.gz",
sha256 = "6228d9618ab9536892aa69082c063207c91e777e51bd3c5544c9c060cafe1bd8",
)
load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains()
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
gazelle_dependencies()
go_repository(
name = "org_golang_x_net",
commit = "66aacef3dd8a676686c7ae3716979581e8b03c47",
importpath = "golang.org/x/net",
)
# keep
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
remote = "https://github.com/golang/sys",
)
http_archive(
name = "com_github_go_yaml_yaml",
urls = ["https://example.com/yaml.tar.gz"],
sha256 = "1234",
)
go_repository(
name = "com_github_pkg_errors",
commit = "645ef00459ed84a119197bfb8d8205042c6df63d",
importpath = "github.com/pkg/errors",
)
`,
}})
}
func TestDeleteRulesInEmptyDir(t *testing.T) {
files := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
args := []string{"-go_prefix=example.com/repo"}
if err := runGazelle(dir, args); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []fileSpec{
{
path: "BUILD.bazel",
content: "",
},
})
}
func TestFixWorkspaceWithoutGazelle(t *testing.T) {
files := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
if err := runGazelle(dir, nil); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, []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 := []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, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
if err := runGazelle(dir, nil); err != nil {
t.Fatal(err)
}
checkFiles(t, dir, files)
}
func TestDontCreateBuildFileInEmptyDir(t *testing.T) {
files := []fileSpec{
{path: "WORKSPACE"},
{path: "sub/"},
}
dir, err := createFiles(files)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
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)
}
}
}
// TODO(jayconrod): more tests
// run in fix mode in testdata directories to create new files
// run in diff mode in testdata directories to update existing files (no change)