github.com/wolfd/bazel-gazelle@v0.14.0/internal/language/go/resolve_test.go (about) 1 /* Copyright 2018 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 package golang 17 18 import ( 19 "fmt" 20 "path/filepath" 21 "strings" 22 "testing" 23 24 "github.com/bazelbuild/bazel-gazelle/internal/config" 25 "github.com/bazelbuild/bazel-gazelle/internal/label" 26 "github.com/bazelbuild/bazel-gazelle/internal/language/proto" 27 "github.com/bazelbuild/bazel-gazelle/internal/repos" 28 "github.com/bazelbuild/bazel-gazelle/internal/resolve" 29 "github.com/bazelbuild/bazel-gazelle/internal/rule" 30 bzl "github.com/bazelbuild/buildtools/build" 31 "golang.org/x/tools/go/vcs" 32 ) 33 34 func TestResolveGo(t *testing.T) { 35 type buildFile struct { 36 rel, content string 37 } 38 type testCase struct { 39 desc string 40 index []buildFile 41 old buildFile 42 want string 43 } 44 for _, tc := range []testCase{ 45 { 46 desc: "std", 47 index: []buildFile{{ 48 rel: "bad", 49 content: ` 50 go_library( 51 name = "go_default_library", 52 importpath = "fmt", 53 ) 54 `, 55 }}, 56 old: buildFile{ 57 content: ` 58 go_binary( 59 name = "dep", 60 _imports = ["fmt"], 61 ) 62 `, 63 }, 64 want: `go_binary(name = "dep")`, 65 }, { 66 desc: "self_import", 67 old: buildFile{content: ` 68 go_library( 69 name = "go_default_library", 70 importpath = "foo", 71 _imports = ["foo"], 72 ) 73 `}, 74 want: ` 75 go_library( 76 name = "go_default_library", 77 importpath = "foo", 78 ) 79 `, 80 }, { 81 desc: "self_import_embed", 82 old: buildFile{content: ` 83 go_library( 84 name = "a", 85 embeds = [":b"], 86 importpath = "x", 87 ) 88 89 go_library( 90 name = "b", 91 importpath = "x", 92 _imports = ["x"], 93 ) 94 `}, 95 want: ` 96 go_library( 97 name = "a", 98 embeds = [":b"], 99 importpath = "x", 100 ) 101 102 go_library( 103 name = "b", 104 importpath = "x", 105 ) 106 `, 107 }, { 108 desc: "same_package", 109 old: buildFile{content: ` 110 go_library( 111 name = "a", 112 importpath = "foo", 113 ) 114 115 go_binary( 116 name = "b", 117 _imports = ["foo"], 118 ) 119 `}, 120 want: ` 121 go_library( 122 name = "a", 123 importpath = "foo", 124 ) 125 126 go_binary( 127 name = "b", 128 deps = [":a"], 129 ) 130 `, 131 }, { 132 desc: "different_package", 133 index: []buildFile{{ 134 rel: "a", 135 content: ` 136 go_library( 137 name = "a_lib", 138 importpath = "aa", 139 ) 140 `, 141 }}, 142 old: buildFile{ 143 rel: "b", 144 content: ` 145 go_binary( 146 name = "bin", 147 _imports = ["aa"], 148 ) 149 `, 150 }, 151 want: ` 152 go_binary( 153 name = "bin", 154 deps = ["//a:a_lib"], 155 ) 156 `, 157 }, { 158 desc: "multiple_rules_ambiguous", 159 index: []buildFile{{ 160 rel: "foo", 161 content: ` 162 go_library( 163 name = "a", 164 importpath = "example.com/foo", 165 ) 166 167 go_library( 168 name = "b", 169 importpath = "example.com/foo", 170 ) 171 `, 172 }}, 173 old: buildFile{content: ` 174 go_binary( 175 name = "bin", 176 _imports = ["example.com/foo"], 177 ) 178 `, 179 }, 180 // an error should be reported, and no dependency should be emitted 181 want: `go_binary(name = "bin")`, 182 }, { 183 desc: "vendor_not_visible", 184 index: []buildFile{ 185 { 186 rel: "", 187 content: ` 188 go_library( 189 name = "root", 190 importpath = "example.com/foo", 191 ) 192 `, 193 }, { 194 rel: "a/vendor/foo", 195 content: ` 196 go_library( 197 name = "vendored", 198 importpath = "example.com/foo", 199 ) 200 `, 201 }, 202 }, 203 old: buildFile{ 204 rel: "b", 205 content: ` 206 go_binary( 207 name = "bin", 208 _imports = ["example.com/foo"], 209 ) 210 `, 211 }, 212 want: ` 213 go_binary( 214 name = "bin", 215 deps = ["//:root"], 216 ) 217 `, 218 }, { 219 desc: "vendor_supercedes_nonvendor", 220 index: []buildFile{ 221 { 222 rel: "", 223 content: ` 224 go_library( 225 name = "root", 226 importpath = "example.com/foo", 227 ) 228 `, 229 }, { 230 rel: "vendor/foo", 231 content: ` 232 go_library( 233 name = "vendored", 234 importpath = "example.com/foo", 235 ) 236 `, 237 }, 238 }, 239 old: buildFile{ 240 rel: "sub", 241 content: ` 242 go_binary( 243 name = "bin", 244 _imports = ["example.com/foo"], 245 ) 246 `, 247 }, 248 want: ` 249 go_binary( 250 name = "bin", 251 deps = ["//vendor/foo:vendored"], 252 ) 253 `, 254 }, { 255 desc: "deep_vendor_shallow_vendor", 256 index: []buildFile{ 257 { 258 rel: "shallow/vendor", 259 content: ` 260 go_library( 261 name = "shallow", 262 importpath = "example.com/foo", 263 ) 264 `, 265 }, { 266 rel: "shallow/deep/vendor", 267 content: ` 268 go_library( 269 name = "deep", 270 importpath = "example.com/foo", 271 ) 272 `, 273 }, 274 }, 275 old: buildFile{ 276 rel: "shallow/deep", 277 content: ` 278 go_binary( 279 name = "bin", 280 _imports = ["example.com/foo"], 281 ) 282 `, 283 }, 284 want: ` 285 go_binary( 286 name = "bin", 287 deps = ["//shallow/deep/vendor:deep"], 288 ) 289 `, 290 }, { 291 desc: "nested_vendor", 292 index: []buildFile{ 293 { 294 rel: "vendor/a", 295 content: ` 296 go_library( 297 name = "a", 298 importpath = "a", 299 ) 300 `, 301 }, { 302 rel: "vendor/b/vendor/a", 303 content: ` 304 go_library( 305 name = "a", 306 importpath = "a", 307 ) 308 `, 309 }, 310 }, 311 old: buildFile{ 312 rel: "vendor/b/c", 313 content: ` 314 go_binary( 315 name = "bin", 316 _imports = ["a"], 317 ) 318 `, 319 }, 320 want: ` 321 go_binary( 322 name = "bin", 323 deps = ["//vendor/b/vendor/a"], 324 ) 325 `, 326 }, { 327 desc: "skip_self_embed", 328 old: buildFile{content: ` 329 go_library( 330 name = "go_default_library", 331 srcs = ["lib.go"], 332 importpath = "example.com/repo/lib", 333 ) 334 335 go_test( 336 name = "go_default_test", 337 embed = [":go_default_library"], 338 _imports = ["example.com/repo/lib"], 339 ) 340 `, 341 }, 342 want: ` 343 go_library( 344 name = "go_default_library", 345 srcs = ["lib.go"], 346 importpath = "example.com/repo/lib", 347 ) 348 349 go_test( 350 name = "go_default_test", 351 embed = [":go_default_library"], 352 ) 353 `, 354 }, { 355 desc: "binary_embed", 356 old: buildFile{content: ` 357 go_library( 358 name = "a", 359 importpath = "a", 360 ) 361 362 go_library( 363 name = "b", 364 embed = [":a"], 365 ) 366 367 go_binary( 368 name = "c", 369 embed = [":a"], 370 importpath = "a", 371 ) 372 373 go_library( 374 name = "d", 375 _imports = ["a"], 376 ) 377 `}, 378 want: ` 379 go_library( 380 name = "a", 381 importpath = "a", 382 ) 383 384 go_library( 385 name = "b", 386 embed = [":a"], 387 ) 388 389 go_binary( 390 name = "c", 391 embed = [":a"], 392 importpath = "a", 393 ) 394 395 go_library( 396 name = "d", 397 deps = [":b"], 398 ) 399 `, 400 }, { 401 desc: "local_unknown", 402 old: buildFile{content: ` 403 go_binary( 404 name = "bin", 405 _imports = [ 406 "example.com/repo/resolve", 407 "example.com/repo/resolve/sub", 408 ], 409 ) 410 `}, 411 want: ` 412 go_binary( 413 name = "bin", 414 deps = [ 415 ":go_default_library", 416 "//sub:go_default_library", 417 ], 418 ) 419 `, 420 }, { 421 desc: "local_relative", 422 old: buildFile{ 423 rel: "a", 424 content: ` 425 go_binary( 426 name = "bin", 427 _imports = [ 428 ".", 429 "./b", 430 "../c", 431 ], 432 ) 433 `, 434 }, 435 want: ` 436 go_binary( 437 name = "bin", 438 deps = [ 439 ":go_default_library", 440 "//a/b:go_default_library", 441 "//c:go_default_library", 442 ], 443 ) 444 `, 445 }, { 446 desc: "vendor_no_index", 447 old: buildFile{content: ` 448 go_binary( 449 name = "bin", 450 _imports = ["example.com/outside/prefix"], 451 ) 452 `}, 453 want: ` 454 go_binary( 455 name = "bin", 456 deps = ["//vendor/example.com/outside/prefix:go_default_library"], 457 ) 458 `, 459 }, { 460 desc: "test_and_library_not_indexed", 461 index: []buildFile{{ 462 rel: "foo", 463 content: ` 464 go_test( 465 name = "go_default_test", 466 importpath = "example.com/foo", 467 ) 468 469 go_binary( 470 name = "cmd", 471 importpath = "example.com/foo", 472 ) 473 `, 474 }}, 475 old: buildFile{content: ` 476 go_binary( 477 name = "bin", 478 _imports = ["example.com/foo"], 479 ) 480 `}, 481 want: ` 482 go_binary( 483 name = "bin", 484 deps = ["//vendor/example.com/foo:go_default_library"], 485 )`, 486 }, { 487 desc: "proto_index", 488 index: []buildFile{{ 489 rel: "sub", 490 content: ` 491 proto_library( 492 name = "foo_proto", 493 srcs = ["bar.proto"], 494 ) 495 496 go_proto_library( 497 name = "foo_go_proto", 498 importpath = "example.com/foo", 499 proto = ":foo_proto", 500 ) 501 502 go_library( 503 name = "embed", 504 embed = [":foo_go_proto"], 505 importpath = "example.com/foo", 506 ) 507 `, 508 }}, 509 old: buildFile{content: ` 510 go_proto_library( 511 name = "dep_proto", 512 _imports = ["sub/bar.proto"], 513 ) 514 `}, 515 want: ` 516 go_proto_library( 517 name = "dep_proto", 518 deps = ["//sub:embed"], 519 ) 520 `, 521 }, { 522 desc: "proto_embed", 523 old: buildFile{content: ` 524 proto_library( 525 name = "foo_proto", 526 srcs = ["foo.proto"], 527 ) 528 529 go_proto_library( 530 name = "foo_go_proto", 531 importpath = "example.com/repo/foo", 532 proto = ":foo_proto", 533 ) 534 535 go_library( 536 name = "foo_embedder", 537 embed = [":foo_go_proto"], 538 ) 539 540 proto_library( 541 name = "bar_proto", 542 srcs = ["bar.proto"], 543 _imports = ["foo.proto"], 544 ) 545 546 go_proto_library( 547 name = "bar_go_proto", 548 proto = ":bar_proto", 549 _imports = ["foo.proto"], 550 ) 551 `}, 552 want: ` 553 proto_library( 554 name = "foo_proto", 555 srcs = ["foo.proto"], 556 ) 557 558 go_proto_library( 559 name = "foo_go_proto", 560 importpath = "example.com/repo/foo", 561 proto = ":foo_proto", 562 ) 563 564 go_library( 565 name = "foo_embedder", 566 embed = [":foo_go_proto"], 567 ) 568 569 proto_library( 570 name = "bar_proto", 571 srcs = ["bar.proto"], 572 deps = [":foo_proto"], 573 ) 574 575 go_proto_library( 576 name = "bar_go_proto", 577 proto = ":bar_proto", 578 deps = [":foo_embedder"], 579 ) 580 `, 581 }, { 582 desc: "proto_wkt", 583 old: buildFile{content: ` 584 go_proto_library( 585 name = "wkts_go_proto", 586 _imports = [ 587 "google/protobuf/any.proto", 588 "google/protobuf/api.proto", 589 "google/protobuf/compiler_plugin.proto", 590 "google/protobuf/descriptor.proto", 591 "google/protobuf/duration.proto", 592 "google/protobuf/empty.proto", 593 "google/protobuf/field_mask.proto", 594 "google/protobuf/source_context.proto", 595 "google/protobuf/struct.proto", 596 "google/protobuf/timestamp.proto", 597 "google/protobuf/type.proto", 598 "google/protobuf/wrappers.proto", 599 "google/api/http.proto", 600 "google/rpc/status.proto", 601 "google/type/latlng.proto", 602 ], 603 ) 604 605 go_library( 606 name = "wkts_go_lib", 607 _imports = [ 608 "github.com/golang/protobuf/ptypes/any", 609 "google.golang.org/genproto/protobuf/api", 610 "github.com/golang/protobuf/protoc-gen-go/descriptor", 611 "github.com/golang/protobuf/ptypes/duration", 612 "github.com/golang/protobuf/ptypes/empty", 613 "google.golang.org/genproto/protobuf/field_mask", 614 "google.golang.org/genproto/protobuf/source_context", 615 "github.com/golang/protobuf/ptypes/struct", 616 "github.com/golang/protobuf/ptypes/timestamp", 617 "github.com/golang/protobuf/ptypes/wrappers", 618 "github.com/golang/protobuf/protoc-gen-go/plugin", 619 "google.golang.org/genproto/protobuf/ptype", 620 "google.golang.org/genproto/googleapis/api/annotations", 621 "google.golang.org/genproto/googleapis/rpc/status", 622 "google.golang.org/genproto/googleapis/type/latlng", 623 ], 624 ) 625 `}, 626 want: ` 627 go_proto_library( 628 name = "wkts_go_proto", 629 deps = [ 630 "@go_googleapis//google/api:annotations_go_proto", 631 "@go_googleapis//google/rpc:status_go_proto", 632 "@go_googleapis//google/type:latlng_go_proto", 633 ], 634 ) 635 636 go_library( 637 name = "wkts_go_lib", 638 deps = [ 639 "@go_googleapis//google/api:annotations_go_proto", 640 "@go_googleapis//google/rpc:status_go_proto", 641 "@go_googleapis//google/type:latlng_go_proto", 642 "@io_bazel_rules_go//proto/wkt:any_go_proto", 643 "@io_bazel_rules_go//proto/wkt:api_go_proto", 644 "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", 645 "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", 646 "@io_bazel_rules_go//proto/wkt:duration_go_proto", 647 "@io_bazel_rules_go//proto/wkt:empty_go_proto", 648 "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", 649 "@io_bazel_rules_go//proto/wkt:source_context_go_proto", 650 "@io_bazel_rules_go//proto/wkt:struct_go_proto", 651 "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", 652 "@io_bazel_rules_go//proto/wkt:type_go_proto", 653 "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", 654 ], 655 ) 656 `, 657 }, { 658 desc: "proto_ptypes", 659 old: buildFile{content: ` 660 go_library( 661 name = "go_default_library", 662 _imports = [ 663 "github.com/golang/protobuf/jsonpb", 664 "github.com/golang/protobuf/descriptor", 665 "github.com/golang/protobuf/ptypes", 666 ], 667 ) 668 `}, 669 want: ` 670 go_library( 671 name = "go_default_library", 672 deps = [ 673 "@com_github_golang_protobuf//descriptor:go_default_library_gen", 674 "@com_github_golang_protobuf//jsonpb:go_default_library_gen", 675 "@com_github_golang_protobuf//ptypes:go_default_library_gen", 676 ], 677 ) 678 `, 679 }, { 680 desc: "proto_self_import", 681 old: buildFile{content: ` 682 proto_library( 683 name = "foo_proto", 684 srcs = [ 685 "a.proto", 686 "b.proto", 687 ], 688 ) 689 690 go_proto_library( 691 name = "foo_go_proto", 692 importpath = "foo", 693 proto = ":foo_proto", 694 _imports = ["a.proto"], 695 ) 696 697 go_library( 698 name = "go_default_library", 699 embed = [":foo_go_proto"], 700 importpath = "foo", 701 ) 702 `}, 703 want: ` 704 proto_library( 705 name = "foo_proto", 706 srcs = [ 707 "a.proto", 708 "b.proto", 709 ], 710 ) 711 712 go_proto_library( 713 name = "foo_go_proto", 714 importpath = "foo", 715 proto = ":foo_proto", 716 ) 717 718 go_library( 719 name = "go_default_library", 720 embed = [":foo_go_proto"], 721 importpath = "foo", 722 ) 723 `, 724 }, 725 } { 726 t.Run(tc.desc, func(t *testing.T) { 727 c, _, langs := testConfig() 728 gc := getGoConfig(c) 729 gc.prefix = "example.com/repo/resolve" 730 gc.depMode = vendorMode 731 kindToResolver := make(map[string]resolve.Resolver) 732 for _, lang := range langs { 733 for kind := range lang.Kinds() { 734 kindToResolver[kind] = lang 735 } 736 } 737 ix := resolve.NewRuleIndex(kindToResolver) 738 rc := testRemoteCache(nil) 739 740 for _, bf := range tc.index { 741 buildPath := filepath.Join(filepath.FromSlash(bf.rel), "BUILD.bazel") 742 f, err := rule.LoadData(buildPath, bf.rel, []byte(bf.content)) 743 if err != nil { 744 t.Fatal(err) 745 } 746 for _, r := range f.Rules { 747 ix.AddRule(c, r, f) 748 } 749 } 750 buildPath := filepath.Join(filepath.FromSlash(tc.old.rel), "BUILD.bazel") 751 f, err := rule.LoadData(buildPath, tc.old.rel, []byte(tc.old.content)) 752 if err != nil { 753 t.Fatal(err) 754 } 755 for _, r := range f.Rules { 756 convertImportsAttr(r) 757 ix.AddRule(c, r, f) 758 } 759 ix.Finish() 760 for _, r := range f.Rules { 761 kindToResolver[r.Kind()].Resolve(c, ix, rc, r, label.New("", tc.old.rel, r.Name())) 762 } 763 f.Sync() 764 got := strings.TrimSpace(string(bzl.Format(f.File))) 765 want := strings.TrimSpace(tc.want) 766 if got != want { 767 t.Errorf("got:\n%s\nwant:\n%s", got, want) 768 } 769 }) 770 } 771 } 772 773 func TestResolveDisableGlobal(t *testing.T) { 774 c, _, langs := testConfig() 775 gc := getGoConfig(c) 776 gc.prefix = "example.com/repo" 777 gc.prefixSet = true 778 proto.GetProtoConfig(c).Mode = proto.DisableGlobalMode 779 ix := resolve.NewRuleIndex(nil) 780 ix.Finish() 781 rc := testRemoteCache([]repos.Repo{ 782 { 783 Name: "com_github_golang_protobuf", 784 GoPrefix: "github.com/golang/protobuf", 785 }, { 786 Name: "org_golang_google_genproto", 787 GoPrefix: "golang.org/google/genproto", 788 }, 789 }) 790 gl := langs[1].(*goLang) 791 oldContent := []byte(` 792 go_library( 793 name = "go_default_library", 794 importpath = "foo", 795 _imports = [ 796 "github.com/golang/protobuf/ptypes/any", 797 "google.golang.org/genproto/protobuf/api", 798 "github.com/golang/protobuf/protoc-gen-go/descriptor", 799 "github.com/golang/protobuf/ptypes/duration", 800 "github.com/golang/protobuf/ptypes/empty", 801 "google.golang.org/genproto/protobuf/field_mask", 802 "google.golang.org/genproto/protobuf/source_context", 803 "github.com/golang/protobuf/ptypes/struct", 804 "github.com/golang/protobuf/ptypes/timestamp", 805 "github.com/golang/protobuf/ptypes/wrappers", 806 "github.com/golang/protobuf/protoc-gen-go/plugin", 807 "google.golang.org/genproto/protobuf/ptype", 808 "google.golang.org/genproto/googleapis/api/annotations", 809 "google.golang.org/genproto/googleapis/rpc/status", 810 "google.golang.org/genproto/googleapis/type/latlng", 811 "github.com/golang/protobuf/jsonpb", 812 "github.com/golang/protobuf/descriptor", 813 "github.com/golang/protobuf/ptypes", 814 ], 815 ) 816 `) 817 f, err := rule.LoadData("BUILD.bazel", "", oldContent) 818 if err != nil { 819 t.Fatal(err) 820 } 821 for _, r := range f.Rules { 822 convertImportsAttr(r) 823 gl.Resolve(c, ix, rc, r, label.New("", "", r.Name())) 824 } 825 f.Sync() 826 got := strings.TrimSpace(string(bzl.Format(f.File))) 827 want := strings.TrimSpace(` 828 go_library( 829 name = "go_default_library", 830 importpath = "foo", 831 deps = [ 832 "@com_github_golang_protobuf//descriptor:go_default_library", 833 "@com_github_golang_protobuf//jsonpb:go_default_library", 834 "@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library", 835 "@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library", 836 "@com_github_golang_protobuf//ptypes:go_default_library", 837 "@com_github_golang_protobuf//ptypes/any:go_default_library", 838 "@com_github_golang_protobuf//ptypes/duration:go_default_library", 839 "@com_github_golang_protobuf//ptypes/empty:go_default_library", 840 "@com_github_golang_protobuf//ptypes/struct:go_default_library", 841 "@com_github_golang_protobuf//ptypes/timestamp:go_default_library", 842 "@com_github_golang_protobuf//ptypes/wrappers:go_default_library", 843 "@org_golang_google_genproto//googleapis/api/annotations:go_default_library", 844 "@org_golang_google_genproto//googleapis/rpc/status:go_default_library", 845 "@org_golang_google_genproto//googleapis/type/latlng:go_default_library", 846 "@org_golang_google_genproto//protobuf/api:go_default_library", 847 "@org_golang_google_genproto//protobuf/field_mask:go_default_library", 848 "@org_golang_google_genproto//protobuf/ptype:go_default_library", 849 "@org_golang_google_genproto//protobuf/source_context:go_default_library", 850 ], 851 ) 852 `) 853 if got != want { 854 t.Errorf("got:\n%s\nwant:%s", got, want) 855 } 856 } 857 858 func TestResolveExternal(t *testing.T) { 859 c, _, langs := testConfig() 860 gc := getGoConfig(c) 861 gc.prefix = "example.com/local" 862 ix := resolve.NewRuleIndex(nil) 863 ix.Finish() 864 gl := langs[1].(*goLang) 865 for _, tc := range []struct { 866 desc, importpath string 867 repos []repos.Repo 868 want string 869 }{ 870 { 871 desc: "top", 872 importpath: "example.com/repo", 873 want: "@com_example_repo//:go_default_library", 874 }, { 875 desc: "sub", 876 importpath: "example.com/repo/lib", 877 want: "@com_example_repo//lib:go_default_library", 878 }, { 879 desc: "custom_repo", 880 repos: []repos.Repo{{ 881 Name: "custom_repo_name", 882 GoPrefix: "example.com/repo", 883 }}, 884 importpath: "example.com/repo/lib", 885 want: "@custom_repo_name//lib:go_default_library", 886 }, { 887 desc: "qualified", 888 importpath: "example.com/repo.git/lib", 889 want: "@com_example_repo_git//lib:go_default_library", 890 }, { 891 desc: "domain", 892 importpath: "example.com/lib", 893 want: "@com_example//lib:go_default_library", 894 }, 895 } { 896 t.Run(tc.desc, func(t *testing.T) { 897 rc := testRemoteCache(tc.repos) 898 r := rule.NewRule("go_library", "x") 899 imports := rule.PlatformStrings{Generic: []string{tc.importpath}} 900 r.SetPrivateAttr(config.GazelleImportsKey, imports) 901 gl.Resolve(c, ix, rc, r, label.New("", "", "x")) 902 deps := r.AttrStrings("deps") 903 if len(deps) != 1 { 904 t.Fatalf("deps: got %d; want 1", len(deps)) 905 } 906 if deps[0] != tc.want { 907 t.Errorf("got %s; want %s", deps[0], tc.want) 908 } 909 }) 910 } 911 } 912 913 func testRemoteCache(knownRepos []repos.Repo) *repos.RemoteCache { 914 rc := repos.NewRemoteCache(knownRepos) 915 rc.RepoRootForImportPath = stubRepoRootForImportPath 916 rc.HeadCmd = func(remote, vcs string) (string, error) { 917 return "", fmt.Errorf("HeadCmd not supported in test") 918 } 919 return rc 920 } 921 922 // stubRepoRootForImportPath is a stub implementation of vcs.RepoRootForImportPath 923 func stubRepoRootForImportPath(importpath string, verbose bool) (*vcs.RepoRoot, error) { 924 if strings.HasPrefix(importpath, "example.com/repo.git") { 925 return &vcs.RepoRoot{ 926 VCS: vcs.ByCmd("git"), 927 Repo: "https://example.com/repo.git", 928 Root: "example.com/repo.git", 929 }, nil 930 } 931 932 if strings.HasPrefix(importpath, "example.com/repo") { 933 return &vcs.RepoRoot{ 934 VCS: vcs.ByCmd("git"), 935 Repo: "https://example.com/repo.git", 936 Root: "example.com/repo", 937 }, nil 938 } 939 940 if strings.HasPrefix(importpath, "example.com") { 941 return &vcs.RepoRoot{ 942 VCS: vcs.ByCmd("git"), 943 Repo: "https://example.com", 944 Root: "example.com", 945 }, nil 946 } 947 948 return nil, fmt.Errorf("could not resolve import path: %q", importpath) 949 } 950 951 func convertImportsAttr(r *rule.Rule) { 952 kind := r.Kind() 953 value := r.AttrStrings("_imports") 954 r.DelAttr("_imports") 955 if _, ok := goKinds[kind]; ok { 956 r.SetPrivateAttr(config.GazelleImportsKey, rule.PlatformStrings{Generic: value}) 957 } else if kind == "proto_library" { 958 r.SetPrivateAttr(config.GazelleImportsKey, value) 959 } 960 }