diff options
| -rw-r--r-- | git-codereview/doc.go | 7 | ||||
| -rw-r--r-- | git-codereview/pending.go | 111 | ||||
| -rw-r--r-- | git-codereview/pending_test.go | 39 | ||||
| -rw-r--r-- | git-codereview/review.go | 2 |
4 files changed, 155 insertions, 4 deletions
diff --git a/git-codereview/doc.go b/git-codereview/doc.go index 6e65e42..012e5ef 100644 --- a/git-codereview/doc.go +++ b/git-codereview/doc.go @@ -272,15 +272,20 @@ shows diffs between what is on the Gerrit server and the current directory. The pending command prints to standard output the status of all pending changes and staged, unstaged, and untracked files in the local repository. - git codereview pending [-c] [-l] [-s] + git codereview pending [-c] [-g] [-l] [-s] The -c flag causes the command to show pending changes only on the current branch. +The -g flag causes the command to print a different format in which +each Gerrit CL number is listed on a separate line. +May not be used with the -s flag. + The -l flag causes the command to use only locally available information. By default, it fetches recent commits and code review information from the Gerrit server. The -s flag causes the command to print abbreviated (short) output. +May not be used with the -g flag. Useful aliases include “git p” for “git pending” and “git pl” for “git pending -l” (notably faster but without Gerrit information). diff --git a/git-codereview/pending.go b/git-codereview/pending.go index c9b99e7..8a74e09 100644 --- a/git-codereview/pending.go +++ b/git-codereview/pending.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "slices" "sort" "strings" "time" @@ -18,6 +19,7 @@ var ( pendingLocal bool // -l flag, use only local operations (no network) pendingCurrentOnly bool // -c flag, show only current branch pendingShort bool // -s flag, short display + pendingGerrit bool // -g flag, Gerrit based short display ) // A pendingBranch collects information about a single pending branch. @@ -82,10 +84,16 @@ func cmdPending(args []string) { // NOTE: New flags should be added to the usage message below as well as doc.go. flags.BoolVar(&pendingCurrentOnly, "c", false, "show only current branch") flags.BoolVar(&pendingLocal, "l", false, "use only local information - no network operations") - flags.BoolVar(&pendingShort, "s", false, "show short listing") + flags.BoolVar(&pendingShort, "s", false, "show short listing (may not be used with -g)") + flags.BoolVar(&pendingGerrit, "g", false, "show a different Gerrit-based listing (may not be used with -s)") flags.Parse(args) if len(flags.Args()) > 0 { - fmt.Fprintf(stderr(), "Usage: %s pending %s [-c] [-l] [-s]\n", progName, globalFlags) + fmt.Fprintf(stderr(), "Usage: %s pending %s [-c] [-g] [-l] [-s]\n", progName, globalFlags) + exit(2) + } + + if pendingShort && pendingGerrit { + fmt.Fprintf(stderr(), "%s: using -g and -s together is not supported\n", progName) exit(2) } @@ -149,6 +157,16 @@ func cmdPending(args []string) { } <-doneFetch + if !pendingGerrit { + printPendingStandard(branches) + } else { + printPendingGerrit(branches) + } +} + +// printPendingStandard prints the default output format, +// as modified by pendingShort. +func printPendingStandard(branches []*pendingBranch) { // Print output. // If there are multiple changes in the current branch, the output splits them out into separate sections, // in reverse commit order, to match git log output. @@ -409,6 +427,85 @@ func codeReviewScores(g *GerritChange) string { return scores } +// printPendingGerrit prints the Gerrit-based format. +// This prints only CLs that have been fully sent to Gerrit, +// with their CL number and the topic line. +func printPendingGerrit(branches []*pendingBranch) { + type branchBuf struct { + name string + buf bytes.Buffer + updated time.Time + } + var branchBufs []*branchBuf + + for _, b := range branches { + if b.commitsAhead == 0 { + continue + } + + work := b.Pending() + + if len(work) == 0 { + continue + } + + var updatedStr string + for _, c := range work { + if c.g.Updated != "" { + updatedStr = c.g.Updated + break + } + if c.g.Created != "" { + updatedStr = c.g.Created + break + } + } + + var updated time.Time + if updatedStr != "" { + var err error + updated, err = time.Parse("2006-01-02 15:04:05.999999999", updatedStr) + if err != nil { + fmt.Fprintf(stderr(), "failed to parse gerrit timestamp %q: %v\n", updatedStr, err) + } + } + + bb := &branchBuf{ + name: b.Name, + updated: updated, + } + branchBufs = append(branchBufs, bb) + + if allSubmitted(work) { + fmt.Fprintf(&bb.buf, "- branch %s submitted\n", b.Name) + continue + } + if allAbandoned(work) { + fmt.Fprintf(&bb.buf, "- branch %s abandoned\n", b.Name) + continue + } + + fmt.Fprintf(&bb.buf, "- branch %s updated %s\n", b.Name, updated) + for _, c := range work { + if c.g.Number == 0 { + continue + } + fmt.Fprintf(&bb.buf, " https://go.dev/cl/%d %s\n", c.g.Number, c.g.Subject) + } + } + + slices.SortFunc(branchBufs, func(a, b *branchBuf) int { + if r := a.updated.Compare(b.updated); r != 0 { + return r + } + return strings.Compare(a.name, b.name) + }) + + for _, bb := range branchBufs { + stdout().Write(bb.buf.Bytes()) + } +} + // allMailed reports whether all commits in work have been posted to Gerrit. func allMailed(work []*Commit) bool { for _, c := range work { @@ -429,6 +526,16 @@ func allSubmitted(work []*Commit) bool { return true } +// allAbandoned reports whether all commits in work have been abandoned. +func allAbandoned(work []*Commit) bool { + for _, c := range work { + if c.g.Status != "ABANDONED" { + return false + } + } + return true +} + // suffix returns an empty string if n == 1, s otherwise. func suffix(n int, s string) string { if n == 1 { diff --git a/git-codereview/pending_test.go b/git-codereview/pending_test.go index 370f44f..bba3ec7 100644 --- a/git-codereview/pending_test.go +++ b/git-codereview/pending_test.go @@ -148,6 +148,11 @@ func TestPendingComplex(t *testing.T) { + REVHASH some changes `) + + testPendingArgs(t, []string{"-g"}, ` + - branch work updated 0001-01-01 00:00:00 +0000 UTC + - branch work2 updated 0001-01-01 00:00:00 +0000 UTC + `) } func TestPendingMultiChange(t *testing.T) { @@ -203,6 +208,10 @@ func TestPendingMultiChange(t *testing.T) { + REVHASH msg `) + + testPendingArgs(t, []string{"-g"}, ` + - branch work updated 0001-01-01 00:00:00 +0000 UTC + `) } func TestPendingGerrit(t *testing.T) { @@ -294,6 +303,10 @@ func TestPendingGerrit(t *testing.T) { + REVHASH msg `) + + testPendingArgs(t, []string{"-g"}, ` + - branch work submitted + `) } func TestPendingGerritMultiChange(t *testing.T) { @@ -370,6 +383,12 @@ func TestPendingGerritMultiChange(t *testing.T) { + REVHASH msg (CL 1234 -2 +1, mailed, submitted) `) + + testPendingArgs(t, []string{"-g"}, ` + - branch work updated 2025-02-06 00:00:00 +0000 UTC + https://go.dev/cl/1234 + https://go.dev/cl/1234 + `) } func TestPendingGerritMultiChange15(t *testing.T) { @@ -408,6 +427,25 @@ func TestPendingGerritMultiChange15(t *testing.T) { + REVHASH msg (CL 1234 -2 +1, mailed, submitted) `) + + testPendingArgs(t, []string{"-g"}, ` + - branch work updated 2025-02-06 00:00:00 +0000 UTC + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + https://go.dev/cl/1234 + `) } func testPendingReply(srv *gerritServer, id, rev, status string, unresolved int) { @@ -419,6 +457,7 @@ func testPendingReply(srv *gerritServer, id, rev, status string, unresolved int) "unresolved_comment_count":`+fmt.Sprint(unresolved)+`, "_number": 1234, "owner": {"_id": 42}, + "created": "2025-02-06 00:00:00.000000000", "labels": { "Code-Review": { "all": [ diff --git a/git-codereview/review.go b/git-codereview/review.go index fe5bf12..5660b8d 100644 --- a/git-codereview/review.go +++ b/git-codereview/review.go @@ -64,7 +64,7 @@ Available commands: help hooks mail [-r reviewer,...] [-cc mail,...] [options] [commit] - pending [-c] [-l] [-s] + pending [-c] [-g] [-l] [-s] rebase-work reword [commit...] submit [-i | commit...] |
