cmd/releasebot, cmd/release: use releasebot work dir for staging releases

Using a directory inside the system temporary directory for staging
releases can be problematic, because os.Rename may fail to move the
file if /tmp is mounted on a filesystem that is different from where
the releasebot work directory is.

Use $HOME/go-releasebot-work/goX.Y.Z/release-staging as the staging
directory instead.

Change-Id: I74f5f6ace1c0df154a1de989e825f67e808d3c34
Reviewed-on: https://go-review.googlesource.com/c/build/+/191159
Reviewed-by: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/cmd/release/release.go b/cmd/release/release.go
index ec39483..09e0c7f 100644
--- a/cmd/release/release.go
+++ b/cmd/release/release.go
@@ -38,6 +38,8 @@
 	target = flag.String("target", "", "If specified, build specific target platform (e.g. 'linux-amd64'). Default is to build all.")
 	watch  = flag.Bool("watch", false, "Watch the build. Only compatible with -target")
 
+	stagingDir = flag.String("staging_dir", "", "If specified, use this as the staging directory for untested release artifacts. Default is the system temporary directory.")
+
 	rev       = flag.String("rev", "", "Go revision to build, alternative to -tarball")
 	tarball   = flag.String("tarball", "", "Go tree tarball to build, alternative to -rev")
 	toolsRev  = flag.String("tools", "", "Tools revision to build")
@@ -504,17 +506,21 @@
 		Final    string // Final location where to move the file after the release has been tested.
 	}
 	var releases []releaseFile
-	tempFile := func(ext string) string {
-		tempDir, err := ioutil.TempDir("", "")
+	stagingDir := *stagingDir
+	if stagingDir == "" {
+		var err error
+		stagingDir, err = ioutil.TempDir("", "")
 		if err != nil {
 			log.Fatal(err)
 		}
-		return filepath.Join(tempDir, *version+"."+b.String()+ext+".untested")
+	}
+	stagingFile := func(ext string) string {
+		return filepath.Join(stagingDir, *version+"."+b.String()+ext+".untested")
 	}
 
 	switch b.OS {
 	case "darwin":
-		untested := tempFile(".pkg")
+		untested := stagingFile(".pkg")
 		if err := b.fetchFile(client, untested, "pkg"); err != nil {
 			return err
 		}
@@ -524,7 +530,7 @@
 		})
 		cleanFiles = append(cleanFiles, "pkg")
 	case "windows":
-		untested := tempFile(".msi")
+		untested := stagingFile(".msi")
 		if err := b.fetchFile(client, untested, "msi"); err != nil {
 			return err
 		}
@@ -553,7 +559,7 @@
 
 	switch b.OS {
 	default:
-		untested := tempFile(".tar.gz")
+		untested := stagingFile(".tar.gz")
 		if err := b.fetchTarball(client, untested); err != nil {
 			return fmt.Errorf("fetching and writing tarball: %v", err)
 		}
@@ -562,7 +568,7 @@
 			Final:    *version + "." + b.String() + ".tar.gz",
 		})
 	case "windows":
-		untested := tempFile(".zip")
+		untested := stagingFile(".zip")
 		if err := b.fetchZip(client, untested); err != nil {
 			return fmt.Errorf("fetching and writing zip: %v", err)
 		}
diff --git a/cmd/releasebot/main.go b/cmd/releasebot/main.go
index cc111e9..5794360 100644
--- a/cmd/releasebot/main.go
+++ b/cmd/releasebot/main.go
@@ -557,6 +557,9 @@
 	if err := os.MkdirAll(filepath.Join(w.Dir, "release", w.VersionCommit), 0777); err != nil {
 		w.log.Panic(err)
 	}
+	if err := os.MkdirAll(filepath.Join(w.Dir, "release-staging", w.VersionCommit), 0777); err != nil {
+		w.log.Panic(err)
+	}
 	w.ReleaseInfo = make(map[string]*ReleaseInfo)
 
 	if w.Security {
@@ -619,11 +622,15 @@
 
 // buildRelease builds the release packaging for a given target. Because the
 // "release" program can be flaky, it tries up to five times. The release files
-// are written to the current release directory
-// ($HOME/go-releasebot-work/go1.2.3/release/COMMIT_HASH). If files for the
-// current version commit are already present in that directory, they are reused
-// instead of being rebuilt. In release mode, buildRelease then uploads the
-// release packaging to the gs://golang-release-staging bucket, along with files
+// are first written to a release-staging directory
+// ($HOME/go-releasebot-work/go1.2.3/release-staging/COMMIT_HASH),
+// then after the all.bash tests complete successfully (or get skipped),
+// they get moved to the final release directory
+// ($HOME/go-releasebot-work/go1.2.3/release/COMMIT_HASH).
+//
+// If files for the current version commit are already present in the release directory,
+// they are reused instead of being rebuilt. In release mode, buildRelease then uploads
+// the release packaging to the gs://golang-release-staging bucket, along with files
 // containing the SHA256 hash of the releases, for eventual use by the download page.
 func (w *Work) buildRelease(target string) {
 	log.Printf("BUILDRELEASE %s %s\n", w.Version, target)
@@ -663,7 +670,8 @@
 		for {
 			releaseBranch := strings.TrimSuffix(w.ReleaseBranch, "-security")
 			args := []string{w.ReleaseBinary, "-target", target, "-user", gomoteUser,
-				"-version", w.Version, "-tools", releaseBranch, "-net", releaseBranch}
+				"-version", w.Version, "-tools", releaseBranch, "-net", releaseBranch,
+				"-staging_dir", filepath.Join(w.Dir, "release-staging", w.VersionCommit)}
 			if w.Security {
 				args = append(args, "-tarball", filepath.Join(w.Dir, w.VersionCommit+".tar.gz"))
 			} else {