Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion go/tools/releaser/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("//go:def.bzl", "go_binary", "go_library")
load("//go:def.bzl", "go_binary", "go_library", "go_test")

go_binary(
name = "releaser",
Expand Down Expand Up @@ -28,3 +28,10 @@ go_library(
"@org_golang_x_sync//errgroup",
],
)

go_test(
name = "releaser_test",
srcs = ["upgradedep_test.go"],
embed = [":releaser_lib"],
deps = ["@com_github_bazelbuild_buildtools//build:go_default_library"],
)
54 changes: 47 additions & 7 deletions go/tools/releaser/upgradedep.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,19 +433,20 @@ func upgradeDepDecl(ctx context.Context, gh *githubClient, workDir, name string,
return fmt.Errorf("\"patches\" attribute is not a list")
}
for patchIndex, patchLabelExpr := range patchesList.List {
patchLabel, ok := patchLabelExpr.(*bzl.StringExpr)
if !ok {
return fmt.Errorf("not all patches are string literals")
patchLabelValue, comments, err := parsePatchesItem(patchLabelExpr)
if err != nil {
return err
Comment thread
JamyDev marked this conversation as resolved.
Outdated
}
if !strings.HasPrefix(patchLabel.Value, "@io_bazel_rules_go//third_party:") {
return fmt.Errorf("patch does not start with '@io_bazel_rules_go//third_party:': %s", patchLabel)

if !strings.HasPrefix(patchLabelValue, "//third_party:") {
return fmt.Errorf("patch does not start with '//third_party:': %s", patchLabelValue)
Comment thread
JamyDev marked this conversation as resolved.
Outdated
}
patchName := patchLabel.Value[len("@io_bazel_rules_go//third_party:"):]
patchName := patchLabelValue[len("//third_party:"):]
patchPath := filepath.Join(rootDir, "third_party", patchName)
prevDir := filepath.Join(workDir, name, string('a'+patchIndex))
patchDir := filepath.Join(workDir, name, string('a'+patchIndex+1))
var patchCmd []string
for _, c := range patchLabel.Comment().Before {
for _, c := range comments.Before {
words := strings.Fields(strings.TrimPrefix(c.Token, "#"))
if len(words) > 0 && words[0] == "releaser:patch-cmd" {
patchCmd = words[1:]
Expand Down Expand Up @@ -488,6 +489,45 @@ func upgradeDepDecl(ctx context.Context, gh *githubClient, workDir, name string,
return nil
}

func parsePatchesItem(patchLabelExpr bzl.Expr) (value string, comments *bzl.Comments, err error) {
// Parse as regular call
Comment thread
JamyDev marked this conversation as resolved.
Outdated
patchLabelCall, ok := patchLabelExpr.(*bzl.CallExpr)

if ok {
// Verify the identifier, should be Label
Comment thread
JamyDev marked this conversation as resolved.
ident, ok := patchLabelCall.X.(*bzl.Ident)
if !ok {
return "", nil, fmt.Errorf("invalid identifier while parsing patch label")
}
if ident.Name != "Label" {
return "", nil, fmt.Errorf("invalid patch function: %s", ident.Name)
Comment thread
JamyDev marked this conversation as resolved.
Outdated
}

// Expect 1 String argument with the patch
if len(patchLabelCall.List) != 1 {
return "", nil, fmt.Errorf("Label expr should have 1 argument, found %d", len(patchLabelCall.List))
}

// Parse patch as a string
patchLabelStr, ok := patchLabelCall.List[0].(*bzl.StringExpr)
if !ok {
return "", nil, fmt.Errorf("Label expr does not contain a string literal")
}
return patchLabelStr.Value, patchLabelCall.Comment(), nil
}

// non-label string literal
patchLabelStr, ok := patchLabelExpr.(*bzl.StringExpr)
if !ok {
return "", nil, fmt.Errorf("not all patches are string literals or Label()")
}

if strings.HasPrefix(patchLabelStr.Value, "@io_bazel_rules_go") {
Comment thread
JamyDev marked this conversation as resolved.
Outdated
return patchLabelStr.Value[len("@io_bazel_rules_go"):], patchLabelStr.Comment(), nil
}
return patchLabelStr.Value, patchLabelStr.Comment(), nil
}

// parseUpgradeDepDirective parses a '# releaser:upgrade-dep org repo' directive
// and returns the organization and repository name or an error if the directive
// was not found or malformed.
Expand Down
89 changes: 89 additions & 0 deletions go/tools/releaser/upgradedep_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"fmt"
"testing"

bzl "github.com/bazelbuild/buildtools/build"
)

func TestPatchItemParser(t *testing.T) {
Comment thread
JamyDev marked this conversation as resolved.
Outdated
tests := []struct {
expression []byte
result string
error string
}{
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
Label("//third_party:org_golang_x_tools-gazelle.patch")`),
result: "//third_party:org_golang_x_tools-gazelle.patch",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
"@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch"`),
result: "//third_party:org_golang_x_tools-gazelle.patch",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
"//third_party:org_golang_x_tools-gazelle.patch"`),
result: "//third_party:org_golang_x_tools-gazelle.patch",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
Label("@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch")`),
result: "@io_bazel_rules_go//third_party:org_golang_x_tools-gazelle.patch",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
NotLabel("//third_party:org_golang_x_tools-gazelle.patch")`),
result: "",
error: "invalid patch function: NotLabel",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
NotLabel(True)`),
error: "invalid patch function: NotLabel",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
True`),
error: "not all patches are string literals or Label()",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
Label("//third_party:org_golang_x_tools-gazelle.patch", True)`),
error: "Label expr should have 1 argument, found 2",
},
{
expression: []byte(`# releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/tools -go_naming_convention import_alias
Label(True)`),
error: "Label expr does not contain a string literal",
},
}

for _, tt := range tests {
t.Run(fmt.Sprintf("%v", tt.expression), func(t *testing.T) {
patchExpr, err := bzl.Parse("repos.bzl", tt.expression)
if err != nil {
t.Fatalf(err.Error())
}

patchLabelStr, _, err := parsePatchesItem(patchExpr.Stmt[0])
if err != nil && err.Error() != tt.error {
Comment thread
JamyDev marked this conversation as resolved.
Outdated
if tt.error != "" {
t.Errorf("expected error '%s', but got error '%s' instead", tt.error, err.Error())
} else {
t.Errorf("unexpected error while parsing expression: %s", err.Error())
}
}

if err == nil && patchLabelStr != tt.result {
if tt.error != "" {
t.Errorf("expected error '%s', but got result '%s' instead", tt.error, patchLabelStr)
} else {
t.Errorf("expected result '%s', but got result '%s' instead", tt.result, patchLabelStr)
}
}
})
}
}