github.com/wolfd/bazel-gazelle@v0.14.0/cmd/gazelle/integration_test.go (about) 1 /* Copyright 2017 The Bazel Authors. All rights reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 // This file contains integration tests for all of Gazelle. It's meant to test 17 // common usage patterns and check for errors that are difficult to test in 18 // unit tests. 19 20 package main 21 22 import ( 23 "bytes" 24 "flag" 25 "io/ioutil" 26 "log" 27 "os" 28 "path/filepath" 29 "strings" 30 "testing" 31 32 "github.com/bazelbuild/bazel-gazelle/internal/config" 33 "github.com/bazelbuild/bazel-gazelle/internal/wspace" 34 ) 35 36 type fileSpec struct { 37 path, content string 38 } 39 40 func createFiles(files []fileSpec) (string, error) { 41 dir, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "integration_test") 42 if err != nil { 43 return "", err 44 } 45 46 for _, f := range files { 47 path := filepath.Join(dir, filepath.FromSlash(f.path)) 48 if strings.HasSuffix(f.path, "/") { 49 if err := os.MkdirAll(path, 0700); err != nil { 50 os.RemoveAll(dir) 51 return "", err 52 } 53 continue 54 } 55 if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { 56 os.RemoveAll(dir) 57 return "", err 58 } 59 if err := ioutil.WriteFile(path, []byte(f.content), 0600); err != nil { 60 os.RemoveAll(dir) 61 return "", err 62 } 63 } 64 return dir, nil 65 } 66 67 // skipIfWorkspaceVisible skips the test if the WORKSPACE file for the 68 // repository is visible. This happens in newer Bazel versions when tests 69 // are run without sandboxing, since temp directories may be inside the 70 // exec root. 71 func skipIfWorkspaceVisible(t *testing.T, dir string) { 72 if parent, err := wspace.Find(dir); err == nil { 73 t.Skipf("WORKSPACE visible in parent %q of tmp %q", parent, dir) 74 } 75 } 76 77 func checkFiles(t *testing.T, dir string, files []fileSpec) { 78 for _, f := range files { 79 path := filepath.Join(dir, f.path) 80 if strings.HasSuffix(f.path, "/") { 81 if st, err := os.Stat(path); err != nil { 82 t.Errorf("could not stat %s: %v", f.path, err) 83 } else if !st.IsDir() { 84 t.Errorf("not a directory: %s", f.path) 85 } 86 } else { 87 want := strings.TrimSpace(f.content) 88 gotBytes, err := ioutil.ReadFile(filepath.Join(dir, f.path)) 89 if err != nil { 90 t.Errorf("could not read %s: %v", f.path, err) 91 continue 92 } 93 got := strings.TrimSpace(string(gotBytes)) 94 if got != want { 95 t.Errorf("%s: got:\n%s\nwant:\n %s", f.path, gotBytes, f.content) 96 } 97 } 98 } 99 } 100 101 func runGazelle(wd string, args []string) error { 102 oldWd, err := os.Getwd() 103 if err != nil { 104 return err 105 } 106 if err := os.Chdir(wd); err != nil { 107 return err 108 } 109 defer os.Chdir(oldWd) 110 111 return run(args) 112 } 113 114 // TestHelp checks that help commands do not panic due to nil flag values. 115 // Verifies #256. 116 func TestHelp(t *testing.T) { 117 for _, args := range [][]string{ 118 {"help"}, 119 {"fix", "-h"}, 120 {"update", "-h"}, 121 {"update-repos", "-h"}, 122 } { 123 t.Run(args[0], func(t *testing.T) { 124 if err := runGazelle(".", args); err == nil { 125 t.Errorf("%s: got success, want flag.ErrHelp", args[0]) 126 } else if err != flag.ErrHelp { 127 t.Errorf("%s: got %v, want flag.ErrHelp", args[0], err) 128 } 129 }) 130 } 131 } 132 133 func TestNoRepoRootOrWorkspace(t *testing.T) { 134 dir, err := createFiles(nil) 135 if err != nil { 136 t.Fatal(err) 137 } 138 defer os.RemoveAll(dir) 139 skipIfWorkspaceVisible(t, dir) 140 want := "-repo_root not specified" 141 if err := runGazelle(dir, nil); err == nil { 142 t.Fatalf("got success; want %q", want) 143 } else if !strings.Contains(err.Error(), want) { 144 t.Fatalf("got %q; want %q", err, want) 145 } 146 } 147 148 func TestNoGoPrefixArgOrRule(t *testing.T) { 149 dir, err := createFiles([]fileSpec{ 150 {path: "WORKSPACE", content: ""}, 151 {path: "hello.go", content: "package hello"}, 152 }) 153 if err != nil { 154 t.Fatal(err) 155 } 156 buf := new(bytes.Buffer) 157 log.SetOutput(buf) 158 defer log.SetOutput(os.Stderr) 159 if err := runGazelle(dir, nil); err != nil { 160 t.Fatalf("got %#v; want success", err) 161 } 162 want := "go prefix is not set" 163 if !strings.Contains(buf.String(), want) { 164 t.Errorf("log does not contain %q\n--begin--\n%s--end--\n", want, buf.String()) 165 } 166 } 167 168 // TestSelectLabelsSorted checks that string lists in srcs and deps are sorted 169 // using buildifier order, even if they are inside select expressions. 170 // This applies to both new and existing lists and should preserve comments. 171 // buildifier does not do this yet bazelbuild/buildtools#122, so we do this 172 // in addition to calling build.Rewrite. 173 func TestSelectLabelsSorted(t *testing.T) { 174 dir, err := createFiles([]fileSpec{ 175 {path: "WORKSPACE"}, 176 { 177 path: "BUILD", 178 content: ` 179 load("@io_bazel_rules_go//go:def.bzl", "go_library") 180 181 go_library( 182 name = "go_default_library", 183 srcs = select({ 184 "@io_bazel_rules_go//go/platform:linux": [ 185 # foo comment 186 "foo.go", # side comment 187 # bar comment 188 "bar.go", 189 ], 190 "//conditions:default": [], 191 }), 192 importpath = "example.com/foo", 193 ) 194 `, 195 }, 196 { 197 path: "foo.go", 198 content: ` 199 // +build linux 200 201 package foo 202 203 import ( 204 _ "example.com/foo/outer" 205 _ "example.com/foo/outer/inner" 206 _ "github.com/jr_hacker/tools" 207 ) 208 `, 209 }, 210 { 211 path: "bar.go", 212 content: `// +build linux 213 214 package foo 215 `, 216 }, 217 {path: "outer/outer.go", content: "package outer"}, 218 {path: "outer/inner/inner.go", content: "package inner"}, 219 }) 220 want := `load("@io_bazel_rules_go//go:def.bzl", "go_library") 221 222 go_library( 223 name = "go_default_library", 224 srcs = [ 225 # bar comment 226 "bar.go", 227 # foo comment 228 "foo.go", # side comment 229 ], 230 importpath = "example.com/foo", 231 visibility = ["//visibility:public"], 232 deps = select({ 233 "@io_bazel_rules_go//go/platform:linux": [ 234 "//outer:go_default_library", 235 "//outer/inner:go_default_library", 236 "@com_github_jr_hacker_tools//:go_default_library", 237 ], 238 "//conditions:default": [], 239 }), 240 ) 241 ` 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 if err := runGazelle(dir, []string{"-go_prefix", "example.com/foo"}); err != nil { 247 t.Fatal(err) 248 } 249 if got, err := ioutil.ReadFile(filepath.Join(dir, "BUILD")); err != nil { 250 t.Fatal(err) 251 } else if string(got) != want { 252 t.Fatalf("got %s ; want %s", string(got), want) 253 } 254 } 255 256 func TestFixAndUpdateChanges(t *testing.T) { 257 files := []fileSpec{ 258 {path: "WORKSPACE"}, 259 { 260 path: "BUILD", 261 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_prefix") 262 load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_test") 263 264 go_prefix("example.com/foo") 265 266 go_library( 267 name = "go_default_library", 268 srcs = [ 269 "extra.go", 270 "pure.go", 271 ], 272 library = ":cgo_default_library", 273 visibility = ["//visibility:default"], 274 ) 275 276 cgo_library( 277 name = "cgo_default_library", 278 srcs = ["cgo.go"], 279 ) 280 `, 281 }, 282 { 283 path: "pure.go", 284 content: "package foo", 285 }, 286 { 287 path: "cgo.go", 288 content: `package foo 289 290 import "C" 291 `, 292 }, 293 } 294 295 cases := []struct { 296 cmd, want string 297 }{ 298 { 299 cmd: "update", 300 want: `load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_library", "go_prefix") 301 302 go_prefix("example.com/foo") 303 304 go_library( 305 name = "go_default_library", 306 srcs = [ 307 "cgo.go", 308 "pure.go", 309 ], 310 cgo = True, 311 importpath = "example.com/foo", 312 visibility = ["//visibility:default"], 313 ) 314 315 cgo_library( 316 name = "cgo_default_library", 317 srcs = ["cgo.go"], 318 ) 319 `, 320 }, { 321 cmd: "fix", 322 want: `load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_prefix") 323 324 go_prefix("example.com/foo") 325 326 go_library( 327 name = "go_default_library", 328 srcs = [ 329 "cgo.go", 330 "pure.go", 331 ], 332 cgo = True, 333 importpath = "example.com/foo", 334 visibility = ["//visibility:default"], 335 ) 336 `, 337 }, 338 } 339 340 for _, c := range cases { 341 t.Run(c.cmd, func(t *testing.T) { 342 dir, err := createFiles(files) 343 if err != nil { 344 t.Fatal(err) 345 } 346 347 if err := runGazelle(dir, []string{c.cmd}); err != nil { 348 t.Fatal(err) 349 } 350 if got, err := ioutil.ReadFile(filepath.Join(dir, "BUILD")); err != nil { 351 t.Fatal(err) 352 } else if string(got) != c.want { 353 t.Fatalf("got %s ; want %s", string(got), c.want) 354 } 355 }) 356 } 357 } 358 359 func TestFixUnlinkedCgoLibrary(t *testing.T) { 360 files := []fileSpec{ 361 {path: "WORKSPACE"}, 362 { 363 path: "BUILD", 364 content: `load("@io_bazel_rules_go//go:def.bzl", "cgo_library", "go_library") 365 366 cgo_library( 367 name = "cgo_default_library", 368 srcs = ["cgo.go"], 369 ) 370 371 go_library( 372 name = "go_default_library", 373 srcs = ["pure.go"], 374 importpath = "example.com/foo", 375 visibility = ["//visibility:public"], 376 ) 377 `, 378 }, { 379 path: "pure.go", 380 content: "package foo", 381 }, 382 } 383 384 dir, err := createFiles(files) 385 if err != nil { 386 t.Fatal(err) 387 } 388 389 want := `load("@io_bazel_rules_go//go:def.bzl", "go_library") 390 391 go_library( 392 name = "go_default_library", 393 srcs = ["pure.go"], 394 importpath = "example.com/foo", 395 visibility = ["//visibility:public"], 396 ) 397 ` 398 if err := runGazelle(dir, []string{"fix", "-go_prefix", "example.com/foo"}); err != nil { 399 t.Fatal(err) 400 } 401 if got, err := ioutil.ReadFile(filepath.Join(dir, "BUILD")); err != nil { 402 t.Fatal(err) 403 } else if string(got) != want { 404 t.Fatalf("got %s ; want %s", string(got), want) 405 } 406 } 407 408 // TestMultipleDirectories checks that all directories in a repository are 409 // indexed but only directories listed on the command line are updated. 410 func TestMultipleDirectories(t *testing.T) { 411 files := []fileSpec{ 412 {path: "WORKSPACE"}, 413 { 414 path: "a/BUILD.bazel", 415 content: `# This file shouldn't be modified. 416 load("@io_bazel_rules_go//go:def.bzl", "go_library") 417 418 go_library( 419 name = "go_default_library", 420 srcs = ["a.go"], 421 importpath = "example.com/foo/x", 422 ) 423 `, 424 }, { 425 path: "a/a.go", 426 content: "package a", 427 }, { 428 path: "b/b.go", 429 content: ` 430 package b 431 432 import _ "example.com/foo/x" 433 `, 434 }, 435 } 436 dir, err := createFiles(files) 437 if err != nil { 438 t.Fatal(err) 439 } 440 defer os.RemoveAll(dir) 441 442 args := []string{"-go_prefix", "example.com/foo", "b"} 443 if err := runGazelle(dir, args); err != nil { 444 t.Fatal(err) 445 } 446 447 checkFiles(t, dir, []fileSpec{ 448 files[1], // should not change 449 { 450 path: "b/BUILD.bazel", 451 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") 452 453 go_library( 454 name = "go_default_library", 455 srcs = ["b.go"], 456 importpath = "example.com/foo/b", 457 visibility = ["//visibility:public"], 458 deps = ["//a:go_default_library"], 459 ) 460 `, 461 }, 462 }) 463 } 464 465 func TestErrorOutsideWorkspace(t *testing.T) { 466 files := []fileSpec{ 467 {path: "a/"}, 468 {path: "b/"}, 469 } 470 dir, err := createFiles(files) 471 if err != nil { 472 t.Fatal(err) 473 } 474 defer os.RemoveAll(dir) 475 skipIfWorkspaceVisible(t, dir) 476 477 cases := []struct { 478 name, dir, want string 479 args []string 480 }{ 481 { 482 name: "outside workspace", 483 dir: dir, 484 args: nil, 485 want: "WORKSPACE cannot be found", 486 }, { 487 name: "outside repo_root", 488 dir: filepath.Join(dir, "a"), 489 args: []string{"-repo_root", filepath.Join(dir, "b")}, 490 want: "not a subdirectory of repo root", 491 }, 492 } 493 for _, c := range cases { 494 t.Run(c.name, func(t *testing.T) { 495 if err := runGazelle(c.dir, c.args); err == nil { 496 t.Fatalf("got success; want %q", c.want) 497 } else if !strings.Contains(err.Error(), c.want) { 498 t.Fatalf("got %q; want %q", err, c.want) 499 } 500 }) 501 } 502 } 503 504 func TestBuildFileNameIgnoresBuild(t *testing.T) { 505 files := []fileSpec{ 506 {path: "WORKSPACE"}, 507 {path: "BUILD/"}, 508 { 509 path: "a/BUILD", 510 content: "!!! parse error", 511 }, { 512 path: "a.go", 513 content: "package a", 514 }, 515 } 516 dir, err := createFiles(files) 517 if err != nil { 518 t.Fatal(err) 519 } 520 defer os.Remove(dir) 521 522 args := []string{"-go_prefix", "example.com/foo", "-build_file_name", "BUILD.bazel"} 523 if err := runGazelle(dir, args); err != nil { 524 t.Fatal(err) 525 } 526 if _, err := os.Stat(filepath.Join(dir, "BUILD.bazel")); err != nil { 527 t.Errorf("BUILD.bazel not created: %v", err) 528 } 529 } 530 531 func TestExternalVendor(t *testing.T) { 532 files := []fileSpec{ 533 { 534 path: "WORKSPACE", 535 content: `workspace(name = "banana")`, 536 }, { 537 path: "a.go", 538 content: `package foo 539 540 import _ "golang.org/x/bar" 541 `, 542 }, { 543 path: "vendor/golang.org/x/bar/bar.go", 544 content: `package bar 545 546 import _ "golang.org/x/baz" 547 `, 548 }, { 549 path: "vendor/golang.org/x/baz/baz.go", 550 content: "package baz", 551 }, 552 } 553 dir, err := createFiles(files) 554 if err != nil { 555 t.Fatal(err) 556 } 557 defer os.RemoveAll(dir) 558 559 args := []string{"-go_prefix", "example.com/foo", "-external", "vendored"} 560 if err := runGazelle(dir, args); err != nil { 561 t.Fatal(err) 562 } 563 564 checkFiles(t, dir, []fileSpec{ 565 { 566 path: config.DefaultValidBuildFileNames[0], 567 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") 568 569 go_library( 570 name = "go_default_library", 571 srcs = ["a.go"], 572 importpath = "example.com/foo", 573 visibility = ["//visibility:public"], 574 deps = ["//vendor/golang.org/x/bar:go_default_library"], 575 ) 576 `, 577 }, { 578 path: "vendor/golang.org/x/bar/" + config.DefaultValidBuildFileNames[0], 579 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") 580 581 go_library( 582 name = "go_default_library", 583 srcs = ["bar.go"], 584 importmap = "example.com/foo/vendor/golang.org/x/bar", 585 importpath = "golang.org/x/bar", 586 visibility = ["//visibility:public"], 587 deps = ["//vendor/golang.org/x/baz:go_default_library"], 588 ) 589 `, 590 }, 591 }) 592 } 593 594 func TestMigrateProtoRules(t *testing.T) { 595 files := []fileSpec{ 596 {path: "WORKSPACE"}, 597 { 598 path: config.DefaultValidBuildFileNames[0], 599 content: ` 600 load("@io_bazel_rules_go//proto:go_proto_library.bzl", "go_proto_library") 601 602 filegroup( 603 name = "go_default_library_protos", 604 srcs = ["foo.proto"], 605 visibility = ["//visibility:public"], 606 ) 607 608 go_proto_library( 609 name = "go_default_library", 610 srcs = [":go_default_library_protos"], 611 ) 612 `, 613 }, { 614 path: "foo.proto", 615 content: `syntax = "proto3"; 616 617 option go_package = "example.com/repo"; 618 `, 619 }, { 620 path: "foo.pb.go", 621 content: `package repo`, 622 }, 623 } 624 625 for _, tc := range []struct { 626 args []string 627 want string 628 }{ 629 { 630 args: []string{"update", "-go_prefix", "example.com/repo"}, 631 want: ` 632 load("@io_bazel_rules_go//proto:go_proto_library.bzl", "go_proto_library") 633 634 filegroup( 635 name = "go_default_library_protos", 636 srcs = ["foo.proto"], 637 visibility = ["//visibility:public"], 638 ) 639 640 go_proto_library( 641 name = "go_default_library", 642 srcs = [":go_default_library_protos"], 643 ) 644 `, 645 }, { 646 args: []string{"fix", "-go_prefix", "example.com/repo"}, 647 want: ` 648 load("@io_bazel_rules_go//go:def.bzl", "go_library") 649 load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 650 651 proto_library( 652 name = "repo_proto", 653 srcs = ["foo.proto"], 654 visibility = ["//visibility:public"], 655 ) 656 657 go_proto_library( 658 name = "repo_go_proto", 659 importpath = "example.com/repo", 660 proto = ":repo_proto", 661 visibility = ["//visibility:public"], 662 ) 663 664 go_library( 665 name = "go_default_library", 666 embed = [":repo_go_proto"], 667 importpath = "example.com/repo", 668 visibility = ["//visibility:public"], 669 ) 670 `, 671 }, 672 } { 673 t.Run(tc.args[0], func(t *testing.T) { 674 dir, err := createFiles(files) 675 if err != nil { 676 t.Fatal(err) 677 } 678 defer os.RemoveAll(dir) 679 680 if err := runGazelle(dir, tc.args); err != nil { 681 t.Fatal(err) 682 } 683 684 checkFiles(t, dir, []fileSpec{{ 685 path: config.DefaultValidBuildFileNames[0], 686 content: tc.want, 687 }}) 688 }) 689 } 690 } 691 692 func TestRemoveProtoDeletesRules(t *testing.T) { 693 files := []fileSpec{ 694 {path: "WORKSPACE"}, 695 { 696 path: config.DefaultValidBuildFileNames[0], 697 content: ` 698 load("@io_bazel_rules_go//go:def.bzl", "go_library") 699 load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 700 701 filegroup( 702 name = "go_default_library_protos", 703 srcs = ["foo.proto"], 704 visibility = ["//visibility:public"], 705 ) 706 707 proto_library( 708 name = "repo_proto", 709 srcs = ["foo.proto"], 710 visibility = ["//visibility:public"], 711 ) 712 713 go_proto_library( 714 name = "repo_go_proto", 715 importpath = "example.com/repo", 716 proto = ":repo_proto", 717 visibility = ["//visibility:public"], 718 ) 719 720 go_library( 721 name = "go_default_library", 722 srcs = ["extra.go"], 723 embed = [":repo_go_proto"], 724 importpath = "example.com/repo", 725 visibility = ["//visibility:public"], 726 ) 727 `, 728 }, { 729 path: "extra.go", 730 content: `package repo`, 731 }, 732 } 733 dir, err := createFiles(files) 734 if err != nil { 735 t.Fatal(err) 736 } 737 defer os.RemoveAll(dir) 738 739 args := []string{"fix", "-go_prefix", "example.com/repo"} 740 if err := runGazelle(dir, args); err != nil { 741 t.Fatal(err) 742 } 743 744 checkFiles(t, dir, []fileSpec{{ 745 path: config.DefaultValidBuildFileNames[0], 746 content: ` 747 load("@io_bazel_rules_go//go:def.bzl", "go_library") 748 749 go_library( 750 name = "go_default_library", 751 srcs = ["extra.go"], 752 importpath = "example.com/repo", 753 visibility = ["//visibility:public"], 754 ) 755 `, 756 }}) 757 } 758 759 func TestAddServiceConvertsToGrpc(t *testing.T) { 760 files := []fileSpec{ 761 {path: "WORKSPACE"}, 762 { 763 path: config.DefaultValidBuildFileNames[0], 764 content: ` 765 load("@io_bazel_rules_go//go:def.bzl", "go_library") 766 load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 767 768 proto_library( 769 name = "repo_proto", 770 srcs = ["foo.proto"], 771 visibility = ["//visibility:public"], 772 ) 773 774 go_proto_library( 775 name = "repo_go_proto", 776 importpath = "example.com/repo", 777 proto = ":repo_proto", 778 visibility = ["//visibility:public"], 779 ) 780 781 go_library( 782 name = "go_default_library", 783 embed = [":repo_go_proto"], 784 importpath = "example.com/repo", 785 visibility = ["//visibility:public"], 786 ) 787 `, 788 }, { 789 path: "foo.proto", 790 content: `syntax = "proto3"; 791 792 option go_package = "example.com/repo"; 793 794 service {} 795 `, 796 }, 797 } 798 799 dir, err := createFiles(files) 800 if err != nil { 801 t.Fatal(err) 802 } 803 defer os.RemoveAll(dir) 804 805 args := []string{"-go_prefix", "example.com/repo"} 806 if err := runGazelle(dir, args); err != nil { 807 t.Fatal(err) 808 } 809 810 checkFiles(t, dir, []fileSpec{{ 811 path: config.DefaultValidBuildFileNames[0], 812 content: ` 813 load("@io_bazel_rules_go//go:def.bzl", "go_library") 814 load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 815 816 proto_library( 817 name = "repo_proto", 818 srcs = ["foo.proto"], 819 visibility = ["//visibility:public"], 820 ) 821 822 go_proto_library( 823 name = "repo_go_proto", 824 compilers = ["@io_bazel_rules_go//proto:go_grpc"], 825 importpath = "example.com/repo", 826 proto = ":repo_proto", 827 visibility = ["//visibility:public"], 828 ) 829 830 go_library( 831 name = "go_default_library", 832 embed = [":repo_go_proto"], 833 importpath = "example.com/repo", 834 visibility = ["//visibility:public"], 835 ) 836 `, 837 }}) 838 } 839 840 func TestEmptyGoPrefix(t *testing.T) { 841 files := []fileSpec{ 842 {path: "WORKSPACE"}, 843 { 844 path: "foo/foo.go", 845 content: "package foo", 846 }, { 847 path: "bar/bar.go", 848 content: ` 849 package bar 850 851 import ( 852 _ "fmt" 853 _ "foo" 854 ) 855 `, 856 }, 857 } 858 859 dir, err := createFiles(files) 860 if err != nil { 861 t.Fatal(err) 862 } 863 defer os.RemoveAll(dir) 864 865 args := []string{"-go_prefix", ""} 866 if err := runGazelle(dir, args); err != nil { 867 t.Fatal(err) 868 } 869 870 checkFiles(t, dir, []fileSpec{{ 871 path: filepath.Join("bar", config.DefaultValidBuildFileNames[0]), 872 content: ` 873 load("@io_bazel_rules_go//go:def.bzl", "go_library") 874 875 go_library( 876 name = "go_default_library", 877 srcs = ["bar.go"], 878 importpath = "bar", 879 visibility = ["//visibility:public"], 880 deps = ["//foo:go_default_library"], 881 ) 882 `, 883 }}) 884 } 885 886 // TestResolveKeptImportpath checks that Gazelle can resolve dependencies 887 // against a library with a '# keep' comment on its importpath attribute 888 // when the importpath doesn't match what Gazelle would infer. 889 func TestResolveKeptImportpath(t *testing.T) { 890 files := []fileSpec{ 891 {path: "WORKSPACE"}, 892 { 893 path: "foo/foo.go", 894 content: ` 895 package foo 896 897 import _ "example.com/alt/baz" 898 `, 899 }, { 900 path: "bar/BUILD.bazel", 901 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") 902 903 go_library( 904 name = "go_default_library", 905 srcs = ["bar.go"], 906 importpath = "example.com/alt/baz", # keep 907 visibility = ["//visibility:public"], 908 ) 909 `, 910 }, { 911 path: "bar/bar.go", 912 content: "package bar", 913 }, 914 } 915 916 dir, err := createFiles(files) 917 if err != nil { 918 t.Fatal(err) 919 } 920 defer os.RemoveAll(dir) 921 922 args := []string{"-go_prefix", "example.com/repo"} 923 if err := runGazelle(dir, args); err != nil { 924 t.Fatal(err) 925 } 926 927 checkFiles(t, dir, []fileSpec{ 928 { 929 path: "foo/BUILD.bazel", 930 content: ` 931 load("@io_bazel_rules_go//go:def.bzl", "go_library") 932 933 go_library( 934 name = "go_default_library", 935 srcs = ["foo.go"], 936 importpath = "example.com/repo/foo", 937 visibility = ["//visibility:public"], 938 deps = ["//bar:go_default_library"], 939 ) 940 `, 941 }, { 942 path: "bar/BUILD.bazel", 943 content: `load("@io_bazel_rules_go//go:def.bzl", "go_library") 944 945 go_library( 946 name = "go_default_library", 947 srcs = ["bar.go"], 948 importpath = "example.com/alt/baz", # keep 949 visibility = ["//visibility:public"], 950 ) 951 `, 952 }, 953 }) 954 } 955 956 // TestResolveVendorSubdirectory checks that Gazelle can resolve libraries 957 // in a vendor directory which is not at the repository root. 958 func TestResolveVendorSubdirectory(t *testing.T) { 959 files := []fileSpec{ 960 {path: "WORKSPACE"}, 961 { 962 path: "sub/vendor/example.com/foo/foo.go", 963 content: "package foo", 964 }, { 965 path: "sub/bar/bar.go", 966 content: ` 967 package bar 968 969 import _ "example.com/foo" 970 `, 971 }, 972 } 973 dir, err := createFiles(files) 974 if err != nil { 975 t.Fatal(err) 976 } 977 defer os.RemoveAll(dir) 978 979 args := []string{"-go_prefix", "example.com/repo"} 980 if err := runGazelle(dir, args); err != nil { 981 t.Fatal(err) 982 } 983 984 checkFiles(t, dir, []fileSpec{ 985 { 986 path: "sub/vendor/example.com/foo/BUILD.bazel", 987 content: ` 988 load("@io_bazel_rules_go//go:def.bzl", "go_library") 989 990 go_library( 991 name = "go_default_library", 992 srcs = ["foo.go"], 993 importmap = "example.com/repo/sub/vendor/example.com/foo", 994 importpath = "example.com/foo", 995 visibility = ["//visibility:public"], 996 ) 997 `, 998 }, { 999 path: "sub/bar/BUILD.bazel", 1000 content: ` 1001 load("@io_bazel_rules_go//go:def.bzl", "go_library") 1002 1003 go_library( 1004 name = "go_default_library", 1005 srcs = ["bar.go"], 1006 importpath = "example.com/repo/sub/bar", 1007 visibility = ["//visibility:public"], 1008 deps = ["//sub/vendor/example.com/foo:go_default_library"], 1009 ) 1010 `, 1011 }, 1012 }) 1013 } 1014 1015 // TestDeleteProtoWithDeps checks that Gazelle will delete proto rules with 1016 // dependencies after the proto sources are removed. 1017 func TestDeleteProtoWithDeps(t *testing.T) { 1018 files := []fileSpec{ 1019 {path: "WORKSPACE"}, 1020 { 1021 path: "foo/BUILD.bazel", 1022 content: ` 1023 load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 1024 load("@io_bazel_rules_go//go:def.bzl", "go_library") 1025 1026 go_library( 1027 name = "go_default_library", 1028 srcs = ["extra.go"], 1029 embed = [":scratch_go_proto"], 1030 importpath = "example.com/repo/foo", 1031 visibility = ["//visibility:public"], 1032 ) 1033 1034 proto_library( 1035 name = "foo_proto", 1036 srcs = ["foo.proto"], 1037 visibility = ["//visibility:public"], 1038 deps = ["//foo/bar:bar_proto"], 1039 ) 1040 1041 go_proto_library( 1042 name = "foo_go_proto", 1043 importpath = "example.com/repo/foo", 1044 proto = ":foo_proto", 1045 visibility = ["//visibility:public"], 1046 deps = ["//foo/bar:go_default_library"], 1047 ) 1048 `, 1049 }, { 1050 path: "foo/extra.go", 1051 content: "package foo", 1052 }, { 1053 path: "foo/bar/bar.proto", 1054 content: ` 1055 syntax = "proto3"; 1056 1057 option go_package = "example.com/repo/foo/bar"; 1058 1059 message Bar {}; 1060 `, 1061 }, 1062 } 1063 dir, err := createFiles(files) 1064 if err != nil { 1065 t.Fatal(err) 1066 } 1067 defer os.RemoveAll(dir) 1068 1069 args := []string{"-go_prefix", "example.com/repo"} 1070 if err := runGazelle(dir, args); err != nil { 1071 t.Fatal(err) 1072 } 1073 1074 checkFiles(t, dir, []fileSpec{ 1075 { 1076 path: "foo/BUILD.bazel", 1077 content: ` 1078 load("@io_bazel_rules_go//go:def.bzl", "go_library") 1079 1080 go_library( 1081 name = "go_default_library", 1082 srcs = ["extra.go"], 1083 importpath = "example.com/repo/foo", 1084 visibility = ["//visibility:public"], 1085 ) 1086 `, 1087 }, 1088 }) 1089 } 1090 1091 func TestCustomRepoNames(t *testing.T) { 1092 files := []fileSpec{ 1093 { 1094 path: "WORKSPACE", 1095 content: ` 1096 go_repository( 1097 name = "custom_repo", 1098 importpath = "example.com/bar", 1099 commit = "123456", 1100 ) 1101 `, 1102 }, { 1103 path: "foo.go", 1104 content: ` 1105 package foo 1106 1107 import _ "example.com/bar" 1108 `, 1109 }, 1110 } 1111 dir, err := createFiles(files) 1112 if err != nil { 1113 t.Fatal(err) 1114 } 1115 defer os.RemoveAll(dir) 1116 1117 args := []string{"-go_prefix", "example.com/foo"} 1118 if err := runGazelle(dir, args); err != nil { 1119 t.Fatal(err) 1120 } 1121 1122 checkFiles(t, dir, []fileSpec{ 1123 { 1124 path: "BUILD.bazel", 1125 content: ` 1126 load("@io_bazel_rules_go//go:def.bzl", "go_library") 1127 1128 go_library( 1129 name = "go_default_library", 1130 srcs = ["foo.go"], 1131 importpath = "example.com/foo", 1132 visibility = ["//visibility:public"], 1133 deps = ["@custom_repo//:go_default_library"], 1134 ) 1135 `, 1136 }, 1137 }) 1138 } 1139 1140 func TestImportReposFromDep(t *testing.T) { 1141 files := []fileSpec{ 1142 { 1143 path: "WORKSPACE", 1144 content: ` 1145 http_archive( 1146 name = "io_bazel_rules_go", 1147 url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.1/rules_go-0.10.1.tar.gz", 1148 sha256 = "4b14d8dd31c6dbaf3ff871adcd03f28c3274e42abc855cb8fb4d01233c0154dc", 1149 ) 1150 http_archive( 1151 name = "bazel_gazelle", 1152 url = "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.10.0/bazel-gazelle-0.10.0.tar.gz", 1153 sha256 = "6228d9618ab9536892aa69082c063207c91e777e51bd3c5544c9c060cafe1bd8", 1154 ) 1155 load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains", "go_repository") 1156 go_rules_dependencies() 1157 go_register_toolchains() 1158 1159 load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") 1160 gazelle_dependencies() 1161 1162 go_repository( 1163 name = "org_golang_x_net", 1164 importpath = "golang.org/x/net", 1165 tag = "1.2", 1166 ) 1167 1168 # keep 1169 go_repository( 1170 name = "org_golang_x_sys", 1171 importpath = "golang.org/x/sys", 1172 remote = "https://github.com/golang/sys", 1173 ) 1174 1175 http_archive( 1176 name = "com_github_go_yaml_yaml", 1177 urls = ["https://example.com/yaml.tar.gz"], 1178 sha256 = "1234", 1179 ) 1180 `, 1181 }, { 1182 path: "Gopkg.lock", 1183 content: `# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 1184 1185 1186 [[projects]] 1187 name = "github.com/pkg/errors" 1188 packages = ["."] 1189 revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 1190 version = "v0.8.0" 1191 1192 [[projects]] 1193 branch = "master" 1194 name = "golang.org/x/net" 1195 packages = ["context"] 1196 revision = "66aacef3dd8a676686c7ae3716979581e8b03c47" 1197 1198 [[projects]] 1199 branch = "master" 1200 name = "golang.org/x/sys" 1201 packages = ["unix"] 1202 revision = "bb24a47a89eac6c1227fbcb2ae37a8b9ed323366" 1203 1204 [[projects]] 1205 branch = "v2" 1206 name = "github.com/go-yaml/yaml" 1207 packages = ["."] 1208 revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b" 1209 1210 [solve-meta] 1211 analyzer-name = "dep" 1212 analyzer-version = 1 1213 inputs-digest = "05c1cd69be2c917c0cc4b32942830c2acfa044d8200fdc94716aae48a8083702" 1214 solver-name = "gps-cdcl" 1215 solver-version = 1 1216 `, 1217 }, 1218 } 1219 dir, err := createFiles(files) 1220 if err != nil { 1221 t.Fatal(err) 1222 } 1223 defer os.RemoveAll(dir) 1224 1225 args := []string{"update-repos", "-from_file", "Gopkg.lock"} 1226 if err := runGazelle(dir, args); err != nil { 1227 t.Fatal(err) 1228 } 1229 1230 checkFiles(t, dir, []fileSpec{ 1231 { 1232 path: "WORKSPACE", 1233 content: ` 1234 http_archive( 1235 name = "io_bazel_rules_go", 1236 url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.1/rules_go-0.10.1.tar.gz", 1237 sha256 = "4b14d8dd31c6dbaf3ff871adcd03f28c3274e42abc855cb8fb4d01233c0154dc", 1238 ) 1239 1240 http_archive( 1241 name = "bazel_gazelle", 1242 url = "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.10.0/bazel-gazelle-0.10.0.tar.gz", 1243 sha256 = "6228d9618ab9536892aa69082c063207c91e777e51bd3c5544c9c060cafe1bd8", 1244 ) 1245 1246 load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies") 1247 1248 go_rules_dependencies() 1249 1250 go_register_toolchains() 1251 1252 load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") 1253 1254 gazelle_dependencies() 1255 1256 go_repository( 1257 name = "org_golang_x_net", 1258 commit = "66aacef3dd8a676686c7ae3716979581e8b03c47", 1259 importpath = "golang.org/x/net", 1260 ) 1261 1262 # keep 1263 go_repository( 1264 name = "org_golang_x_sys", 1265 importpath = "golang.org/x/sys", 1266 remote = "https://github.com/golang/sys", 1267 ) 1268 1269 http_archive( 1270 name = "com_github_go_yaml_yaml", 1271 urls = ["https://example.com/yaml.tar.gz"], 1272 sha256 = "1234", 1273 ) 1274 1275 go_repository( 1276 name = "com_github_pkg_errors", 1277 commit = "645ef00459ed84a119197bfb8d8205042c6df63d", 1278 importpath = "github.com/pkg/errors", 1279 ) 1280 `, 1281 }}) 1282 } 1283 1284 func TestDeleteRulesInEmptyDir(t *testing.T) { 1285 files := []fileSpec{ 1286 {path: "WORKSPACE"}, 1287 { 1288 path: "BUILD.bazel", 1289 content: ` 1290 load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_binary") 1291 1292 go_library( 1293 name = "go_default_library", 1294 srcs = [ 1295 "bar.go", 1296 "foo.go", 1297 ], 1298 importpath = "example.com/repo", 1299 visibility = ["//visibility:private"], 1300 ) 1301 1302 go_binary( 1303 name = "cmd", 1304 embed = [":go_default_library"], 1305 visibility = ["//visibility:public"], 1306 ) 1307 `, 1308 }, 1309 } 1310 dir, err := createFiles(files) 1311 if err != nil { 1312 t.Fatal(err) 1313 } 1314 defer os.RemoveAll(dir) 1315 1316 args := []string{"-go_prefix=example.com/repo"} 1317 if err := runGazelle(dir, args); err != nil { 1318 t.Fatal(err) 1319 } 1320 1321 checkFiles(t, dir, []fileSpec{ 1322 { 1323 path: "BUILD.bazel", 1324 content: "", 1325 }, 1326 }) 1327 } 1328 1329 func TestFixWorkspaceWithoutGazelle(t *testing.T) { 1330 files := []fileSpec{ 1331 { 1332 path: "WORKSPACE", 1333 content: ` 1334 load("@io_bazel_rules_go//go:def.bzl", "go_repository") 1335 1336 go_repository( 1337 name = "com_example_repo", 1338 importpath = "example.com/repo", 1339 tag = "1.2.3", 1340 ) 1341 `, 1342 }, 1343 } 1344 dir, err := createFiles(files) 1345 if err != nil { 1346 t.Fatal(err) 1347 } 1348 defer os.RemoveAll(dir) 1349 1350 if err := runGazelle(dir, []string{"fix", "-go_prefix="}); err == nil { 1351 t.Error("got success; want error") 1352 } else if want := "bazel_gazelle is not declared"; !strings.Contains(err.Error(), want) { 1353 t.Errorf("got error %v; want error containing %q", err, want) 1354 } 1355 } 1356 1357 // TestFixGazelle checks that loads of the gazelle macro from the old location 1358 // in rules_go are replaced with the new location in @bazel_gazelle. 1359 func TestFixGazelle(t *testing.T) { 1360 files := []fileSpec{ 1361 { 1362 path: "WORKSPACE", 1363 }, { 1364 path: "BUILD.bazel", 1365 content: ` 1366 load("@io_bazel_rules_go//go:def.bzl", "gazelle", "go_library") 1367 1368 gazelle(name = "gazelle") 1369 1370 # keep 1371 go_library(name = "go_default_library") 1372 `, 1373 }, 1374 } 1375 dir, err := createFiles(files) 1376 if err != nil { 1377 t.Fatal(err) 1378 } 1379 defer os.RemoveAll(dir) 1380 1381 if err := runGazelle(dir, nil); err != nil { 1382 t.Fatal(err) 1383 } 1384 checkFiles(t, dir, []fileSpec{ 1385 { 1386 path: "BUILD.bazel", 1387 content: ` 1388 load("@bazel_gazelle//:def.bzl", "gazelle") 1389 load("@io_bazel_rules_go//go:def.bzl", "go_library") 1390 1391 gazelle(name = "gazelle") 1392 1393 # keep 1394 go_library(name = "go_default_library") 1395 `, 1396 }, 1397 }) 1398 } 1399 1400 // TestKeepDeps checks rules with keep comments on the rule or on the deps 1401 // attribute will not be modified during dependency resolution. Verifies #212. 1402 func TestKeepDeps(t *testing.T) { 1403 files := []fileSpec{ 1404 { 1405 path: "WORKSPACE", 1406 }, { 1407 path: "BUILD.bazel", 1408 content: ` 1409 load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 1410 1411 # gazelle:prefix example.com/repo 1412 1413 # keep 1414 go_library( 1415 name = "go_default_library", 1416 srcs = ["lib.go"], 1417 importpath = "example.com/repo", 1418 deps = [":dont_remove"], 1419 ) 1420 1421 go_test( 1422 name = "go_default_test", 1423 # keep 1424 srcs = ["lib_test.go"], 1425 # keep 1426 embed = [":go_default_library"], 1427 # keep 1428 deps = [":dont_remove"], 1429 ) 1430 `, 1431 }, 1432 } 1433 dir, err := createFiles(files) 1434 if err != nil { 1435 t.Fatal(err) 1436 } 1437 defer os.RemoveAll(dir) 1438 1439 if err := runGazelle(dir, nil); err != nil { 1440 t.Fatal(err) 1441 } 1442 1443 checkFiles(t, dir, files) 1444 } 1445 1446 func TestDontCreateBuildFileInEmptyDir(t *testing.T) { 1447 files := []fileSpec{ 1448 {path: "WORKSPACE"}, 1449 {path: "sub/"}, 1450 } 1451 dir, err := createFiles(files) 1452 if err != nil { 1453 t.Fatal(err) 1454 } 1455 defer os.RemoveAll(dir) 1456 if err := runGazelle(dir, nil); err != nil { 1457 t.Error(err) 1458 } 1459 for _, f := range []string{"BUILD.bazel", "sub/BUILD.bazel"} { 1460 path := filepath.Join(dir, filepath.FromSlash(f)) 1461 _, err := os.Stat(path) 1462 if err == nil { 1463 t.Errorf("%s: build file was created", f) 1464 } 1465 } 1466 } 1467 1468 // TODO(jayconrod): more tests 1469 // run in fix mode in testdata directories to create new files 1470 // run in diff mode in testdata directories to update existing files (no change)