Skip to content

Commit a93cae3

Browse files
authored
tools/upgradedep: add support for Label based repositories.bzl (#3051)
1 parent 75fdf4c commit a93cae3

File tree

3 files changed

+146
-8
lines changed

3 files changed

+146
-8
lines changed

go/tools/releaser/BUILD.bazel

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//go:def.bzl", "go_binary", "go_library")
1+
load("//go:def.bzl", "go_binary", "go_library", "go_test")
22

33
go_binary(
44
name = "releaser",
@@ -28,3 +28,10 @@ go_library(
2828
"@org_golang_x_sync//errgroup",
2929
],
3030
)
31+
32+
go_test(
33+
name = "releaser_test",
34+
srcs = ["upgradedep_test.go"],
35+
embed = [":releaser_lib"],
36+
deps = ["@com_github_bazelbuild_buildtools//build:go_default_library"],
37+
)

go/tools/releaser/upgradedep.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,19 +433,20 @@ func upgradeDepDecl(ctx context.Context, gh *githubClient, workDir, name string,
433433
return fmt.Errorf("\"patches\" attribute is not a list")
434434
}
435435
for patchIndex, patchLabelExpr := range patchesList.List {
436-
patchLabel, ok := patchLabelExpr.(*bzl.StringExpr)
437-
if !ok {
438-
return fmt.Errorf("not all patches are string literals")
436+
patchLabelValue, comments, err := parsePatchesItem(patchLabelExpr)
437+
if err != nil {
438+
return fmt.Errorf("parsing expr %#v : %w", patchLabelExpr, err)
439439
}
440-
if !strings.HasPrefix(patchLabel.Value, "@io_bazel_rules_go//third_party:") {
441-
return fmt.Errorf("patch does not start with '@io_bazel_rules_go//third_party:': %s", patchLabel)
440+
441+
if !strings.HasPrefix(patchLabelValue, "//third_party:") {
442+
return fmt.Errorf("patch does not start with '//third_party:': %q", patchLabelValue)
442443
}
443-
patchName := patchLabel.Value[len("@io_bazel_rules_go//third_party:"):]
444+
patchName := patchLabelValue[len("//third_party:"):]
444445
patchPath := filepath.Join(rootDir, "third_party", patchName)
445446
prevDir := filepath.Join(workDir, name, string('a'+patchIndex))
446447
patchDir := filepath.Join(workDir, name, string('a'+patchIndex+1))
447448
var patchCmd []string
448-
for _, c := range patchLabel.Comment().Before {
449+
for _, c := range comments.Before {
449450
words := strings.Fields(strings.TrimPrefix(c.Token, "#"))
450451
if len(words) > 0 && words[0] == "releaser:patch-cmd" {
451452
patchCmd = words[1:]
@@ -488,6 +489,34 @@ func upgradeDepDecl(ctx context.Context, gh *githubClient, workDir, name string,
488489
return nil
489490
}
490491

492+
func parsePatchesItem(patchLabelExpr bzl.Expr) (value string, comments *bzl.Comments, err error) {
493+
switch patchLabel := patchLabelExpr.(type) {
494+
case *bzl.CallExpr:
495+
// Verify the identifier, should be Label
496+
if ident, ok := patchLabel.X.(*bzl.Ident); !ok {
497+
return "", nil, fmt.Errorf("invalid identifier while parsing patch label")
498+
} else if ident.Name != "Label" {
499+
return "", nil, fmt.Errorf("invalid patch function: %q", ident.Name)
500+
}
501+
502+
// Expect 1 String argument with the patch
503+
if len(patchLabel.List) != 1 {
504+
return "", nil, fmt.Errorf("Label expr should have 1 argument, found %d", len(patchLabel.List))
505+
}
506+
507+
// Parse patch as a string
508+
patchLabelStr, ok := patchLabel.List[0].(*bzl.StringExpr)
509+
if !ok {
510+
return "", nil, fmt.Errorf("Label expr does not contain a string literal")
511+
}
512+
return patchLabelStr.Value, patchLabel.Comment(), nil
513+
case *bzl.StringExpr:
514+
return strings.TrimPrefix(patchLabel.Value, "@io_bazel_rules_go"), patchLabel.Comment(), nil
515+
default:
516+
return "", nil, fmt.Errorf("not all patches are string literals or Label()")
517+
}
518+
}
519+
491520
// parseUpgradeDepDirective parses a '# releaser:upgrade-dep org repo' directive
492521
// and returns the organization and repository name or an error if the directive
493522
// was not found or malformed.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
bzl "github.com/bazelbuild/buildtools/build"
8+
)
9+
10+
func TestPatchItemParser_Success(t *testing.T) {
11+
tests := []struct {
12+
expression []byte
13+
result string
14+
}{
15+
{
16+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
17+
Label("//third_party:org_golang_x_tools-gazelle.patch")`),
18+
result: "//third_party:org_golang_x_tools-gazelle.patch",
19+
},
20+
{
21+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
22+
"@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch"`),
23+
result: "//third_party:org_golang_x_tools-gazelle.patch",
24+
},
25+
{
26+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
27+
"//third_party:org_golang_x_tools-gazelle.patch"`),
28+
result: "//third_party:org_golang_x_tools-gazelle.patch",
29+
},
30+
{
31+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
32+
Label("@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch")`),
33+
result: "@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch",
34+
},
35+
}
36+
37+
for _, tt := range tests {
38+
t.Run(fmt.Sprintf("%v", tt.expression), func(t *testing.T) {
39+
patchExpr, err := bzl.Parse("repos.bzl", tt.expression)
40+
if err != nil {
41+
t.Fatalf(err.Error())
42+
}
43+
44+
patchLabelStr, _, err := parsePatchesItem(patchExpr.Stmt[0])
45+
if err != nil {
46+
t.Errorf("unexpected error while parsing expression: %q", err.Error())
47+
} else if patchLabelStr != tt.result {
48+
t.Errorf("expected result %q, but got result %q instead", tt.result, patchLabelStr)
49+
}
50+
})
51+
}
52+
}
53+
54+
func TestPatchItemParser_Error(t *testing.T) {
55+
tests := []struct {
56+
expression []byte
57+
error string
58+
}{
59+
{
60+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
61+
NotLabel("//third_party:org_golang_x_tools-gazelle.patch")`),
62+
error: `invalid patch function: "NotLabel"`,
63+
},
64+
{
65+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
66+
NotLabel(True)`),
67+
error: `invalid patch function: "NotLabel"`,
68+
},
69+
{
70+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
71+
True`),
72+
error: "not all patches are string literals or Label()",
73+
},
74+
{
75+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
76+
Label("//third_party:org_golang_x_tools-gazelle.patch", True)`),
77+
error: "Label expr should have 1 argument, found 2",
78+
},
79+
{
80+
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
81+
Label(True)`),
82+
error: "Label expr does not contain a string literal",
83+
},
84+
}
85+
86+
for _, tt := range tests {
87+
t.Run(fmt.Sprintf("%v", tt.expression), func(t *testing.T) {
88+
patchExpr, err := bzl.Parse("repos.bzl", tt.expression)
89+
if err != nil {
90+
t.Fatalf(err.Error())
91+
}
92+
93+
patchLabelStr, _, err := parsePatchesItem(patchExpr.Stmt[0])
94+
95+
if err == nil {
96+
t.Errorf("expected error %q, but got result %q instead", tt.error, patchLabelStr)
97+
} else if err.Error() != tt.error {
98+
t.Errorf("expected error %q, but got error %q instead", tt.error, err.Error())
99+
}
100+
})
101+
}
102+
}

0 commit comments

Comments
 (0)