Commit 77fb535e35
Verified · cmc
Layout: unified · split
internal/control/deps.go +29 −2
| @@ -4,6 +4,7 @@ import ( | ||
| 4 | 4 | "errors" |
| 5 | 5 | "fmt" |
| 6 | 6 | "io" |
| 7 | "strconv" | |
| 7 | 8 | |
| 8 | 9 | "gitbay.org/gitbay/internal/policy" |
| 9 | 10 | "gitbay.org/gitbay/internal/protocol" |
| @@ -92,9 +93,14 @@ func runDepsStatus(c *Ctx, args []string) int { | ||
| 92 | 93 | } |
| 93 | 94 | check, err := c.Store.DepCheckFor(repo.ID) |
| 94 | 95 | if errors.Is(err, store.ErrNotFound) { |
| 95 | return c.emit(map[string]any{"enabled": false}, func(w io.Writer) { | |
| 96 | return c.emitView(map[string]any{"enabled": false}, func(w io.Writer) { | |
| 96 | 97 | v := c.view(w) |
| 97 | 98 | v.fields("checks", fmt.Sprintf("off (repo deps enable %s)", repo.Path())) |
| 99 | }, func() screen { | |
| 100 | return screen{ | |
| 101 | fields: []field{{"Checks", []cell{cText("off")}}}, | |
| 102 | actions: []action{{"Deps", []string{"repo", "deps", "enable", repo.Path()}}}, | |
| 103 | } | |
| 98 | 104 | }) |
| 99 | 105 | } |
| 100 | 106 | if err != nil { |
| @@ -109,7 +115,7 @@ func runDepsStatus(c *Ctx, args []string) int { | ||
| 109 | 115 | for _, r := range reports { |
| 110 | 116 | out.Behind = append(out.Behind, DepBehind{r.Ecosystem, r.Name, r.Current, r.Latest}) |
| 111 | 117 | } |
| 112 | return c.emit(out, func(w io.Writer) { | |
| 118 | return c.emitView(out, func(w io.Writer) { | |
| 113 | 119 | tracked := "" |
| 114 | 120 | if check.IssueNumber != 0 { |
| 115 | 121 | tracked = fmt.Sprintf("#%d", check.IssueNumber) |
| @@ -129,5 +135,26 @@ func runDepsStatus(c *Ctx, args []string) int { | ||
| 129 | 135 | } |
| 130 | 136 | tb.flush() |
| 131 | 137 | } |
| 138 | }, func() screen { | |
| 139 | state := []cell{cGlyph("ok"), cText("on")} | |
| 140 | if check.LastError != "" { | |
| 141 | state = []cell{cGlyph("failed"), cText("on")} | |
| 142 | } | |
| 143 | s := screen{fields: []field{ | |
| 144 | {"Checks", state}, | |
| 145 | {"Last check", []cell{cAge(check.LastCheck)}}, | |
| 146 | {"Error", []cell{cMark(check.LastError, sgrRed)}}, | |
| 147 | }} | |
| 148 | if check.IssueNumber != 0 { | |
| 149 | n := strconv.FormatInt(check.IssueNumber, 10) | |
| 150 | s.fields = append(s.fields, field{"Tracked in", []cell{cLink("#"+n, c.siteURL(repo.Path(), "issues", n))}}) | |
| 151 | } | |
| 152 | behind := section{title: "Behind", n: len(out.Behind)} | |
| 153 | for _, b := range out.Behind { | |
| 154 | behind.rows = append(behind.rows, rowOf(cRef(b.Name), cText(b.Ecosystem), cMeta(b.Current+" → "+b.Latest))) | |
| 155 | } | |
| 156 | s.sections = []section{behind} | |
| 157 | s.actions = []action{{"Deps", []string{"repo", "deps", "disable", repo.Path()}}} | |
| 158 | return s | |
| 132 | 159 | }) |
| 133 | 160 | } |
internal/control/repo.go +44 −1
| @@ -811,7 +811,7 @@ func runSettingsShow(c *Ctx, args []string) int { | ||
| 811 | 811 | if code >= 0 { |
| 812 | 812 | return code |
| 813 | 813 | } |
| 814 | return c.emit(repo.Settings, func(w io.Writer) { | |
| 814 | return c.emitView(repo.Settings, func(w io.Writer) { | |
| 815 | 815 | v := c.view(w) |
| 816 | 816 | v.title(repo.Path(), "settings", "") |
| 817 | 817 | v.fields( |
| @@ -824,6 +824,49 @@ func runSettingsShow(c *Ctx, args []string) int { | ||
| 824 | 824 | "git daemon", strconv.FormatBool(repo.Settings.GitDaemon), |
| 825 | 825 | "archived", strconv.FormatBool(repo.Settings.Archived), |
| 826 | 826 | ) |
| 827 | }, func() screen { | |
| 828 | set := repo.Settings | |
| 829 | onOff := func(b bool) cell { | |
| 830 | if b { | |
| 831 | return cText("on") | |
| 832 | } | |
| 833 | return cMeta("off") | |
| 834 | } | |
| 835 | approvals := cMeta("off") | |
| 836 | if set.RequireApprovals > 0 { | |
| 837 | approvals = cText(strconv.Itoa(set.RequireApprovals)) | |
| 838 | } | |
| 839 | list := func(xs []string) cell { | |
| 840 | if len(xs) == 0 { | |
| 841 | return cMeta("none") | |
| 842 | } | |
| 843 | return cText(strings.Join(xs, ", ")) | |
| 844 | } | |
| 845 | mr := "on" | |
| 846 | if set.RequireMR { | |
| 847 | mr = "off" | |
| 848 | } | |
| 849 | s := screen{fields: []field{ | |
| 850 | {"Repo", []cell{cLink(repo.Path(), c.siteURL(repo.Path())), cMeta("settings")}}, | |
| 851 | {"Protected", []cell{list(set.ProtectedBranches)}}, | |
| 852 | {"Protected tags", []cell{list(set.ProtectedTags)}}, | |
| 853 | {"Require MR", []cell{onOff(set.RequireMR)}}, | |
| 854 | {"Require checks", []cell{onOff(set.RequireChecks)}}, | |
| 855 | {"Contexts", []cell{list(set.RequiredContexts)}}, | |
| 856 | {"Approvals", []cell{approvals}}, | |
| 857 | {"Resolved threads", []cell{onOff(set.RequireResolved)}}, | |
| 858 | {"Code owners", []cell{onOff(set.RequireCodeowners)}}, | |
| 859 | {"Signed commits", []cell{onOff(set.RequireSignedCommits)}}, | |
| 860 | {"Git daemon", []cell{onOff(set.GitDaemon)}}, | |
| 861 | {"Archived", []cell{onOff(set.Archived)}}, | |
| 862 | }, actions: []action{ | |
| 863 | {"Settings", []string{"repo", "settings", "protect", repo.Path(), "<branch>"}}, | |
| 864 | {"Settings", []string{"repo", "settings", "require-mr", repo.Path(), mr}}, | |
| 865 | }} | |
| 866 | if set.Website != "" { | |
| 867 | s.fields = append(s.fields, field{"Website", []cell{cText(set.Website)}}) | |
| 868 | } | |
| 869 | return s | |
| 827 | 870 | }) |
| 828 | 871 | } |
| 829 | 872 | |
internal/control/sig.go +20 −19
| @@ -354,27 +354,28 @@ func runRepoCommit(c *Ctx, args []string) int { | ||
| 354 | 354 | fmt.Fprintf(w, "\n%s", d.Diff) |
| 355 | 355 | return |
| 356 | 356 | } |
| 357 | v := c.view(w) | |
| 358 | v.title(d.SHA[:10], d.Subject, d.Signature.State) | |
| 359 | signer := d.Signature.Signer | |
| 360 | if signer != "" && d.Signature.Fingerprint != "" { | |
| 361 | signer += ", key " + d.Signature.Fingerprint | |
| 357 | short, url := d.SHA[:min(10, len(d.SHA))], c.siteURL(repo.OwnerName, repo.Name, "commit", d.SHA[:min(12, len(d.SHA))]) | |
| 358 | s := screen{body: body, format: "text", fields: []field{ | |
| 359 | {"Commit", []cell{cLink(short, url), cText(d.Subject)}}, | |
| 360 | {"Author", []cell{cText(fmt.Sprintf("%s <%s>", d.AuthorName, d.AuthorEmail)), cAge(d.Date)}}, | |
| 361 | }} | |
| 362 | if d.CommitterEmail != "" && d.CommitterEmail != d.AuthorEmail { | |
| 363 | s.fields = append(s.fields, field{"Committer", []cell{cText(d.CommitterEmail)}}) | |
| 362 | 364 | } |
| 363 | v.fields( | |
| 364 | "author", fmt.Sprintf("%s <%s>, %s", d.AuthorName, d.AuthorEmail, c.when(d.Date)), | |
| 365 | "committer", d.CommitterEmail, | |
| 366 | "signer", signer, | |
| 367 | "url", c.siteURL(repo.OwnerName, repo.Name, "commit", d.SHA[:12]), | |
| 368 | ) | |
| 369 | v.text(body) | |
| 370 | if len(d.Checks) > 0 { | |
| 371 | v.section("checks") | |
| 372 | tb := c.table(w, "CHECK", "STATE") | |
| 373 | for _, ch := range d.Checks { | |
| 374 | tb.row(cText(ch.Context), cState(ch.State)) | |
| 375 | } | |
| 376 | tb.flush() | |
| 365 | s.fields = append(s.fields, field{"Signature", []cell{cGlyph(d.Signature.State), cState(d.Signature.State), cMeta(d.Signature.Signer, d.Signature.Fingerprint)}}) | |
| 366 | if !c.Term.Links { | |
| 367 | s.fields = append(s.fields, field{"URL", []cell{cText(url)}}) | |
| 368 | } | |
| 369 | checks := section{title: "Checks", n: len(d.Checks)} | |
| 370 | for _, ch := range d.Checks { | |
| 371 | checks.rows = append(checks.rows, rowOf(cGlyph(ch.State), cFlex(ch.Context))) | |
| 372 | } | |
| 373 | s.sections = []section{checks} | |
| 374 | s.actions = []action{ | |
| 375 | {"Read", []string{"repo", "log", repo.Path(), "--ref", short}}, | |
| 376 | {"Read", []string{"repo", "tree", repo.Path(), "--ref", short}}, | |
| 377 | 377 | } |
| 378 | c.render(w, s) | |
| 378 | 379 | fmt.Fprintf(w, "\n%s", c.Term.diff(d.Diff)) |
| 379 | 380 | }) |
| 380 | 381 | } |
internal/control/stage3repo_test.go +40
| @@ -244,3 +244,43 @@ func TestRepoBrowseScreens(t *testing.T) { | ||
| 244 | 244 | } |
| 245 | 245 | checkLegend(t, out) |
| 246 | 246 | } |
| 247 | ||
| 248 | func TestRepoShowsPlainPinned(t *testing.T) { | |
| 249 | st, repo, u, root := browseFixture(t) | |
| 250 | p := repo.Path() | |
| 251 | pinPlain(t, "repo-settings-show", dispatchIn(t, st, u, root, "", "repo", "settings", "show", p)) | |
| 252 | pinPlain(t, "repo-deps-status-off", dispatchIn(t, st, u, root, "", "repo", "deps", "status", p)) | |
| 253 | pinPlain(t, "repo-commit", dispatchIn(t, st, u, root, "", "repo", "commit", p, "aee4475ad9")) | |
| 254 | dispatchIn(t, st, u, root, "", "repo", "deps", "enable", p) | |
| 255 | pinPlain(t, "repo-deps-status", dispatchIn(t, st, u, root, "", "repo", "deps", "status", p)) | |
| 256 | } | |
| 257 | ||
| 258 | func TestRepoShowScreens(t *testing.T) { | |
| 259 | st, repo, u, root := browseFixture(t) | |
| 260 | p := repo.Path() | |
| 261 | for _, tc := range []struct { | |
| 262 | argv []string | |
| 263 | want []string | |
| 264 | }{ | |
| 265 | {[]string{"repo", "settings", "show", p}, []string{"Repo:", "alice/app", "Require MR:", "off", "Approvals:"}}, | |
| 266 | {[]string{"repo", "deps", "status", p}, []string{"Checks: off\n", "gitbay repo deps enable alice/app"}}, | |
| 267 | {[]string{"repo", "commit", p, "aee4475ad9"}, []string{"Commit:", "aee4475ad9 docs: guide", "Author:", "t <t@example.test>", "gitbay repo log alice/app --ref aee4475ad9", "+# guide"}}, | |
| 268 | } { | |
| 269 | out := atTerminalIn(t, st, u, root, tc.argv...) | |
| 270 | for _, w := range tc.want { | |
| 271 | if !strings.Contains(out, w) { | |
| 272 | t.Errorf("%v: missing %q in:\n%s", tc.argv, w, out) | |
| 273 | } | |
| 274 | } | |
| 275 | checkLegend(t, out) | |
| 276 | } | |
| 277 | dispatchIn(t, st, u, root, "", "repo", "deps", "enable", p) | |
| 278 | out := atTerminalIn(t, st, u, root, "repo", "deps", "status", p) | |
| 279 | if !strings.Contains(out, "Checks:") || !strings.Contains(out, "gitbay repo deps disable alice/app") { | |
| 280 | t.Errorf("deps on:\n%s", out) | |
| 281 | } | |
| 282 | checkLegend(t, out) | |
| 283 | if i, j := strings.Index(out, "gitbay repo deps"), strings.Index(out, "Checks:"); i < j { | |
| 284 | t.Errorf("legend before the header:\n%s", out) | |
| 285 | } | |
| 286 | } | |
internal/control/testdata/plain/repo-commit.txt added +16
| @@ -0,0 +1,16 @@ | ||
| 1 | commit aee4475ad9033773a17e148aafa3105212ac9c10 | |
| 2 | Author: t <t@example.test> | |
| 3 | Date: <time> | |
| 4 | ||
| 5 | docs: guide | |
| 6 | ||
| 7 | docs/guide.md | 1 + | |
| 8 | 1 file changed, 1 insertion(+) | |
| 9 | ||
| 10 | diff --git a/docs/guide.md b/docs/guide.md | |
| 11 | new file mode 100644 | |
| 12 | index 0000000..cd51204 | |
| 13 | --- /dev/null | |
| 14 | +++ b/docs/guide.md | |
| 15 | @@ -0,0 +1 @@ | |
| 16 | +# guide | |
internal/control/testdata/plain/repo-deps-status-off.txt added +1
| @@ -0,0 +1 @@ | ||
| 1 | checks off (repo deps enable alice/app) | |
internal/control/testdata/plain/repo-deps-status.txt added +1
| @@ -0,0 +1 @@ | ||
| 1 | checks on | |
internal/control/testdata/plain/repo-settings-show.txt added +7
| @@ -0,0 +1,7 @@ | ||
| 1 | alice/app settings | |
| 2 | ||
| 3 | require mr false | |
| 4 | require checks false | |
| 5 | require signed commits false | |
| 6 | git daemon false | |
| 7 | archived false | |