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 {
159159 ds[i].Subject = subjects[ds[i].SHA]
160160 }
161161 return c.emitPage(p, ds, next, func(w io.Writer) {
162 tb := c.table(w, "#", "JOB", "STATUS", "SHA", "REF", "TITLE")
162163 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))
164165 }
166 tb.flush()
165167 })
166168}
167169
@@ -259,16 +261,18 @@ func runBuildJobs(c *Ctx, args []string) int {
259261 out = append(out, JobOut{Name: j.Name, Schedule: j.Schedule, Tags: j.Tags})
260262 }
261263 return c.emit(out, func(w io.Writer) {
264 tb := c.table(w, "NAME", "WHEN")
262265 for _, j := range out {
266 when := "on push"
263267 switch {
264268 case j.Schedule != "":
265 fmt.Fprintf(w, "%s\tschedule %s\n", j.Name, j.Schedule)
269 when = "schedule " + j.Schedule
266270 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
270272 }
273 tb.row(cRef(j.Name), cText(when))
271274 }
275 tb.flush()
272276 })
273277}
274278
@@ -365,9 +369,11 @@ func runSecretList(c *Ctx, args []string) int {
365369 return c.fail(protocol.ExitFailure, "%v", err)
366370 }
367371 return c.emit(names, func(w io.Writer) {
372 tb := c.table(w, "NAME")
368373 for _, n := range names {
369 fmt.Fprintln(w, n)
374 tb.row(cRef(n))
370375 }
376 tb.flush()
371377 })
372378}
373379
internal/control/explore.go +3 −2
@@ -1,7 +1,6 @@
11package control
22
33import (
4 "fmt"
54 "io"
65 "strings"
76
@@ -75,9 +74,11 @@ func runExplore(c *Ctx, args []string) int {
7574 }
7675 ds, next := trimPage(p, ds, "explore", func(o out) string { return o.Path })
7776 return c.emitPage(p, ds, next, func(w io.Writer) {
77 tb := c.table(w, "PATH", "DESCRIPTION")
7878 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))
8080 }
81 tb.flush()
8182 })
8283}
8384
internal/control/issue.go +3 −1
@@ -204,9 +204,11 @@ func runIssueList(c *Ctx, args []string) int {
204204 ds = append(ds, issueToOut(i, false))
205205 }
206206 return c.emitPage(p, ds, next, func(w io.Writer) {
207 tb := c.table(w, "#", "STATE", "TITLE", "AUTHOR")
207208 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))
209210 }
211 tb.flush()
210212 })
211213}
212214
internal/control/label.go +7 −1
@@ -46,9 +46,15 @@ func runLabelList(c *Ctx, args []string) int {
4646 return c.fail(protocol.ExitFailure, "%v", err)
4747 }
4848 return c.emit(labels, func(w io.Writer) {
49 tb := c.table(w, "NAME", "COLOR", "ISSUES", "MRS")
4950 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...)
5156 }
57 tb.flush()
5258 })
5359}
5460
internal/control/milestone.go +8 −4
@@ -114,17 +114,19 @@ func emitMilestones(c *Ctx, ms []store.Milestone) int {
114114 ds = append(ds, out{m.Title, m.Description, m.DueDate, m.State, m.OrgID != 0, m.OpenItems, m.ClosedItems})
115115 }
116116 return c.emit(ds, func(w io.Writer) {
117 tb := c.table(w, "TITLE", "STATE", "DUE", "PROGRESS")
117118 for _, d := range ds {
118119 due := d.Due
119120 if due == "" {
120121 due = "-"
121122 }
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))}
123124 if d.Org {
124 mark = "\torg"
125 cells = append(cells, cText("org"))
125126 }
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...)
127128 }
129 tb.flush()
128130 })
129131}
130132
@@ -241,9 +243,11 @@ func runIssueTemplates(c *Ctx, args []string) int {
241243 dir := RepoDir(c.Cfg.Server.Root, repo.OwnerName, repo.Name)
242244 ts := IssueTemplates(dir, repo.DefaultBranch)
243245 return c.emit(ts, func(w io.Writer) {
246 tb := c.table(w, "NAME")
244247 for _, t := range ts {
245 fmt.Fprintln(w, t.Name)
248 tb.row(cRef(t.Name))
246249 }
250 tb.flush()
247251 })
248252}
249253
internal/control/mr.go +10 −6
@@ -499,17 +499,19 @@ func runMRList(c *Ctx, args []string) int {
499499 ds = append(ds, o)
500500 }
501501 return c.emitPage(p, ds, next, func(w io.Writer) {
502 tb := c.table(w, "!", "STATE", "TITLE", "REF")
502503 for _, d := range ds {
503 stacked := ""
504 if d.StackedOn != nil {
505 stacked = fmt.Sprintf("\tstacked on !%d", d.StackedOn.Number)
506 }
507504 state := d.State
508505 if d.Draft {
509506 state = "draft"
510507 }
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...)
512513 }
514 tb.flush()
513515 })
514516}
515517
@@ -1703,13 +1705,15 @@ func runMRRevisions(c *Ctx, args []string) int {
17031705 return c.fail(protocol.ExitFailure, "%v", err)
17041706 }
17051707 return c.emit(revs, func(w io.Writer) {
1708 tb := c.table(w, "REV", "SHA", "WHEN")
17061709 for _, r := range revs {
17071710 mark := " "
17081711 if r.Current {
17091712 mark = "*"
17101713 }
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))
17121715 }
1716 tb.flush()
17131717 if len(revs) < 2 {
17141718 fmt.Fprintf(w, "\nonly one revision; %s!%d has not been pushed to since it was opened\n",
17151719 repo.Path(), mr.Number)
internal/control/orglabel.go +3 −1
@@ -128,9 +128,11 @@ func runOrgLabelList(c *Ctx, args []string) int {
128128 return c.fail(protocol.ExitFailure, "%v", err)
129129 }
130130 return c.emit(labels, func(w io.Writer) {
131 tb := c.table(w, "NAME", "COLOR", "ISSUES", "MRS")
131132 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))
133134 }
135 tb.flush()
134136 })
135137}
136138
internal/control/release.go +3 −1
@@ -246,13 +246,15 @@ func runReleaseList(c *Ctx, args []string) int {
246246 ds = append(ds, releaseToOut(r, false))
247247 }
248248 return c.emitPage(p, ds, next, func(w io.Writer) {
249 tb := c.table(w, "TAG", "TITLE", "ASSETS")
249250 for _, d := range ds {
250251 title := d.Title
251252 if title == d.Tag {
252253 title = ""
253254 }
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))))
255256 }
257 tb.flush()
256258 })
257259}
258260
internal/control/search.go +4 −3
@@ -98,15 +98,16 @@ func runSearch(c *Ctx, args []string) int {
9898 return c.fail(protocol.ExitFailure, "%v", err)
9999 }
100100 return c.emit(results, func(w io.Writer) {
101 tb := c.table(w, "KIND", "REF", "STATE", "TITLE")
101102 for _, r := range results {
102103 switch r.Kind {
103104 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))
105106 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))
108108 }
109109 }
110 tb.flush()
110111 })
111112}
112113