cmd/releasebot: remove runDir and extraEnv object state
Change-Id: I361a42676926aaf92314a2681f519bbf21a1d612
Reviewed-on: https://go-review.googlesource.com/119536
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/cmd/releasebot/git.go b/cmd/releasebot/git.go
index 59e92b0..e2474fd 100644
--- a/cmd/releasebot/git.go
+++ b/cmd/releasebot/git.go
@@ -18,8 +18,6 @@
// gitCheckout also creates a clean checkout in
// $HOME/go-releasebot-work/<release>/gitmirror,
// to use as an object cache to speed future checkouts.
-// On return, w.runDir has been set to gitwork/src,
-// to allow commands like "./make.bash".
func (w *Work) gitCheckout() {
shortRel := strings.ToLower(w.Milestone.Title)
shortRel = shortRel[:strings.LastIndex(shortRel, ".")]
@@ -33,28 +31,26 @@
// Check out a local mirror to work-mirror, to speed future checkouts for this point release.
mirror := filepath.Join(w.Dir, "gitmirror")
+ r := w.runner(mirror)
if _, err := os.Stat(mirror); err != nil {
- w.run("git", "clone", "https://go.googlesource.com/go", mirror)
- w.runDir = mirror
- w.run("git", "config", "gc.auto", "0") // don't throw away refs we fetch
+ w.runner(w.Dir).run("git", "clone", "https://go.googlesource.com/go", mirror)
+ r.run("git", "config", "gc.auto", "0") // don't throw away refs we fetch
} else {
- w.runDir = mirror
- w.run("git", "fetch", "origin", "master")
+ r.run("git", "fetch", "origin", "master")
}
- w.run("git", "fetch", "origin", w.ReleaseBranch)
+ r.run("git", "fetch", "origin", w.ReleaseBranch)
// Clone real Gerrit, but using local mirror for most objects.
gitDir := filepath.Join(w.Dir, "gitwork")
if err := os.RemoveAll(gitDir); err != nil {
w.log.Panic(err)
}
- w.run("git", "clone", "--reference", mirror, "-b", w.ReleaseBranch, "https://go.googlesource.com/go", gitDir)
- w.runDir = gitDir
- w.run("git", "codereview", "change", "relwork")
- w.run("git", "config", "gc.auto", "0") // don't throw away refs we fetch
- w.runDir = filepath.Join(gitDir, "src")
+ w.runner(w.Dir).run("git", "clone", "--reference", mirror, "-b", w.ReleaseBranch, "https://go.googlesource.com/go", gitDir)
+ r = w.runner(gitDir)
+ r.run("git", "codereview", "change", "relwork")
+ r.run("git", "config", "gc.auto", "0") // don't throw away refs we fetch
- _, err := w.runErr("git", "rev-parse", w.Version)
+ _, err := r.runErr("git", "rev-parse", w.Version)
if err == nil {
w.logError("%s tag already exists in Go repository!", w.Version)
w.log.Panic("already released")
@@ -63,10 +59,10 @@
// gitTagVersion tags the release candidate or release in Git.
func (w *Work) gitTagVersion() {
- w.runDir = filepath.Join(w.Dir, "gitwork")
- out := w.runOut("git", "rev-parse", "HEAD")
+ r := w.runner(filepath.Join(w.Dir, "gitwork"))
+ out := r.runOut("git", "rev-parse", "HEAD")
w.VersionCommit = strings.TrimSpace(string(out))
- out = w.runOut("git", "show", w.VersionCommit)
+ out = r.runOut("git", "show", w.VersionCommit)
fmt.Printf("About to tag the following commit as %s:\n\n%s\n\nOk? (y/n) ", w.Version, out)
if dryRun {
return
@@ -79,10 +75,10 @@
if response != "y" {
w.log.Panic("stopped")
}
- out, err = w.runErr("git", "tag", w.Version, w.VersionCommit)
+ out, err = r.runErr("git", "tag", w.Version, w.VersionCommit)
if err != nil {
w.logError("git tag failed: %s\n%s", err, out)
return
}
- w.run("git", "push", "origin", w.Version)
+ r.run("git", "push", "origin", w.Version)
}
diff --git a/cmd/releasebot/main.go b/cmd/releasebot/main.go
index dd13ea6..df08340 100644
--- a/cmd/releasebot/main.go
+++ b/cmd/releasebot/main.go
@@ -171,10 +171,8 @@
// is managing multiple releases, although the current releasebot command line
// only accepts a single release.
type Work struct {
- logBuf *bytes.Buffer
- log *log.Logger
- runDir string
- extraEnv []string
+ logBuf *bytes.Buffer
+ log *log.Logger
Prepare bool // create the release commit and submit it for review
@@ -182,7 +180,7 @@
NextMilestone *maintner.GitHubMilestone // Next minor milestone
ReleaseIssue int // Release status issue number
ReleaseBranch string
- Dir string // work directory
+ Dir string // work directory ($HOME/go-releasebot-work/<release>)
Errors []string
ReleaseBinary string
Version string
@@ -224,14 +222,28 @@
w.postSummary()
}
+type runner struct {
+ w *Work
+ dir string
+ extraEnv []string
+}
+
+func (w *Work) runner(dir string, env ...string) *runner {
+ return &runner{
+ w: w,
+ dir: dir,
+ extraEnv: env,
+ }
+}
+
// run runs the command and requires that it succeeds.
// If not, it logs the failure and aborts the work.
// It logs the command line.
-func (w *Work) run(args ...string) {
- out, err := w.runErr(args...)
+func (r *runner) run(args ...string) {
+ out, err := r.runErr(args...)
if err != nil {
- w.log.Printf("command failed: %s\n%s", err, out)
- panic("cmd")
+ r.w.log.Printf("command failed: %s\n%s", err, out)
+ panic("command failed")
}
}
@@ -240,47 +252,28 @@
// It does not log the command line except in case of failure.
// Not logging these commands avoids filling the log with
// runs of side-effect-free commands like "git cat-file commit HEAD".
-func (w *Work) runOut(args ...string) []byte {
+func (r *runner) runOut(args ...string) []byte {
cmd := exec.Command(args[0], args[1:]...)
- // Make Git editor a no-op so that git codereview submit -i does not pop up
- // an editor.
- cmd.Env = []string{"EDITOR=true"}
- cmd.Dir = w.runDir
+ cmd.Dir = r.dir
out, err := cmd.CombinedOutput()
if err != nil {
- w.log.Printf("$ %s\n", strings.Join(args, " "))
- w.log.Printf("command failed: %s\n%s", err, out)
- panic("cmd")
+ r.w.log.Printf("$ %s\n", strings.Join(args, " "))
+ r.w.log.Printf("command failed: %s\n%s", err, out)
+ panic("command failed")
}
return out
}
// runErr runs the given command and returns the output and status (error).
// It logs the command line.
-// It retries certain known-flaky commands automatically.
-func (w *Work) runErr(args ...string) ([]byte, error) {
- maxTry := 1
- try := 0
- // Gerrit sometimes returns 502 errors from git fetch
- if len(args) >= 2 && args[0] == "git" && args[1] == "fetch" {
- maxTry = 3
- }
-Again:
- try++
- w.log.Printf("$ %s\n", strings.Join(args, " "))
+func (r *runner) runErr(args ...string) ([]byte, error) {
+ r.w.log.Printf("$ %s\n", strings.Join(args, " "))
cmd := exec.Command(args[0], args[1:]...)
- // Make Git editor a no-op so that git codereview submit -i does not pop up
- // an editor.
- cmd.Env = append(os.Environ(), "EDITOR=true")
- cmd.Dir = w.runDir
- if len(w.extraEnv) > 0 {
- cmd.Env = append(cmd.Env, w.extraEnv...)
+ cmd.Dir = r.dir
+ if len(r.extraEnv) > 0 {
+ cmd.Env = append(os.Environ(), r.extraEnv...)
}
- out, err := cmd.CombinedOutput()
- if err != nil && try < maxTry {
- goto Again
- }
- return out, err
+ return cmd.CombinedOutput()
}
func (w *Work) doRelease() {
@@ -428,7 +421,7 @@
func (w *Work) checkDocs() {
// Check that we've documented the release.
version := strings.ToLower(w.Milestone.Title)
- data, err := ioutil.ReadFile(filepath.Join(w.runDir, "../doc/devel/release.html"))
+ data, err := ioutil.ReadFile(filepath.Join(w.Dir, "gitwork", "doc/devel/release.html"))
if err != nil {
w.log.Panic(err)
}
@@ -442,7 +435,7 @@
version := strings.ToLower(w.Milestone.Title)
- err := ioutil.WriteFile(filepath.Join(w.runDir, "../VERSION"), []byte(version), 0666)
+ err := ioutil.WriteFile(filepath.Join(w.Dir, "gitwork", "VERSION"), []byte(version), 0666)
if err != nil {
w.log.Panic(err)
}
@@ -450,18 +443,19 @@
desc := version + "\n\n"
desc += "Change-Id: " + changeID + "\n"
- w.run("git", "commit", "-m", desc, "../VERSION")
+ r := w.runner(filepath.Join(w.Dir, "gitwork"))
+ r.run("git", "commit", "-m", desc, "VERSION")
if dryRun {
- fmt.Printf("\n### VERSION commit\n\n%s\n", w.runOut("git", "show", "HEAD"))
+ fmt.Printf("\n### VERSION commit\n\n%s\n", r.runOut("git", "show", "HEAD"))
} else {
- w.run("git", "codereview", "mail", "-trybot", "HEAD")
+ r.run("git", "codereview", "mail", "-trybot", "HEAD")
}
return
}
// checkVersion makes sure that the version commit has been submitted.
func (w *Work) checkVersion() {
- ver, err := ioutil.ReadFile(filepath.Join(w.runDir, "../VERSION"))
+ ver, err := ioutil.ReadFile(filepath.Join(w.Dir, "gitwork", "VERSION"))
if err != nil {
w.log.Panic(err)
}
@@ -478,8 +472,8 @@
if err := os.MkdirAll(gopath, 0777); err != nil {
w.log.Panic(err)
}
- w.extraEnv = append(w.extraEnv, "GOPATH="+gopath, "GOBIN="+filepath.Join(gopath, "bin"))
- w.run("go", "get", "golang.org/x/build/cmd/release")
+ r := w.runner(w.Dir, "GOPATH="+gopath, "GOBIN="+filepath.Join(gopath, "bin"))
+ r.run("go", "get", "golang.org/x/build/cmd/release")
w.ReleaseBinary = filepath.Join(gopath, "bin/release")
}
@@ -488,7 +482,6 @@
if err := os.MkdirAll(filepath.Join(w.Dir, "release"), 0777); err != nil {
w.log.Panic(err)
}
- w.runDir = filepath.Join(w.Dir, "release")
w.ReleaseInfo = make(map[string]*ReleaseInfo)
var wg sync.WaitGroup
@@ -564,7 +557,7 @@
Suffix: strings.TrimPrefix(file, prefix),
}
outs = append(outs, out)
- _, err := os.Stat(filepath.Join(w.runDir, file))
+ _, err := os.Stat(filepath.Join(w.Dir, "release", file))
if err != nil {
haveFiles = false
}
@@ -576,14 +569,17 @@
if haveFiles {
w.log.Printf("release %s: already have %v; not rebuilding files", target, files)
} else {
- for failures := 0; ; {
- out, err := w.runErr(w.ReleaseBinary, "-target", target, "-user", gomoteUser, "-version", w.Version, "-rev", w.VersionCommit, "-tools", w.ReleaseBranch, "-net", w.ReleaseBranch)
+ failures := 0
+ for {
+ out, err := w.runner(filepath.Join(w.Dir, "release"), "GOPATH="+filepath.Join(w.Dir, "gopath")).runErr(
+ w.ReleaseBinary, "-target", target, "-user", gomoteUser, "-version", w.Version, "-rev", w.VersionCommit,
+ "-tools", w.ReleaseBranch, "-net", w.ReleaseBranch)
// Exit code from release binary is apparently unreliable.
// Look to see if the files we expected were created instead.
failed := false
w.releaseMu.Lock()
for _, out := range outs {
- if _, err := os.Stat(filepath.Join(w.runDir, out.File)); err != nil {
+ if _, err := os.Stat(filepath.Join(w.Dir, "release", out.File)); err != nil {
failed = true
}
}
@@ -630,7 +626,7 @@
return errors.New("attempted write operation in dry-run mode")
}
- src := filepath.Join(w.runDir, out.File)
+ src := filepath.Join(w.Dir, "release", out.File)
h := sha256.New()
f, err := os.Open(src)
if err != nil {