git-codereview: allow multiple commit hashes for submit
This adds support to the submit subcommand for passing and submitting
multiple commit hashes.
Change-Id: Id030b07cac21d11acbeb8015fde9cb9e1acb1479
Reviewed-on: https://go-review.googlesource.com/16674
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/git-codereview/review.go b/git-codereview/review.go
index 8ebb8d9..1898463 100644
--- a/git-codereview/review.go
+++ b/git-codereview/review.go
@@ -95,7 +95,7 @@
If -l is specified, only use locally available information.
If -s is specified, show short output.
- submit
+ submit [commit-hash...]
Push the pending change to the Gerrit server and tell Gerrit to
submit it to the master branch.
diff --git a/git-codereview/submit.go b/git-codereview/submit.go
index df43148..209f14b 100644
--- a/git-codereview/submit.go
+++ b/git-codereview/submit.go
@@ -14,20 +14,18 @@
func cmdSubmit(args []string) {
flags.Usage = func() {
- fmt.Fprintf(stderr(), "Usage: %s submit %s [commit-hash]\n", os.Args[0], globalFlags)
+ fmt.Fprintf(stderr(), "Usage: %s submit %s [commit-hash...]\n", os.Args[0], globalFlags)
}
flags.Parse(args)
- if n := len(flags.Args()); n > 1 {
- flags.Usage()
- os.Exit(2)
- }
b := CurrentBranch()
- var c *Commit
- if len(flags.Args()) == 1 {
- c = b.CommitByHash("submit", flags.Arg(0))
+ var cs []*Commit
+ if args := flags.Args(); len(args) >= 1 {
+ for _, arg := range args {
+ cs = append(cs, b.CommitByHash("submit", arg))
+ }
} else {
- c = b.DefaultCommit("submit")
+ cs = append(cs, b.DefaultCommit("submit"))
}
// No staged changes.
@@ -37,13 +35,17 @@
checkStaged("submit")
checkUnstaged("submit")
- // Submit the change.
- g := submit(b, c)
+ // Submit the changes.
+ var g *GerritChange
+ for _, c := range cs {
+ printf("submitting %s %s", c.ShortHash, c.Subject)
+ g = submit(b, c)
+ }
// Sync client to revision that Gerrit committed, but only if we can do it cleanly.
// Otherwise require user to run 'git sync' themselves (if they care).
run("git", "fetch", "-q")
- if len(b.Pending()) == 1 {
+ if len(cs) == 1 && len(b.Pending()) == 1 {
if err := runErr("git", "checkout", "-q", "-B", b.Name, g.CurrentRevision, "--"); err != nil {
dief("submit succeeded, but cannot sync local branch\n"+
"\trun 'git sync' to sync, or\n"+
@@ -119,7 +121,8 @@
}
if *noRun {
- dief("stopped before submit")
+ printf("stopped before submit")
+ return g
}
// Otherwise, try the submit. Sends back updated GerritChange,
diff --git a/git-codereview/submit_test.go b/git-codereview/submit_test.go
index 8e91e42..ead9157 100644
--- a/git-codereview/submit_test.go
+++ b/git-codereview/submit_test.go
@@ -163,3 +163,60 @@
"git fetch -q",
"git checkout -q -B work "+serverHead+" --")
}
+
+func TestSubmitMultiple(t *testing.T) {
+ gt := newGitTest(t)
+ defer gt.done()
+
+ srv := newGerritServer(t)
+ defer srv.done()
+
+ write(t, gt.client+"/file1", "")
+ trun(t, gt.client, "git", "add", "file1")
+ trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I0000001\n")
+ hash1 := strings.TrimSpace(trun(t, gt.client, "git", "log", "-n", "1", "--format=format:%H"))
+
+ write(t, gt.client+"/file2", "")
+ trun(t, gt.client, "git", "add", "file2")
+ trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I0000002\n")
+ hash2 := strings.TrimSpace(trun(t, gt.client, "git", "log", "-n", "1", "--format=format:%H"))
+
+ testMainDied(t, "submit")
+ testPrintedStderr(t, "cannot submit: multiple changes pending")
+
+ cl1 := GerritChange{
+ Status: "NEW",
+ Mergeable: true,
+ CurrentRevision: hash1,
+ Labels: map[string]*GerritLabel{"Code-Review": &GerritLabel{Approved: new(GerritAccount)}},
+ }
+ cl2 := GerritChange{
+ Status: "NEW",
+ Mergeable: false,
+ CurrentRevision: hash2,
+ Labels: map[string]*GerritLabel{"Code-Review": &GerritLabel{Approved: new(GerritAccount)}},
+ }
+
+ srv.setReply("/a/changes/proj~master~I0000001", gerritReply{f: func() gerritReply {
+ return gerritReply{json: cl1}
+ }})
+ srv.setReply("/a/changes/proj~master~I0000001/submit", gerritReply{f: func() gerritReply {
+ if cl1.Status != "NEW" {
+ return gerritReply{status: 409}
+ }
+ cl1.Status = "MERGED"
+ cl2.Mergeable = true
+ return gerritReply{json: cl1}
+ }})
+ srv.setReply("/a/changes/proj~master~I0000002", gerritReply{f: func() gerritReply {
+ return gerritReply{json: cl2}
+ }})
+ srv.setReply("/a/changes/proj~master~I0000002/submit", gerritReply{f: func() gerritReply {
+ if cl2.Status != "NEW" || !cl2.Mergeable {
+ return gerritReply{status: 409}
+ }
+ cl2.Status = "MERGED"
+ return gerritReply{json: cl2}
+ }})
+ testMain(t, "submit", hash1, hash2)
+}
diff --git a/git-codereview/util_test.go b/git-codereview/util_test.go
index 400beb4..b010f08 100644
--- a/git-codereview/util_test.go
+++ b/git-codereview/util_test.go
@@ -6,6 +6,7 @@
import (
"bytes"
+ "encoding/json"
"fmt"
"io/ioutil"
"net"
@@ -386,6 +387,7 @@
type gerritReply struct {
status int
body string
+ json interface{}
f func() gerritReply
}
@@ -413,6 +415,13 @@
if reply.status != 0 {
w.WriteHeader(reply.status)
}
+ if reply.json != nil {
+ body, err := json.Marshal(reply.json)
+ if err != nil {
+ dief("%v", err)
+ }
+ reply.body = ")]}'\n" + string(body)
+ }
if len(reply.body) > 0 {
w.Write([]byte(reply.body))
}