cmd/relui,internal/task: add workflow for re-syncing go-private master
This is currently a manual process that requires a high-priv grant, a
workflow significantly reduces the likelihood of getting this wrong. It
also lets us use a cron-like schedule to automate these updates.
Updates golang/go#59717
Change-Id: Iff7ce7c37f2ecd9dfee79ee8e80cfb98810011e6
Reviewed-on: https://go-review.googlesource.com/c/build/+/486575
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/relui/main.go b/cmd/relui/main.go
index 9de5a33..2051571 100644
--- a/cmd/relui/main.go
+++ b/cmd/relui/main.go
@@ -245,6 +245,12 @@
}
dh.RegisterDefinition("Tag a new version of x/telemetry/config (if necessary)", tagTelemetryTasks.NewDefinition())
+ privateSyncTask := &task.PrivateMasterSyncTask{
+ PrivateGerritURL: "https://team.googlesource.com/golang/go-private",
+ Ref: "public",
+ }
+ dh.RegisterDefinition("Sync go-private master branch with public", privateSyncTask.NewDefinition())
+
var base *url.URL
if *baseURL != "" {
base, err = url.Parse(*baseURL)
diff --git a/internal/task/sync_private.go b/internal/task/sync_private.go
new file mode 100644
index 0000000..7a2a37e
--- /dev/null
+++ b/internal/task/sync_private.go
@@ -0,0 +1,47 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package task
+
+import (
+ "fmt"
+
+ wf "golang.org/x/build/internal/workflow"
+)
+
+type PrivateMasterSyncTask struct {
+ PrivateGerritURL string
+ Ref string
+}
+
+func (t *PrivateMasterSyncTask) NewDefinition() *wf.Definition {
+ wd := wf.New()
+ // We use a Task, instead of an Action, even though we don't actually want
+ // to return any result, because nothing depends on the Action, and if we
+ // use an Action the definition will tell us we don't reference it anywhere
+ // and say it should be deleted.
+ synced := wf.Task0(wd, "Sync go-private master to public", func(ctx *wf.TaskContext) (string, error) {
+ git := &Git{}
+ repo, err := git.Clone(ctx, t.PrivateGerritURL)
+ if err != nil {
+ return "", err
+ }
+
+ // NOTE: we assume this is generally safe in the case of a race between
+ // submitting a patch and resetting the master branch due to the ordering
+ // of operations at Gerrit. If the submit wins, we reset the master
+ // branch, and the submitted commit is orphaned, which is the expected
+ // behavior anyway. If the reset wins, the submission will either be
+ // cherry-picked onto the new base, which should either succeed, or fail
+ // due to a merge conflict, or Gerrit will reject the submission because
+ // something changed underneath it. Either case seems fine.
+ if _, err := repo.RunCommand(ctx.Context, "push", "--force", "origin", fmt.Sprintf("origin/%s:refs/heads/master", t.Ref)); err != nil {
+ return "", err
+ }
+
+ return "finished", nil
+ })
+ wf.Output(wd, fmt.Sprintf("Reset master to %s", t.Ref), synced)
+ return wd
+}
diff --git a/internal/task/sync_private_test.go b/internal/task/sync_private_test.go
new file mode 100644
index 0000000..c4a4b10
--- /dev/null
+++ b/internal/task/sync_private_test.go
@@ -0,0 +1,46 @@
+package task
+
+import (
+ "context"
+ "strings"
+ "testing"
+ "time"
+
+ "golang.org/x/build/internal/workflow"
+)
+
+func TestSyncPrivate(t *testing.T) {
+ fakeRepo := NewFakeRepo(t, "fake")
+ masterCommit := fakeRepo.CommitOnBranch("master", map[string]string{
+ "hello": "there",
+ })
+ fakeRepo.Branch("public", masterCommit)
+ publicCommit := fakeRepo.CommitOnBranch("public", map[string]string{
+ "general": "kenobi",
+ })
+
+ sync := &PrivateMasterSyncTask{
+ PrivateGerritURL: fakeRepo.dir.dir, // kind of wild that this works
+ Ref: "public",
+ }
+
+ wd := sync.NewDefinition()
+ w, err := workflow.Start(wd, map[string]any{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
+ defer cancel()
+ _, err = w.Run(ctx, &verboseListener{t: t})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fakeRepo.runGit("switch", "master")
+ newMasterCommit := strings.TrimSpace(string(fakeRepo.runGit("rev-parse", "HEAD")))
+ // newMasterCommit := fakeRepo.ReadBranchHead(context.Background(), )
+
+ if newMasterCommit != publicCommit {
+ t.Fatalf("unexpected master commit: got %q, want %q", newMasterCommit, publicCommit)
+ }
+}