Commit 00817b309d
00817b309d2ade4a926e1a2fe2942eefcf3e5f61
parent: fd7099acea
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-24 01:28 UTC
control: issue, mr, build, release, label, milestone, search and explore lists as tables
Ref #254
internal/control/build.go
+12 −6
| @@ -159,9 +159,11 @@ func runBuildList(c *Ctx, args []string) int { |
| 159 | 159 | ds[i].Subject = subjects[ds[i].SHA] |
| 160 | 160 | } |
| 161 | 161 | return c.emitPage(p, ds, next, func(w io.Writer) { |
| 162 | tb := c.table(w, "#", "JOB", "STATUS", "SHA", "REF", "TITLE") |
| 162 | 163 | for _, d := range ds { |
| 163 | | fmt.Fprintf(w, "%d\t%s\t%s\t%.10s\t%s\t%s\n", d.Number, d.Job, d.Status, d.SHA, d.Ref, d.Subject) |
| 164 | tb.row(cRef(fmt.Sprintf("%d", d.Number)), cText(d.Job), cState(d.Status), cRef(fmt.Sprintf("%.10s", d.SHA)), cText(d.Ref), cFlex(d.Subject)) |
| 164 | 165 | } |
| 166 | tb.flush() |
| 165 | 167 | }) |
| 166 | 168 | } |
| 167 | 169 | |
| @@ -259,16 +261,18 @@ func runBuildJobs(c *Ctx, args []string) int { |
| 259 | 261 | out = append(out, JobOut{Name: j.Name, Schedule: j.Schedule, Tags: j.Tags}) |
| 260 | 262 | } |
| 261 | 263 | return c.emit(out, func(w io.Writer) { |
| 264 | tb := c.table(w, "NAME", "WHEN") |
| 262 | 265 | for _, j := range out { |
| 266 | when := "on push" |
| 263 | 267 | switch { |
| 264 | 268 | case j.Schedule != "": |
| 265 | | fmt.Fprintf(w, "%s\tschedule %s\n", j.Name, j.Schedule) |
| 269 | when = "schedule " + j.Schedule |
| 266 | 270 | case j.Tags != "": |
| 267 | | fmt.Fprintf(w, "%s\ttags %s\n", j.Name, j.Tags) |
| 268 | | default: |
| 269 | | fmt.Fprintf(w, "%s\ton push\n", j.Name) |
| 271 | when = "tags " + j.Tags |
| 270 | 272 | } |
| 273 | tb.row(cRef(j.Name), cText(when)) |
| 271 | 274 | } |
| 275 | tb.flush() |
| 272 | 276 | }) |
| 273 | 277 | } |
| 274 | 278 | |
| @@ -365,9 +369,11 @@ func runSecretList(c *Ctx, args []string) int { |
| 365 | 369 | return c.fail(protocol.ExitFailure, "%v", err) |
| 366 | 370 | } |
| 367 | 371 | return c.emit(names, func(w io.Writer) { |
| 372 | tb := c.table(w, "NAME") |
| 368 | 373 | for _, n := range names { |
| 369 | | fmt.Fprintln(w, n) |
| 374 | tb.row(cRef(n)) |
| 370 | 375 | } |
| 376 | tb.flush() |
| 371 | 377 | }) |
| 372 | 378 | } |
| 373 | 379 | |
internal/control/explore.go
+3 −2
| @@ -1,7 +1,6 @@ |
| 1 | 1 | package control |
| 2 | 2 | |
| 3 | 3 | import ( |
| 4 | | "fmt" |
| 5 | 4 | "io" |
| 6 | 5 | "strings" |
| 7 | 6 | |
| @@ -75,9 +74,11 @@ func runExplore(c *Ctx, args []string) int { |
| 75 | 74 | } |
| 76 | 75 | ds, next := trimPage(p, ds, "explore", func(o out) string { return o.Path }) |
| 77 | 76 | return c.emitPage(p, ds, next, func(w io.Writer) { |
| 77 | tb := c.table(w, "PATH", "DESCRIPTION") |
| 78 | 78 | for _, d := range ds { |
| 79 | | fmt.Fprintf(w, "%s\t%s\n", d.Path, d.Description) |
| 79 | tb.row(cRef(d.Path), cFlex(d.Description)) |
| 80 | 80 | } |
| 81 | tb.flush() |
| 81 | 82 | }) |
| 82 | 83 | } |
| 83 | 84 | |
internal/control/issue.go
+3 −1
| @@ -204,9 +204,11 @@ func runIssueList(c *Ctx, args []string) int { |
| 204 | 204 | ds = append(ds, issueToOut(i, false)) |
| 205 | 205 | } |
| 206 | 206 | return c.emitPage(p, ds, next, func(w io.Writer) { |
| 207 | tb := c.table(w, "#", "STATE", "TITLE", "AUTHOR") |
| 207 | 208 | for _, d := range ds { |
| 208 | | fmt.Fprintf(w, "#%d\t%s\t%s\t%s\n", d.Number, d.State, d.Title, d.Author) |
| 209 | tb.row(cRef(fmt.Sprintf("#%d", d.Number)), cState(d.State), cFlex(d.Title), cText(d.Author)) |
| 209 | 210 | } |
| 211 | tb.flush() |
| 210 | 212 | }) |
| 211 | 213 | } |
| 212 | 214 | |
internal/control/label.go
+7 −1
| @@ -46,9 +46,15 @@ func runLabelList(c *Ctx, args []string) int { |
| 46 | 46 | return c.fail(protocol.ExitFailure, "%v", err) |
| 47 | 47 | } |
| 48 | 48 | return c.emit(labels, func(w io.Writer) { |
| 49 | tb := c.table(w, "NAME", "COLOR", "ISSUES", "MRS") |
| 49 | 50 | for _, l := range labels { |
| 50 | | fmt.Fprintf(w, "%s\t%s\t%d\t%d%s\n", l.Name, l.Color, l.Issues, l.MRs, map[bool]string{true: "\torg"}[l.Org]) |
| 51 | cells := []cell{cRef(l.Name), cText(l.Color), cNum(l.Issues), cNum(l.MRs)} |
| 52 | if l.Org { |
| 53 | cells = append(cells, cText("org")) |
| 54 | } |
| 55 | tb.row(cells...) |
| 51 | 56 | } |
| 57 | tb.flush() |
| 52 | 58 | }) |
| 53 | 59 | } |
| 54 | 60 | |
internal/control/milestone.go
+8 −4
| @@ -114,17 +114,19 @@ func emitMilestones(c *Ctx, ms []store.Milestone) int { |
| 114 | 114 | ds = append(ds, out{m.Title, m.Description, m.DueDate, m.State, m.OrgID != 0, m.OpenItems, m.ClosedItems}) |
| 115 | 115 | } |
| 116 | 116 | return c.emit(ds, func(w io.Writer) { |
| 117 | tb := c.table(w, "TITLE", "STATE", "DUE", "PROGRESS") |
| 117 | 118 | for _, d := range ds { |
| 118 | 119 | due := d.Due |
| 119 | 120 | if due == "" { |
| 120 | 121 | due = "-" |
| 121 | 122 | } |
| 122 | | mark := "" |
| 123 | cells := []cell{cRef(d.Title), cState(d.State), cText("due " + due), cText(fmt.Sprintf("%d open, %d closed", d.Open, d.Closed))} |
| 123 | 124 | if d.Org { |
| 124 | | mark = "\torg" |
| 125 | cells = append(cells, cText("org")) |
| 125 | 126 | } |
| 126 | | fmt.Fprintf(w, "%s\t%s\tdue %s\t%d open, %d closed%s\n", d.Title, d.State, due, d.Open, d.Closed, mark) |
| 127 | tb.row(cells...) |
| 127 | 128 | } |
| 129 | tb.flush() |
| 128 | 130 | }) |
| 129 | 131 | } |
| 130 | 132 | |
| @@ -241,9 +243,11 @@ func runIssueTemplates(c *Ctx, args []string) int { |
| 241 | 243 | dir := RepoDir(c.Cfg.Server.Root, repo.OwnerName, repo.Name) |
| 242 | 244 | ts := IssueTemplates(dir, repo.DefaultBranch) |
| 243 | 245 | return c.emit(ts, func(w io.Writer) { |
| 246 | tb := c.table(w, "NAME") |
| 244 | 247 | for _, t := range ts { |
| 245 | | fmt.Fprintln(w, t.Name) |
| 248 | tb.row(cRef(t.Name)) |
| 246 | 249 | } |
| 250 | tb.flush() |
| 247 | 251 | }) |
| 248 | 252 | } |
| 249 | 253 | |
internal/control/mr.go
+10 −6
| @@ -499,17 +499,19 @@ func runMRList(c *Ctx, args []string) int { |
| 499 | 499 | ds = append(ds, o) |
| 500 | 500 | } |
| 501 | 501 | return c.emitPage(p, ds, next, func(w io.Writer) { |
| 502 | tb := c.table(w, "!", "STATE", "TITLE", "REF") |
| 502 | 503 | for _, d := range ds { |
| 503 | | stacked := "" |
| 504 | | if d.StackedOn != nil { |
| 505 | | stacked = fmt.Sprintf("\tstacked on !%d", d.StackedOn.Number) |
| 506 | | } |
| 507 | 504 | state := d.State |
| 508 | 505 | if d.Draft { |
| 509 | 506 | state = "draft" |
| 510 | 507 | } |
| 511 | | fmt.Fprintf(w, "!%d\t%s\t%s\t%s -> %s%s\n", d.Number, state, d.Title, d.Source, d.TargetRef, stacked) |
| 508 | cells := []cell{cRef(fmt.Sprintf("!%d", d.Number)), cState(state), cFlex(d.Title), cText(fmt.Sprintf("%s -> %s", d.Source, d.TargetRef))} |
| 509 | if d.StackedOn != nil { |
| 510 | cells = append(cells, cText(fmt.Sprintf("stacked on !%d", d.StackedOn.Number))) |
| 511 | } |
| 512 | tb.row(cells...) |
| 512 | 513 | } |
| 514 | tb.flush() |
| 513 | 515 | }) |
| 514 | 516 | } |
| 515 | 517 | |
| @@ -1703,13 +1705,15 @@ func runMRRevisions(c *Ctx, args []string) int { |
| 1703 | 1705 | return c.fail(protocol.ExitFailure, "%v", err) |
| 1704 | 1706 | } |
| 1705 | 1707 | return c.emit(revs, func(w io.Writer) { |
| 1708 | tb := c.table(w, "REV", "SHA", "WHEN") |
| 1706 | 1709 | for _, r := range revs { |
| 1707 | 1710 | mark := " " |
| 1708 | 1711 | if r.Current { |
| 1709 | 1712 | mark = "*" |
| 1710 | 1713 | } |
| 1711 | | fmt.Fprintf(w, "%s v%d\t%.10s\t%s\n", mark, r.N, r.SHA, r.CreatedAt) |
| 1714 | tb.row(cRef(fmt.Sprintf("%s v%d", mark, r.N)), cRef(fmt.Sprintf("%.10s", r.SHA)), cAge(r.CreatedAt)) |
| 1712 | 1715 | } |
| 1716 | tb.flush() |
| 1713 | 1717 | if len(revs) < 2 { |
| 1714 | 1718 | fmt.Fprintf(w, "\nonly one revision; %s!%d has not been pushed to since it was opened\n", |
| 1715 | 1719 | repo.Path(), mr.Number) |
internal/control/orglabel.go
+3 −1
| @@ -128,9 +128,11 @@ func runOrgLabelList(c *Ctx, args []string) int { |
| 128 | 128 | return c.fail(protocol.ExitFailure, "%v", err) |
| 129 | 129 | } |
| 130 | 130 | return c.emit(labels, func(w io.Writer) { |
| 131 | tb := c.table(w, "NAME", "COLOR", "ISSUES", "MRS") |
| 131 | 132 | for _, l := range labels { |
| 132 | | fmt.Fprintf(w, "%s\t%s\t%d\t%d\n", l.Name, l.Color, l.Issues, l.MRs) |
| 133 | tb.row(cRef(l.Name), cText(l.Color), cNum(l.Issues), cNum(l.MRs)) |
| 133 | 134 | } |
| 135 | tb.flush() |
| 134 | 136 | }) |
| 135 | 137 | } |
| 136 | 138 | |
internal/control/release.go
+3 −1
| @@ -246,13 +246,15 @@ func runReleaseList(c *Ctx, args []string) int { |
| 246 | 246 | ds = append(ds, releaseToOut(r, false)) |
| 247 | 247 | } |
| 248 | 248 | return c.emitPage(p, ds, next, func(w io.Writer) { |
| 249 | tb := c.table(w, "TAG", "TITLE", "ASSETS") |
| 249 | 250 | for _, d := range ds { |
| 250 | 251 | title := d.Title |
| 251 | 252 | if title == d.Tag { |
| 252 | 253 | title = "" |
| 253 | 254 | } |
| 254 | | fmt.Fprintf(w, "%s\t%s\t%d asset(s)\n", d.Tag, title, len(d.Assets)) |
| 255 | tb.row(cRef(d.Tag), cFlex(title), cText(fmt.Sprintf("%d asset(s)", len(d.Assets)))) |
| 255 | 256 | } |
| 257 | tb.flush() |
| 256 | 258 | }) |
| 257 | 259 | } |
| 258 | 260 | |
internal/control/search.go
+4 −3
| @@ -98,15 +98,16 @@ func runSearch(c *Ctx, args []string) int { |
| 98 | 98 | return c.fail(protocol.ExitFailure, "%v", err) |
| 99 | 99 | } |
| 100 | 100 | return c.emit(results, func(w io.Writer) { |
| 101 | tb := c.table(w, "KIND", "REF", "STATE", "TITLE") |
| 101 | 102 | for _, r := range results { |
| 102 | 103 | switch r.Kind { |
| 103 | 104 | case "repo": |
| 104 | | fmt.Fprintf(w, "repo\t%s\t%s\n", r.Repo, r.Title) |
| 105 | tb.row(cText("repo"), cRef(r.Repo), cFlex(r.Title)) |
| 105 | 106 | default: |
| 106 | | fmt.Fprintf(w, "%s\t%s%s%d\t%s\t%s\n", r.Kind, r.Repo, |
| 107 | | SearchMarker(r.Kind), r.Number, r.State, r.Title) |
| 107 | tb.row(cText(r.Kind), cRef(fmt.Sprintf("%s%s%d", r.Repo, SearchMarker(r.Kind), r.Number)), cState(r.State), cFlex(r.Title)) |
| 108 | 108 | } |
| 109 | 109 | } |
| 110 | tb.flush() |
| 110 | 111 | }) |
| 111 | 112 | } |
| 112 | 113 | |