cmd/relui: allow picking which of the private go projects to build from

Rather than hardcoding using golang/go-private, allow picking from that
and the "go" project on the go-internal host. This paves the way for
migrating to the new repository without needing to rollback in case of
an issue. Once we are fully migrated we'll likely go back to hardcoding
the project.

Change-Id: I380d3934279f7217964bfa5656cba642da11d66e
Reviewed-on: https://go-review.googlesource.com/c/build/+/569457
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/cmd/relui/main.go b/cmd/relui/main.go
index c05c023..c368ea4 100644
--- a/cmd/relui/main.go
+++ b/cmd/relui/main.go
@@ -220,13 +220,12 @@
 	signServer := sign.NewServer()
 	protos.RegisterReleaseServiceServer(grpcServer, signServer)
 	buildTasks := &relui.BuildReleaseTasks{
-		GerritClient:         gerritClient,
-		GerritProject:        "go",
-		GerritHTTPClient:     oauth2.NewClient(ctx, creds.TokenSource),
-		PrivateGerritClient:  privateGerritClient,
-		PrivateGerritProject: "golang/go-private",
-		SignService:          signServer,
-		GCSClient:            gcsClient,
+		GerritClient:        gerritClient,
+		GerritProject:       "go",
+		GerritHTTPClient:    oauth2.NewClient(ctx, creds.TokenSource),
+		PrivateGerritClient: privateGerritClient,
+		SignService:         signServer,
+		GCSClient:           gcsClient,
 		ScratchFS: &task.ScratchFS{
 			BaseURL: *scratchFilesBase,
 			GCS:     gcsClient,
diff --git a/internal/relui/buildrelease_test.go b/internal/relui/buildrelease_test.go
index ac54e5b..6b4bfb3 100644
--- a/internal/relui/buildrelease_test.go
+++ b/internal/relui/buildrelease_test.go
@@ -218,6 +218,7 @@
 			"js-wasm",        // Builder used on 1.20 and older.
 		},
 		"Ref from the private repository to build from (optional)": "",
+		"Security repository to retrieve ref from (optional)":      "",
 	})
 	if err != nil {
 		t.Fatal(err)
@@ -368,15 +369,15 @@
 
 	// Set up the fake merge process. Once we stop to ask for approval, commit
 	// the fix to the public server.
-	privateRepo := task.NewFakeRepo(t, "go-private")
+	privateRepo := task.NewFakeRepo(t, "go")
 	privateRepo.Commit(goFiles)
 	securityFix := map[string]string{"security.txt": "This file makes us secure"}
+	privateRepoName := "go-internal/go (new)"
 	privateRef := privateRepo.Commit(securityFix)
 	privateGerrit := task.NewFakeGerrit(t, privateRepo)
 	deps.buildBucket.GerritURL = privateGerrit.GerritURL()
-	deps.buildBucket.Projects = []string{"go-private"}
+	deps.buildBucket.Projects = []string{"go"}
 	deps.buildTasks.PrivateGerritClient = privateGerrit
-	deps.buildTasks.PrivateGerritProject = "go-private"
 
 	defaultApprove := deps.buildTasks.ApproveAction
 	deps.buildTasks.ApproveAction = func(tc *workflow.TaskContext) error {
@@ -394,6 +395,7 @@
 	w, err := workflow.Start(wd, map[string]interface{}{
 		"Targets to skip testing (or 'all') (optional)":            []string{"js-wasm"},
 		"Ref from the private repository to build from (optional)": privateRef,
+		"Security repository to retrieve ref from (optional)":      privateRepoName,
 	})
 	if err != nil {
 		t.Fatal(err)
@@ -438,6 +440,7 @@
 	w, err := workflow.Start(wd, map[string]interface{}{
 		"Targets to skip testing (or 'all') (optional)":            []string(nil),
 		"Ref from the private repository to build from (optional)": "",
+		"Security repository to retrieve ref from (optional)":      "",
 	})
 	if err != nil {
 		t.Fatal(err)
diff --git a/internal/relui/workflows.go b/internal/relui/workflows.go
index 85f49a4..2d1ce31 100644
--- a/internal/relui/workflows.go
+++ b/internal/relui/workflows.go
@@ -389,7 +389,7 @@
 	versionFile := wf.Task2(wd, "Generate VERSION file", version.GenerateVersionFile, nextVersion, timestamp)
 	wf.Output(wd, "VERSION file", versionFile)
 	head := wf.Task1(wd, "Read branch head", version.ReadBranchHead, branchVal)
-	srcSpec := wf.Task4(wd, "Select source spec", build.getGitSource, branchVal, head, wf.Const(""), versionFile)
+	srcSpec := wf.Task5(wd, "Select source spec", build.getGitSource, branchVal, head, wf.Const(""), wf.Const(""), versionFile)
 	source, artifacts, mods := build.addBuildTasks(wd, major, kind, nextVersion, timestamp, srcSpec)
 	wf.Output(wd, "Source", source)
 	wf.Output(wd, "Artifacts", artifacts)
@@ -434,6 +434,11 @@
 	return time.Now().UTC().Round(time.Second), nil
 }
 
+var securityProjectNameToProject = map[string]string{
+	"go-internal/go (new)":                "go",
+	"go-internal/golang/go-private (old)": "golang/go-private",
+}
+
 func addSingleReleaseWorkflow(
 	build *BuildReleaseTasks, milestone *task.MilestoneTasks, version *task.VersionTasks,
 	wd *wf.Definition, major int, kind task.ReleaseKind, coordinators wf.Value[[]string],
@@ -454,9 +459,23 @@
 	milestones := wf.Task2(wd, "Pick milestones", milestone.FetchMilestones, nextVersion, kindVal)
 	checked := wf.Action3(wd, "Check blocking issues", milestone.CheckBlockers, milestones, nextVersion, kindVal)
 
+	securityProjectName := wf.Param(wd, wf.ParamDef[string]{
+		Name: "Security repository to retrieve ref from (optional)",
+		ParamType: workflow.ParamType[string]{
+			HTMLElement: "select",
+			HTMLSelectOptions: []string{
+				"go-internal/go (new)",
+				"go-internal/golang/go-private (old)",
+			},
+		},
+		Doc: `"go-internal/golang/go-private" is the old internal gerrit repository, "go-internal/go" is the new repository.`,
+	})
+	securityProject := wf.Task1(wd, "Convert security project name", func(ctx *wf.TaskContext, projectName string) (string, error) {
+		return securityProjectNameToProject[projectName], nil
+	}, securityProjectName)
 	securityRef := wf.Param(wd, wf.ParamDef[string]{Name: "Ref from the private repository to build from (optional)"})
-	securityCommit := wf.Task1(wd, "Read security ref", build.readSecurityRef, securityRef)
-	srcSpec := wf.Task4(wd, "Select source spec", build.getGitSource, branchVal, startingHead, securityCommit, versionFile, wf.After(checked))
+	securityCommit := wf.Task2(wd, "Read security ref", build.readSecurityRef, securityProject, securityRef)
+	srcSpec := wf.Task5(wd, "Select source spec", build.getGitSource, branchVal, startingHead, securityProject, securityCommit, versionFile, wf.After(checked))
 
 	// Build, test, and sign release.
 	source, signedAndTestedArtifacts, modules := build.addBuildTasks(wd, major, kind, nextVersion, timestamp, srcSpec)
@@ -610,7 +629,6 @@
 	GerritProject            string
 	GerritHTTPClient         *http.Client // GerritHTTPClient is an HTTP client that authenticates to Gerrit instances. (Both public and private.)
 	PrivateGerritClient      task.GerritClient
-	PrivateGerritProject     string
 	GCSClient                *storage.Client
 	ScratchFS                *task.ScratchFS
 	SignedURL                string // SignedURL is a gs:// or file:// URL, no trailing slash.
@@ -629,24 +647,24 @@
 
 var commitRE = regexp.MustCompile(`[a-f0-9]{40}`)
 
-func (b *BuildReleaseTasks) readSecurityRef(ctx *wf.TaskContext, ref string) (string, error) {
+func (b *BuildReleaseTasks) readSecurityRef(ctx *wf.TaskContext, project, ref string) (string, error) {
 	if ref == "" {
 		return "", nil
 	}
 	if commitRE.MatchString(ref) {
 		return ref, nil
 	}
-	commit, err := b.PrivateGerritClient.ReadBranchHead(ctx, b.PrivateGerritProject, ref)
+	commit, err := b.PrivateGerritClient.ReadBranchHead(ctx, project, ref)
 	if err != nil {
 		return "", fmt.Errorf("%q doesn't appear to be a commit hash, but resolving it as a branch failed: %v", ref, err)
 	}
 	return commit, nil
 }
 
-func (b *BuildReleaseTasks) getGitSource(ctx *wf.TaskContext, branch, commit, securityCommit, versionFile string) (sourceSpec, error) {
+func (b *BuildReleaseTasks) getGitSource(ctx *wf.TaskContext, branch, commit, securityProject, securityCommit, versionFile string) (sourceSpec, error) {
 	client, project, rev := b.GerritClient, b.GerritProject, commit
 	if securityCommit != "" {
-		client, project, rev = b.PrivateGerritClient, b.PrivateGerritProject, securityCommit
+		client, project, rev = b.PrivateGerritClient, securityProject, securityCommit
 	}
 	return sourceSpec{
 		GitilesURL:  client.GitilesURL(),
@@ -718,7 +736,7 @@
 	if err != nil {
 		return "", err
 	}
-	spec, err := b.getGitSource(ctx, branch, head, "", versionFile)
+	spec, err := b.getGitSource(ctx, branch, head, "", "", versionFile)
 	if err != nil {
 		return "", err
 	}