Commit 99ec0bbcaf

99ec0bbcafb36eedac6497cc8701a659c10410bf

parent: 171bcbd6c9

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-24 03:37 UTC

control: flags described and examples for work and repository commands

Ref #254
internal/control/build.go +55 −19
@@ -22,37 +22,64 @@ import (
2222func init() {
2323 register(Command{Path: []string{"build", "list"},
2424 Summary: "list recent builds",
25 Usage: "build list <owner/name> [--ref <branch>] [--status <state>] [--job <name>] [--limit <n>] [--cursor <c>]", ReadOnly: true, Run: runBuildList})
25 Usage: "build list <owner/name> [--ref <branch>] [--status <state>] [--job <name>] [--limit <n>] [--cursor <c>]",
26 Flags: []Flag{
27 {"--ref", "<branch>", "only builds on this branch", ""},
28 {"--status", "<state>", "only builds in this state", ""},
29 {"--job", "<name>", "only this job", ""},
30 {"--limit", "<n>", "rows per page", "50"},
31 {"--cursor", "<c>", "continue from the previous page", ""},
32 },
33 Examples: []string{"build list krz/gitbay --status failure"},
34 ReadOnly: true, Run: runBuildList})
2635 register(Command{Path: []string{"build", "show"},
27 Summary: "show one build",
28 Usage: "build show <owner/name> <n>", ReadOnly: true, Run: runBuildShow})
36 Summary: "show one build",
37 Usage: "build show <owner/name> <n>",
38 Examples: []string{"build show krz/gitbay 431"},
39 ReadOnly: true, Run: runBuildShow})
2940 register(Command{Path: []string{"build", "log"},
3041 Summary: "print a build's log, or follow it until the build ends",
31 Usage: "build log <owner/name> <n> [--follow]", ReadOnly: true, Run: runBuildLog})
42 Usage: "build log <owner/name> <n> [--follow]",
43 Flags: []Flag{
44 {"--follow", "", "stream the log until the build ends", ""},
45 },
46 Examples: []string{"build log krz/gitbay 431 --follow"},
47 ReadOnly: true, Run: runBuildLog})
3248
3349 register(Command{Path: []string{"build", "jobs"},
34 Summary: "list the jobs a trigger can name",
35 Usage: "build jobs <owner/name>", ReadOnly: true, Run: runBuildJobs})
50 Summary: "list the jobs a trigger can name",
51 Usage: "build jobs <owner/name>",
52 Examples: []string{"build jobs krz/gitbay"},
53 ReadOnly: true, Run: runBuildJobs})
3654
3755 register(Command{Path: []string{"build", "cancel"},
38 Summary: "withdraw a queued build before a runner claims it",
39 Usage: "build cancel <owner/name> <n>", Run: runBuildCancel})
56 Summary: "withdraw a queued build before a runner claims it",
57 Usage: "build cancel <owner/name> <n>",
58 Examples: []string{"build cancel krz/gitbay 431"},
59 Run: runBuildCancel})
4060 register(Command{Path: []string{"build", "trigger"},
41 Summary: "queue a job now (scheduled or not)",
42 Usage: "build trigger <owner/name> <job>", Run: runBuildTrigger})
61 Summary: "queue a job now (scheduled or not)",
62 Usage: "build trigger <owner/name> <job>",
63 Examples: []string{"build trigger krz/gitbay vuln"},
64 Run: runBuildTrigger})
4365 // Secrets: set over stdin, listed by name only, injected into the
4466 // repo's builds as environment variables. Same discipline as mirror
4567 // tokens — the value never appears in argv, logs, or output.
4668 register(Command{Path: []string{"repo", "secret", "set"},
4769 Summary: "set a build secret",
4870 Usage: "repo secret set <owner/name> <NAME> (value on stdin)",
71 Examples: []string{"repo secret set krz/gitbay DEPLOY_TOKEN"},
4972 ReadsStdin: true, Run: runSecretSet})
5073 register(Command{Path: []string{"repo", "secret", "remove"},
51 Summary: "remove a build secret",
52 Usage: "repo secret remove <owner/name> <NAME>", Run: runSecretRemove})
74 Summary: "remove a build secret",
75 Usage: "repo secret remove <owner/name> <NAME>",
76 Examples: []string{"repo secret remove krz/gitbay DEPLOY_TOKEN"},
77 Run: runSecretRemove})
5378 register(Command{Path: []string{"repo", "secret", "list"},
54 Summary: "list build secret names",
55 Usage: "repo secret list <owner/name>", ReadOnly: true, Run: runSecretList})
79 Summary: "list build secret names",
80 Usage: "repo secret list <owner/name>",
81 Examples: []string{"repo secret list krz/gitbay"},
82 ReadOnly: true, Run: runSecretList})
5683
5784 // Runner commands: the claim/report loop for gitbay-runner. A runner
5885 // executes arbitrary repo code, so handing out jobs is the instance
@@ -61,13 +88,22 @@ func init() {
6188 // an admin key, which a runner host should not hold (#92).
6289 register(Command{Path: []string{"runner", "next"},
6390 Summary: "claim the oldest pending build this key may run (runner protocol)",
64 Usage: "runner next [--untrusted] [<owner/name>...]", Run: runRunnerNext})
91 Usage: "runner next [--untrusted] [<owner/name>...]",
92 Flags: []Flag{
93 {"--untrusted", "", "this runner may build a fork's merge request head", ""},
94 },
95 Examples: []string{"runner next krz/gitbay"},
96 Run: runRunnerNext})
6597 register(Command{Path: []string{"runner", "log"},
66 Summary: "append a build's log from stdin",
67 Usage: "runner log <build-id>", ReadsStdin: true, Run: runRunnerLog})
98 Summary: "append a build's log from stdin",
99 Usage: "runner log <build-id>",
100 Examples: []string{"runner log 431"},
101 ReadsStdin: true, Run: runRunnerLog})
68102 register(Command{Path: []string{"runner", "done"},
69 Summary: "finish a build",
70 Usage: "runner done <build-id> success|failure", Run: runRunnerDone})
103 Summary: "finish a build",
104 Usage: "runner done <build-id> success|failure",
105 Examples: []string{"runner done 431 success"},
106 Run: runRunnerDone})
71107}
72108
73109type BuildOut struct {
internal/control/commitfile.go +8
@@ -17,6 +17,14 @@ func init() {
1717 Summary: "write a file and commit it",
1818 Usage: "repo commit-file <owner/name> <path> " +
1919 "--ref <branch> [--message <m>] [--file -]",
20 Flags: []Flag{
21 {"--ref", "<branch>", "branch to commit to", ""},
22 {"--message", "<m>", "the commit message", ""},
23 {"--file", "-", "read the new content from stdin", ""},
24 },
25 Examples: []string{
26 `repo commit-file krz/gitbay CHANGELOG.org --ref main --message "note the release" --file - '< CHANGELOG.org'`,
27 },
2028 ReadsStdin: true,
2129 Run: runCommitFile,
2230 })
internal/control/control.go +10
@@ -68,6 +68,14 @@ func (c *Ctx) usageWith(msg string) int {
6868 return c.fail(protocol.ExitUsage, "%s\nusage: %s", msg, c.Cmd.Usage)
6969}
7070
71// Flag is one flag in a command's help.
72type Flag struct {
73 Name string // "--state"
74 Arg string // "open|closed|all"; empty for a switch
75 Desc string // what it does, lower case, no full stop
76 Default string // empty for none
77}
78
7179type Command struct {
7280 Path []string // e.g. ["keys", "add"]
7381 // Summary is one line of prose: what the command does, no argument
@@ -75,6 +83,8 @@ type Command struct {
7583 // help renders them separately, so neither may carry the other's job.
7684 Summary string
7785 Usage string
86 Flags []Flag
87 Examples []string // full argv after the program, repository named
7888 ReadsStdin bool
7989 ReadOnly bool // safe for read-scoped API tokens
8090 Run func(c *Ctx, args []string) int
internal/control/dashboard.go +8 −2
@@ -18,10 +18,16 @@ func init() {
1818 register(Command{Path: []string{"dashboard"},
1919 Summary: "one read for the account dashboard: review queue, assigned and open work, pins, activity, builds",
2020 Usage: "dashboard",
21 Examples: []string{"dashboard"},
2122 ReadOnly: true, Run: runDashboard})
2223 register(Command{Path: []string{"feed"},
23 Summary: "activity on repositories you can reach",
24 Usage: "feed [--limit <n>] [--cursor <c>]",
24 Summary: "activity on repositories you can reach",
25 Usage: "feed [--limit <n>] [--cursor <c>]",
26 Flags: []Flag{
27 {"--limit", "<n>", "rows per page", ""},
28 {"--cursor", "<c>", "continue from the previous page", ""},
29 },
30 Examples: []string{"feed --limit 20"},
2531 ReadOnly: true, Run: runFeed})
2632}
2733
internal/control/deploykey.go +14 −6
@@ -14,15 +14,23 @@ import (
1414
1515func init() {
1616 register(Command{Path: []string{"repo", "deploy-key", "add"},
17 Summary: "bind a read-only (or --rw) key to one repository",
18 Usage: "repo deploy-key add <owner/name> [--rw] < key.pub",
17 Summary: "bind a read-only (or --rw) key to one repository",
18 Usage: "repo deploy-key add <owner/name> [--rw] < key.pub",
19 Flags: []Flag{
20 {"--rw", "", "the key may push, not just fetch", ""},
21 },
22 Examples: []string{"repo deploy-key add krz/gitbay '< key.pub'"},
1923 ReadsStdin: true, Run: runDeployKeyAdd})
2024 register(Command{Path: []string{"repo", "deploy-key", "list"},
21 Summary: "list deploy keys",
22 Usage: "repo deploy-key list <owner/name>", ReadOnly: true, Run: runDeployKeyList})
25 Summary: "list deploy keys",
26 Usage: "repo deploy-key list <owner/name>",
27 Examples: []string{"repo deploy-key list krz/gitbay"},
28 ReadOnly: true, Run: runDeployKeyList})
2329 register(Command{Path: []string{"repo", "deploy-key", "remove"},
24 Summary: "remove a deploy key",
25 Usage: "repo deploy-key remove <owner/name> <fingerprint>", Run: runDeployKeyRemove})
30 Summary: "remove a deploy key",
31 Usage: "repo deploy-key remove <owner/name> <fingerprint>",
32 Examples: []string{"repo deploy-key remove krz/gitbay SHA256:abcd1234"},
33 Run: runDeployKeyRemove})
2634}
2735
2836func runDeployKeyAdd(c *Ctx, args []string) int {
internal/control/deps.go +12 −6
@@ -15,14 +15,20 @@ func init() {
1515 // public registry what the repository depends on, which is the owner's
1616 // disclosure to make, not the instance's.
1717 register(Command{Path: []string{"repo", "deps", "enable"},
18 Summary: "check dependencies for updates",
19 Usage: "repo deps enable <owner/name>", Run: runDepsEnable})
18 Summary: "check dependencies for updates",
19 Usage: "repo deps enable <owner/name>",
20 Examples: []string{"repo deps enable krz/gitbay"},
21 Run: runDepsEnable})
2022 register(Command{Path: []string{"repo", "deps", "disable"},
21 Summary: "stop checking dependencies",
22 Usage: "repo deps disable <owner/name>", Run: runDepsDisable})
23 Summary: "stop checking dependencies",
24 Usage: "repo deps disable <owner/name>",
25 Examples: []string{"repo deps disable krz/gitbay"},
26 Run: runDepsDisable})
2327 register(Command{Path: []string{"repo", "deps", "status"},
24 Summary: "show dependency check state",
25 Usage: "repo deps status <owner/name>", ReadOnly: true, Run: runDepsStatus})
28 Summary: "show dependency check state",
29 Usage: "repo deps status <owner/name>",
30 Examples: []string{"repo deps status krz/gitbay"},
31 ReadOnly: true, Run: runDepsStatus})
2632}
2733
2834// DepsOut is what `repo deps status` emits: the check's state and what
internal/control/diffcomment.go +27 −8
@@ -16,18 +16,37 @@ import (
1616
1717func init() {
1818 register(Command{Path: []string{"mr", "diff-comment"},
19 Summary: "comment on a diff line",
20 Usage: "mr diff-comment <owner/name> <n> --path <file> --line <l> [--old] [--pending] [--reply <id>] [--message <m> | --file -]",
19 Summary: "comment on a diff line",
20 Usage: "mr diff-comment <owner/name> <n> --path <file> --line <l> [--old] [--pending] [--reply <id>] [--message <m> | --file -]",
21 Flags: []Flag{
22 {"--path", "<file>", "the file the comment is on", ""},
23 {"--line", "<l>", "the line the comment is on", ""},
24 {"--old", "", "the line is on the old side of the diff", ""},
25 {"--pending", "", "hold the comment for `mr review --comment`", ""},
26 {"--reply", "<id>", "reply to this thread instead of opening one", ""},
27 {"--message", "<m>", "the comment's text", ""},
28 {"--file", "-", "read the comment from stdin", ""},
29 },
30 Examples: []string{
31 `mr diff-comment krz/gitbay 431 --path internal/control/build.go --line 42 --message "why is this a switch"`,
32 "mr diff-comment krz/gitbay 431 --reply 12 --file - '< notes.md'",
33 },
2134 ReadsStdin: true, Run: runDiffComment})
2235 register(Command{Path: []string{"mr", "threads"},
23 Summary: "review threads on an MR",
24 Usage: "mr threads <owner/name> <n>", ReadOnly: true, Run: runMRThreads})
36 Summary: "review threads on an MR",
37 Usage: "mr threads <owner/name> <n>",
38 Examples: []string{"mr threads krz/gitbay 431"},
39 ReadOnly: true, Run: runMRThreads})
2540 register(Command{Path: []string{"mr", "resolve"},
26 Summary: "resolve a review thread",
27 Usage: "mr resolve <owner/name> <n> <thread-id>", Run: runMRResolve})
41 Summary: "resolve a review thread",
42 Usage: "mr resolve <owner/name> <n> <thread-id>",
43 Examples: []string{"mr resolve krz/gitbay 431 12"},
44 Run: runMRResolve})
2845 register(Command{Path: []string{"mr", "unresolve"},
29 Summary: "reopen a review thread",
30 Usage: "mr unresolve <owner/name> <n> <thread-id>", Run: runMRUnresolve})
46 Summary: "reopen a review thread",
47 Usage: "mr unresolve <owner/name> <n> <thread-id>",
48 Examples: []string{"mr unresolve krz/gitbay 431 12"},
49 Run: runMRUnresolve})
3150}
3251
3352func runDiffComment(c *Ctx, args []string) int {
internal/control/explore.go +14 −5
@@ -11,9 +11,14 @@ import (
1111
1212func init() {
1313 register(Command{
14 Path: []string{"explore"},
15 Summary: "list public repositories",
16 Usage: "explore [--limit <n>] [--cursor <c>]",
14 Path: []string{"explore"},
15 Summary: "list public repositories",
16 Usage: "explore [--limit <n>] [--cursor <c>]",
17 Flags: []Flag{
18 {"--limit", "<n>", "rows per page", ""},
19 {"--cursor", "<c>", "continue from the previous page", ""},
20 },
21 Examples: []string{"explore --limit 20"},
1722 ReadOnly: true,
1823 Run: runExplore,
1924 })
@@ -21,8 +26,12 @@ func init() {
2126 Path: []string{"repo", "download"},
2227 // Not "repo archive": that name is taken by the read-only flag,
2328 // and renaming it would break every script that sets it.
24 Summary: "write a tar.gz of a ref to stdout",
25 Usage: "repo download <owner/name> [--ref <r>] > repo.tar.gz",
29 Summary: "write a tar.gz of a ref to stdout",
30 Usage: "repo download <owner/name> [--ref <r>] > repo.tar.gz",
31 Flags: []Flag{
32 {"--ref", "<r>", "branch, tag or commit to archive", ""},
33 },
34 Examples: []string{"repo download krz/gitbay --ref main '> gitbay.tar.gz'"},
2635 ReadOnly: true,
2736 Run: runRepoDownload,
2837 })
internal/control/ghimport.go +8 −2
@@ -23,8 +23,14 @@ import (
2323
2424func init() {
2525 register(Command{Path: []string{"repo", "import-issues"},
26 Summary: "import issue and PR history from GitHub or Forgejo",
27 Usage: "repo import-issues <owner/name> --from <owner/repo> [--token-stdin] [--api-base <url>]",
26 Summary: "import issue and PR history from GitHub or Forgejo",
27 Usage: "repo import-issues <owner/name> --from <owner/repo> [--token-stdin] [--api-base <url>]",
28 Flags: []Flag{
29 {"--from", "<owner/repo>", "the source repository", ""},
30 {"--token-stdin", "", "read an API token from stdin", ""},
31 {"--api-base", "<url>", "the API's base URL, for Forgejo", ""},
32 },
33 Examples: []string{"repo import-issues krz/gitbay --from krz/gitbay-old"},
2834 ReadsStdin: true, Run: runImportIssues})
2935}
3036
internal/control/help_test.go added +80
@@ -0,0 +1,80 @@
1package control
2
3import (
4 "regexp"
5 "slices"
6 "strings"
7 "testing"
8
9 "gitbay.org/gitbay/internal/protocol"
10)
11
12var usageFlag = regexp.MustCompile(`--[a-z][a-z0-9-]*`)
13
14// helpCovered restricts TestHelpIsComplete to the path prefixes whose help
15// text this commit filled in. Task 4.3 fills the rest and removes this set.
16// "org label" and "org milestone" name the two prefixes under "org" this
17// commit covers; the rest of "org" (teams, members, profile) is not.
18// widened to every command in the next commit
19var helpCovered = []string{
20 "issue", "mr", "build", "release", "milestone", "label", "search",
21 "dashboard", "feed", "status", "wiki", "snippet", "repo",
22 "org label", "org milestone",
23}
24
25func isHelpCovered(path []string) bool {
26 joined := strings.Join(path, " ")
27 for _, prefix := range helpCovered {
28 if joined == prefix || strings.HasPrefix(joined, prefix+" ") {
29 return true
30 }
31 }
32 return false
33}
34
35// Help is written once, in the registry. Every flag in a usage line has
36// a description, every description names a flag in the usage line, and
37// every command has an example that runs it.
38func TestHelpIsComplete(t *testing.T) {
39 for _, cmd := range Commands() {
40 if !isHelpCovered(cmd.Path) {
41 continue
42 }
43 path := strings.Join(cmd.Path, " ")
44 inUsage := map[string]bool{}
45 for _, f := range usageFlag.FindAllString(cmd.Usage, -1) {
46 if f != "--json" {
47 inUsage[f] = true
48 }
49 }
50 described := map[string]bool{}
51 for _, f := range cmd.Flags {
52 described[f.Name] = true
53 if f.Desc == "" {
54 t.Errorf("%s: %s has no description", path, f.Name)
55 }
56 if !inUsage[f.Name] {
57 t.Errorf("%s: %s is described but not in the usage", path, f.Name)
58 }
59 }
60 for f := range inUsage {
61 if !described[f] {
62 t.Errorf("%s: %s is in the usage with no description", path, f)
63 }
64 }
65 if len(cmd.Examples) == 0 {
66 t.Errorf("%s: no example", path)
67 }
68 for _, ex := range cmd.Examples {
69 argv, err := protocol.Tokenize(ex)
70 if err != nil {
71 t.Errorf("%s: example %q: %v", path, ex, err)
72 continue
73 }
74 got, _, ok := Lookup(argv)
75 if !ok || !slices.Equal(got.Path, cmd.Path) {
76 t.Errorf("%s: example %q runs %v", path, ex, got.Path)
77 }
78 }
79 }
80}
internal/control/import.go +8 −2
@@ -17,8 +17,14 @@ import (
1717
1818func init() {
1919 register(Command{Path: []string{"repo", "import"},
20 Summary: "server-side mirror of a foreign repository",
21 Usage: "repo import <owner/name> --from <url> [--private] [--token-stdin]",
20 Summary: "server-side mirror of a foreign repository",
21 Usage: "repo import <owner/name> --from <url> [--private] [--token-stdin]",
22 Flags: []Flag{
23 {"--from", "<url>", "the repository to import", ""},
24 {"--private", "", "create it private", ""},
25 {"--token-stdin", "", "read a credential token from stdin", ""},
26 },
27 Examples: []string{"repo import krz/imported --from https://github.com/krz/old.git"},
2228 ReadsStdin: true, Run: runRepoImport})
2329}
2430
internal/control/issue.go +77 −15
@@ -16,35 +16,97 @@ const maxBodyBytes = 64 << 10
1616
1717func init() {
1818 register(Command{Path: []string{"issue", "create"},
19 Summary: "open an issue",
20 Usage: "issue create <owner/name> --title <t> [--body <b> | --file -] [--format md|org]",
19 Summary: "open an issue",
20 Usage: "issue create <owner/name> --title <t> [--body <b> | --file -] [--format md|org]",
21 Flags: []Flag{
22 {"--title", "<t>", "the issue's title", ""},
23 {"--body", "<b>", "the issue's body", ""},
24 {"--file", "-", "read the body from stdin", ""},
25 {"--format", "md|org", "the body's markup", "md"},
26 },
27 Examples: []string{
28 `issue create krz/gitbay --title "crash on empty repo" --body "steps to reproduce..."`,
29 "issue create krz/gitbay --title notes --file - '< notes.md'",
30 },
2131 ReadsStdin: true, Run: runIssueCreate})
2232 register(Command{Path: []string{"issue", "list"},
2333 Summary: "list issues",
24 Usage: "issue list <owner/name> [--state open|closed|all] [--label <l>] [--assignee <user>] [--author <user>] [--milestone <title>|none] [--search <text>] [--limit <n>] [--cursor <c>]", ReadOnly: true, Run: runIssueList})
34 Usage: "issue list <owner/name> [--state open|closed|all] [--label <l>] [--assignee <user>] [--author <user>] [--milestone <title>|none] [--search <text>] [--limit <n>] [--cursor <c>]",
35 Flags: []Flag{
36 {"--state", "open|closed|all", "which issues", "open"},
37 {"--label", "<l>", "only issues carrying this label", ""},
38 {"--assignee", "<user>", "only issues assigned to this user", ""},
39 {"--author", "<user>", "only issues opened by this user", ""},
40 {"--milestone", "<title>|none", "only issues in this milestone, or in none", ""},
41 {"--search", "<text>", "match title and body", ""},
42 {"--limit", "<n>", "rows per page", ""},
43 {"--cursor", "<c>", "continue from the previous page", ""},
44 },
45 Examples: []string{
46 "issue list krz/gitbay --label bug --state all",
47 "issue list krz/gitbay --assignee cmc",
48 },
49 ReadOnly: true, Run: runIssueList})
2550 register(Command{Path: []string{"issue", "show"},
26 Summary: "show an issue with comments",
27 Usage: "issue show <owner/name> <n>", ReadOnly: true, Run: runIssueShow})
51 Summary: "show an issue with comments",
52 Usage: "issue show <owner/name> <n>",
53 Examples: []string{"issue show krz/gitbay 42"},
54 ReadOnly: true, Run: runIssueShow})
2855 register(Command{Path: []string{"issue", "edit"},
29 Summary: "edit title or body",
30 Usage: "issue edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org]",
56 Summary: "edit title or body",
57 Usage: "issue edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org]",
58 Flags: []Flag{
59 {"--title", "<t>", "the issue's new title", ""},
60 {"--body", "<b>", "the issue's new body", ""},
61 {"--file", "-", "read the new body from stdin", ""},
62 {"--format", "md|org", "the body's markup", ""},
63 },
64 Examples: []string{
65 `issue edit krz/gitbay 42 --title "crash on empty repo, take two"`,
66 "issue edit krz/gitbay 42 --file - '< notes.md'",
67 },
3168 ReadsStdin: true, Run: runIssueEdit})
3269 register(Command{Path: []string{"issue", "comment"},
33 Summary: "comment",
34 Usage: "issue comment <owner/name> <n> [--message <m> | --file -] [--format md|org]",
70 Summary: "comment",
71 Usage: "issue comment <owner/name> <n> [--message <m> | --file -] [--format md|org]",
72 Flags: []Flag{
73 {"--message", "<m>", "the comment's text", ""},
74 {"--file", "-", "read the comment from stdin", ""},
75 {"--format", "md|org", "the comment's markup", "md"},
76 },
77 Examples: []string{
78 `issue comment krz/gitbay 42 --message "can't reproduce on main"`,
79 "issue comment krz/gitbay 42 --file - '< notes.md'",
80 },
3581 ReadsStdin: true, Run: runIssueComment})
3682 register(Command{Path: []string{"issue", "close"},
37 Summary: "close an issue",
38 Usage: "issue close <owner/name> <n>", Run: runIssueClose})
83 Summary: "close an issue",
84 Usage: "issue close <owner/name> <n>",
85 Examples: []string{"issue close krz/gitbay 42"},
86 Run: runIssueClose})
3987 register(Command{Path: []string{"issue", "reopen"},
40 Summary: "reopen an issue",
41 Usage: "issue reopen <owner/name> <n>", Run: runIssueReopen})
88 Summary: "reopen an issue",
89 Usage: "issue reopen <owner/name> <n>",
90 Examples: []string{"issue reopen krz/gitbay 42"},
91 Run: runIssueReopen})
4292 register(Command{Path: []string{"issue", "label"},
4393 Summary: "labels",
44 Usage: "issue label <owner/name> <n> [--add <l>]... [--remove <l>]...", Run: runIssueLabel})
94 Usage: "issue label <owner/name> <n> [--add <l>]... [--remove <l>]...",
95 Flags: []Flag{
96 {"--add", "<l>", "label to add, may repeat", ""},
97 {"--remove", "<l>", "label to remove, may repeat", ""},
98 },
99 Examples: []string{"issue label krz/gitbay 42 --add bug --remove needs-triage"},
100 Run: runIssueLabel})
45101 register(Command{Path: []string{"issue", "assign"},
46102 Summary: "assignees",
47 Usage: "issue assign <owner/name> <n> [--add <user>]... [--remove <user>]...", Run: runIssueAssign})
103 Usage: "issue assign <owner/name> <n> [--add <user>]... [--remove <user>]...",
104 Flags: []Flag{
105 {"--add", "<user>", "user to assign, may repeat", ""},
106 {"--remove", "<user>", "user to unassign, may repeat", ""},
107 },
108 Examples: []string{"issue assign krz/gitbay 42 --add cmc"},
109 Run: runIssueAssign})
48110}
49111
50112// issueArgs parses "<owner/name> <n>" plus flags handled by the caller.
internal/control/label.go +14 −5
@@ -14,14 +14,23 @@ import (
1414
1515func init() {
1616 register(Command{Path: []string{"label", "list"},
17 Summary: "list a repository's labels with colour and use",
18 Usage: "label list <owner/name>", ReadOnly: true, Run: runLabelList})
17 Summary: "list a repository's labels with colour and use",
18 Usage: "label list <owner/name>",
19 Examples: []string{"label list krz/gitbay"},
20 ReadOnly: true, Run: runLabelList})
1921 register(Command{Path: []string{"label", "set"},
2022 Summary: "create a label or set its colour",
21 Usage: "label set <owner/name> <label> [--color rrggbb|'']", Run: runLabelSet})
23 Usage: "label set <owner/name> <label> [--color rrggbb|'']",
24 Flags: []Flag{
25 {"--color", "rrggbb|''", "the label's colour, or '' to clear it", ""},
26 },
27 Examples: []string{"label set krz/gitbay bug --color d73a4a"},
28 Run: runLabelSet})
2229 register(Command{Path: []string{"label", "remove"},
23 Summary: "remove a label from the repository and from every issue and merge request",
24 Usage: "label remove <owner/name> <label>", Run: runLabelRemove})
30 Summary: "remove a label from the repository and from every issue and merge request",
31 Usage: "label remove <owner/name> <label>",
32 Examples: []string{"label remove krz/gitbay wontfix"},
33 Run: runLabelRemove})
2534}
2635
2736// A colour is six hex digits, with or without the hash: over bare ssh a
internal/control/milestone.go +33 −12
@@ -17,25 +17,46 @@ import (
1717func init() {
1818 register(Command{Path: []string{"milestone", "create"},
1919 Summary: "create a milestone",
20 Usage: "milestone create <owner/name> <title> [--description <d>] [--due YYYY-MM-DD]", Run: runMilestoneCreate})
20 Usage: "milestone create <owner/name> <title> [--description <d>] [--due YYYY-MM-DD]",
21 Flags: []Flag{
22 {"--description", "<d>", "what the milestone covers", ""},
23 {"--due", "YYYY-MM-DD", "target date", ""},
24 },
25 Examples: []string{`milestone create krz/gitbay v1.31.0 --due 2026-10-01`},
26 Run: runMilestoneCreate})
2127 register(Command{Path: []string{"milestone", "list"},
2228 Summary: "list milestones with progress",
23 Usage: "milestone list <owner/name> [--state open|closed|all]", ReadOnly: true, Run: runMilestoneList})
29 Usage: "milestone list <owner/name> [--state open|closed|all]",
30 Flags: []Flag{
31 {"--state", "open|closed|all", "which milestones", "open"},
32 },
33 Examples: []string{"milestone list krz/gitbay --state all"},
34 ReadOnly: true, Run: runMilestoneList})
2435 register(Command{Path: []string{"milestone", "close"},
25 Summary: "close a milestone",
26 Usage: "milestone close <owner/name> <title>", Run: runMilestoneClose})
36 Summary: "close a milestone",
37 Usage: "milestone close <owner/name> <title>",
38 Examples: []string{"milestone close krz/gitbay v1.30.0"},
39 Run: runMilestoneClose})
2740 register(Command{Path: []string{"milestone", "reopen"},
28 Summary: "reopen a milestone",
29 Usage: "milestone reopen <owner/name> <title>", Run: runMilestoneReopen})
41 Summary: "reopen a milestone",
42 Usage: "milestone reopen <owner/name> <title>",
43 Examples: []string{"milestone reopen krz/gitbay v1.30.0"},
44 Run: runMilestoneReopen})
3045 register(Command{Path: []string{"issue", "milestone"},
31 Summary: "set or clear an issue's milestone",
32 Usage: "issue milestone <owner/name> <n> <title|none>", Run: runIssueMilestone})
46 Summary: "set or clear an issue's milestone",
47 Usage: "issue milestone <owner/name> <n> <title|none>",
48 Examples: []string{"issue milestone krz/gitbay 42 v1.31.0"},
49 Run: runIssueMilestone})
3350 register(Command{Path: []string{"mr", "milestone"},
34 Summary: "set or clear an MR's milestone",
35 Usage: "mr milestone <owner/name> <n> <title|none>", Run: runMRMilestone})
51 Summary: "set or clear an MR's milestone",
52 Usage: "mr milestone <owner/name> <n> <title|none>",
53 Examples: []string{"mr milestone krz/gitbay 431 v1.31.0"},
54 Run: runMRMilestone})
3655 register(Command{Path: []string{"issue", "templates"},
37 Summary: "list issue templates (.gitbay/issue-template*.md)",
38 Usage: "issue templates <owner/name>", ReadOnly: true, Run: runIssueTemplates})
56 Summary: "list issue templates (.gitbay/issue-template*.md)",
57 Usage: "issue templates <owner/name>",
58 Examples: []string{"issue templates krz/gitbay"},
59 ReadOnly: true, Run: runIssueTemplates})
3960}
4061
4162var duePat = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
internal/control/mirrorcmd.go +20 −8
@@ -16,18 +16,30 @@ import (
1616
1717func init() {
1818 register(Command{Path: []string{"repo", "mirror", "add"},
19 Summary: "mirror to or from a remote",
20 Usage: "repo mirror add <owner/name> <https-url> --direction push|pull [--username <u>] [--token-stdin]",
19 Summary: "mirror to or from a remote",
20 Usage: "repo mirror add <owner/name> <https-url> --direction push|pull [--username <u>] [--token-stdin]",
21 Flags: []Flag{
22 {"--direction", "push|pull", "which way the mirror syncs", ""},
23 {"--username", "<u>", "the remote's username", ""},
24 {"--token-stdin", "", "read a credential token from stdin", ""},
25 },
26 Examples: []string{"repo mirror add krz/gitbay https://github.com/krazywarez/gitbay.git --direction push"},
2127 ReadsStdin: true, Run: runMirrorAdd})
2228 register(Command{Path: []string{"repo", "mirror", "list"},
23 Summary: "list mirrors with sync status",
24 Usage: "repo mirror list <owner/name>", ReadOnly: true, Run: runMirrorList})
29 Summary: "list mirrors with sync status",
30 Usage: "repo mirror list <owner/name>",
31 Examples: []string{"repo mirror list krz/gitbay"},
32 ReadOnly: true, Run: runMirrorList})
2533 register(Command{Path: []string{"repo", "mirror", "remove"},
26 Summary: "remove a mirror",
27 Usage: "repo mirror remove <owner/name> <id>", Run: runMirrorRemove})
34 Summary: "remove a mirror",
35 Usage: "repo mirror remove <owner/name> <id>",
36 Examples: []string{"repo mirror remove krz/gitbay 3"},
37 Run: runMirrorRemove})
2838 register(Command{Path: []string{"repo", "mirror", "sync"},
29 Summary: "schedule an immediate sync",
30 Usage: "repo mirror sync <owner/name>", Run: runMirrorSync})
39 Summary: "schedule an immediate sync",
40 Usage: "repo mirror sync <owner/name>",
41 Examples: []string{"repo mirror sync krz/gitbay"},
42 Run: runMirrorSync})
3143}
3244
3345func runMirrorAdd(c *Ctx, args []string) int {
internal/control/mr.go +142 −37
@@ -20,78 +20,183 @@ import (
2020func init() {
2121 register(Command{Path: []string{"repo", "fork"},
2222 Summary: "fork a repository under your account",
23 Usage: "repo fork <owner/name> [--owner <o>] [--name <n>]", Run: runRepoFork})
23 Usage: "repo fork <owner/name> [--owner <o>] [--name <n>]",
24 Flags: []Flag{
25 {"--owner", "<o>", "fork under this user or org, default your account", ""},
26 {"--name", "<n>", "name the fork", "the source's name"},
27 },
28 Examples: []string{"repo fork krz/gitbay"},
29 Run: runRepoFork})
2430 register(Command{Path: []string{"repo", "settings", "require-approvals"},
25 Summary: "require N fresh approvals to merge",
26 Usage: "repo settings require-approvals <owner/name> <n> (0 = off)", Run: runRequireApprovals})
31 Summary: "require N fresh approvals to merge",
32 Usage: "repo settings require-approvals <owner/name> <n> (0 = off)",
33 Examples: []string{"repo settings require-approvals krz/gitbay 1"},
34 Run: runRequireApprovals})
2735 register(Command{Path: []string{"repo", "settings", "require-resolved"},
28 Summary: "require all review threads resolved to merge",
29 Usage: "repo settings require-resolved <owner/name> on|off", Run: runRequireResolved})
36 Summary: "require all review threads resolved to merge",
37 Usage: "repo settings require-resolved <owner/name> on|off",
38 Examples: []string{"repo settings require-resolved krz/gitbay on"},
39 Run: runRequireResolved})
3040 register(Command{Path: []string{"repo", "settings", "require-codeowners"},
31 Summary: "require an owner's approval for every file CODEOWNERS covers",
32 Usage: "repo settings require-codeowners <owner/name> on|off", Run: runRequireCodeowners})
41 Summary: "require an owner's approval for every file CODEOWNERS covers",
42 Usage: "repo settings require-codeowners <owner/name> on|off",
43 Examples: []string{"repo settings require-codeowners krz/gitbay on"},
44 Run: runRequireCodeowners})
3345 register(Command{Path: []string{"repo", "settings", "require-checks"},
34 Summary: "gate merges on green statuses",
35 Usage: "repo settings require-checks <owner/name> on|off", Run: runRequireChecks})
46 Summary: "gate merges on green statuses",
47 Usage: "repo settings require-checks <owner/name> on|off",
48 Examples: []string{"repo settings require-checks krz/gitbay on"},
49 Run: runRequireChecks})
3650 register(Command{Path: []string{"repo", "settings", "require-mr"},
37 Summary: "protected branches take changes through merge requests only",
38 Usage: "repo settings require-mr <owner/name> on|off", Run: runRequireMR})
51 Summary: "protected branches take changes through merge requests only",
52 Usage: "repo settings require-mr <owner/name> on|off",
53 Examples: []string{"repo settings require-mr krz/gitbay on"},
54 Run: runRequireMR})
3955 register(Command{Path: []string{"repo", "settings", "require-signed"},
40 Summary: "require verified commit signatures",
41 Usage: "repo settings require-signed <owner/name> on|off", Run: runRequireSigned})
56 Summary: "require verified commit signatures",
57 Usage: "repo settings require-signed <owner/name> on|off",
58 Examples: []string{"repo settings require-signed krz/gitbay on"},
59 Run: runRequireSigned})
4260 register(Command{Path: []string{"mr", "create"},
43 Summary: "open a merge request",
44 Usage: "mr create <target owner/name> --source [owner/name:]<branch> --target <branch> --title <t> [--body <b> | --file -] [--format md|org] [--draft]",
61 Summary: "open a merge request",
62 Usage: "mr create <target owner/name> --source [owner/name:]<branch> --target <branch> --title <t> [--body <b> | --file -] [--format md|org] [--draft]",
63 Flags: []Flag{
64 {"--source", "[owner/name:]<branch>", "the branch to merge, from a fork with owner/name:", ""},
65 {"--target", "<branch>", "the branch to merge into", ""},
66 {"--title", "<t>", "the merge request's title", ""},
67 {"--body", "<b>", "the merge request's body", ""},
68 {"--file", "-", "read the body from stdin", ""},
69 {"--format", "md|org", "the body's markup", "md"},
70 {"--draft", "", "open it as work in progress", ""},
71 },
72 Examples: []string{
73 `mr create krz/gitbay --source cli-output-help --target main --title "control: flag help"`,
74 "mr create krz/gitbay --source cli-output-help --target main --title notes --file - '< notes.md'",
75 },
4576 ReadsStdin: true, Run: runMRCreate})
4677 register(Command{Path: []string{"mr", "range-diff"},
47 Summary: "what changed between two revisions of a merge request",
48 Usage: "mr range-diff <owner/name> <n> [--from <sha>] [--to <sha>]",
78 Summary: "what changed between two revisions of a merge request",
79 Usage: "mr range-diff <owner/name> <n> [--from <sha>] [--to <sha>]",
80 Flags: []Flag{
81 {"--from", "<sha>", "earlier revision, default the one before --to", ""},
82 {"--to", "<sha>", "later revision, default the head", ""},
83 },
84 Examples: []string{"mr range-diff krz/gitbay 431"},
4985 ReadOnly: true, Run: runMRRangeDiff})
5086 register(Command{Path: []string{"mr", "revisions"},
5187 Summary: "the heads a merge request has had",
5288 Usage: "mr revisions <owner/name> <n>",
89 Examples: []string{"mr revisions krz/gitbay 431"},
5390 ReadOnly: true, Run: runMRRevisions})
5491 register(Command{Path: []string{"mr", "draft"},
55 Summary: "mark a merge request as work in progress",
56 Usage: "mr draft <owner/name> <n>", Run: runMRDraft})
92 Summary: "mark a merge request as work in progress",
93 Usage: "mr draft <owner/name> <n>",
94 Examples: []string{"mr draft krz/gitbay 431"},
95 Run: runMRDraft})
5796 register(Command{Path: []string{"mr", "ready"},
58 Summary: "take the draft mark off, so it can merge",
59 Usage: "mr ready <owner/name> <n>", Run: runMRReady})
97 Summary: "take the draft mark off, so it can merge",
98 Usage: "mr ready <owner/name> <n>",
99 Examples: []string{"mr ready krz/gitbay 431"},
100 Run: runMRReady})
60101 register(Command{Path: []string{"mr", "list"},
61102 Summary: "list merge requests",
62 Usage: "mr list <owner/name> [--state open|merged|closed|source_gone|all] [--label <l>] [--author <user>] [--milestone <title>|none] [--search <text>] [--limit <n>] [--cursor <c>]", ReadOnly: true, Run: runMRList})
103 Usage: "mr list <owner/name> [--state open|merged|closed|source_gone|all] [--label <l>] [--author <user>] [--milestone <title>|none] [--search <text>] [--limit <n>] [--cursor <c>]",
104 Flags: []Flag{
105 {"--state", "open|merged|closed|source_gone|all", "which merge requests", "open"},
106 {"--label", "<l>", "only MRs carrying this label", ""},
107 {"--author", "<user>", "only MRs opened by this user", ""},
108 {"--milestone", "<title>|none", "only MRs in this milestone, or in none", ""},
109 {"--search", "<text>", "match title and body", ""},
110 {"--limit", "<n>", "rows per page", ""},
111 {"--cursor", "<c>", "continue from the previous page", ""},
112 },
113 Examples: []string{
114 "mr list krz/gitbay --state open",
115 "mr list krz/gitbay --author cmc --state all",
116 },
117 ReadOnly: true, Run: runMRList})
63118 register(Command{Path: []string{"mr", "show"},
64 Summary: "show a merge request",
65 Usage: "mr show <owner/name> <n>", ReadOnly: true, Run: runMRShow})
119 Summary: "show a merge request",
120 Usage: "mr show <owner/name> <n>",
121 Examples: []string{"mr show krz/gitbay 431"},
122 ReadOnly: true, Run: runMRShow})
66123 register(Command{Path: []string{"mr", "diff"},
67 Summary: "show the diff",
68 Usage: "mr diff <owner/name> <n>", ReadOnly: true, Run: runMRDiff})
124 Summary: "show the diff",
125 Usage: "mr diff <owner/name> <n>",
126 Examples: []string{"mr diff krz/gitbay 431"},
127 ReadOnly: true, Run: runMRDiff})
69128 register(Command{Path: []string{"mr", "edit"},
70 Summary: "edit title or body",
71 Usage: "mr edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org] [--superseded-by <m>|none]",
129 Summary: "edit title or body",
130 Usage: "mr edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org] [--superseded-by <m>|none]",
131 Flags: []Flag{
132 {"--title", "<t>", "the merge request's new title", ""},
133 {"--body", "<b>", "the merge request's new body", ""},
134 {"--file", "-", "read the new body from stdin", ""},
135 {"--format", "md|org", "the body's markup", ""},
136 {"--superseded-by", "<m>|none", "the MR that replaces this closed one, or none to clear", ""},
137 },
138 Examples: []string{`mr edit krz/gitbay 431 --title "control: flag help, take two"`},
72139 ReadsStdin: true, Run: runMREdit})
73140 register(Command{Path: []string{"mr", "retarget"},
74 Summary: "retarget onto another branch",
75 Usage: "mr retarget <owner/name> <n> <branch>", Run: runMRRetarget})
141 Summary: "retarget onto another branch",
142 Usage: "mr retarget <owner/name> <n> <branch>",
143 Examples: []string{"mr retarget krz/gitbay 431 main"},
144 Run: runMRRetarget})
76145 register(Command{Path: []string{"mr", "comment"},
77 Summary: "comment",
78 Usage: "mr comment <owner/name> <n> [--message <m> | --file -] [--format md|org]",
146 Summary: "comment",
147 Usage: "mr comment <owner/name> <n> [--message <m> | --file -] [--format md|org]",
148 Flags: []Flag{
149 {"--message", "<m>", "the comment's text", ""},
150 {"--file", "-", "read the comment from stdin", ""},
151 {"--format", "md|org", "the comment's markup", "md"},
152 },
153 Examples: []string{`mr comment krz/gitbay 431 --message "looks good"`},
79154 ReadsStdin: true, Run: runMRComment})
80155 register(Command{Path: []string{"mr", "review"},
81156 Summary: "review",
82 Usage: "mr review <owner/name> <n> --approve|--request-changes|--comment|--discard", Run: runMRReview})
157 Usage: "mr review <owner/name> <n> --approve|--request-changes|--comment|--discard",
158 Flags: []Flag{
159 {"--approve", "", "approve the merge request", ""},
160 {"--request-changes", "", "ask for changes", ""},
161 {"--comment", "", "submit pending diff comments without a verdict", ""},
162 {"--discard", "", "throw away pending diff comments", ""},
163 },
164 Examples: []string{"mr review krz/gitbay 431 --approve"},
165 Run: runMRReview})
83166 register(Command{Path: []string{"mr", "review", "request"},
84167 Summary: "ask specific people for a review",
85 Usage: "mr review request <owner/name> <n> [--add <user>]... [--remove <user>]...", Run: runMRReviewRequest})
168 Usage: "mr review request <owner/name> <n> [--add <user>]... [--remove <user>]...",
169 Flags: []Flag{
170 {"--add", "<user>", "reviewer to add, may repeat", ""},
171 {"--remove", "<user>", "reviewer to remove, may repeat", ""},
172 },
173 Examples: []string{"mr review request krz/gitbay 431 --add cmc"},
174 Run: runMRReviewRequest})
86175 register(Command{Path: []string{"mr", "label"},
87176 Summary: "labels",
88 Usage: "mr label <owner/name> <n> [--add <l>]... [--remove <l>]...", Run: runMRLabel})
177 Usage: "mr label <owner/name> <n> [--add <l>]... [--remove <l>]...",
178 Flags: []Flag{
179 {"--add", "<l>", "label to add, may repeat", ""},
180 {"--remove", "<l>", "label to remove, may repeat", ""},
181 },
182 Examples: []string{"mr label krz/gitbay 431 --add needs-review"},
183 Run: runMRLabel})
89184 register(Command{Path: []string{"mr", "merge"},
90185 Summary: "merge",
91 Usage: "mr merge <owner/name> <n> [--strategy ff|merge|squash|rebase]", Run: runMRMerge})
186 Usage: "mr merge <owner/name> <n> [--strategy ff|merge|squash|rebase]",
187 Flags: []Flag{
188 {"--strategy", "ff|merge|squash|rebase", "how to merge", ""},
189 },
190 Examples: []string{"mr merge krz/gitbay 431 --strategy ff"},
191 Run: runMRMerge})
92192 register(Command{Path: []string{"mr", "close"},
93193 Summary: "close without merging",
94 Usage: "mr close <owner/name> <n> [--by <m>]", Run: runMRClose})
194 Usage: "mr close <owner/name> <n> [--by <m>]",
195 Flags: []Flag{
196 {"--by", "<m>", "the MR that supersedes this one", ""},
197 },
198 Examples: []string{"mr close krz/gitbay 431"},
199 Run: runMRClose})
95200}
96201
97202// ForkOut is what `repo fork` emits: where the fork landed, and what it
internal/control/notifications.go +12 −6
@@ -48,14 +48,20 @@ func init() {
4848 Summary: "activity on your registered devices as well as the inbox",
4949 Usage: "notifications settings push on|off", Run: runNotificationsSettingsPush})
5050 register(Command{Path: []string{"repo", "watch"},
51 Summary: "hear about all activity on a repository",
52 Usage: "repo watch <owner/name>", Run: runRepoWatch})
51 Summary: "hear about all activity on a repository",
52 Usage: "repo watch <owner/name>",
53 Examples: []string{"repo watch krz/gitbay"},
54 Run: runRepoWatch})
5355 register(Command{Path: []string{"repo", "unwatch"},
54 Summary: "back to the default: only work you are part of",
55 Usage: "repo unwatch <owner/name>", Run: runRepoUnwatch})
56 Summary: "back to the default: only work you are part of",
57 Usage: "repo unwatch <owner/name>",
58 Examples: []string{"repo unwatch krz/gitbay"},
59 Run: runRepoUnwatch})
5660 register(Command{Path: []string{"repo", "mute"},
57 Summary: "mute a repository, including work you are part of",
58 Usage: "repo mute <owner/name>", Run: runRepoMute})
61 Summary: "mute a repository, including work you are part of",
62 Usage: "repo mute <owner/name>",
63 Examples: []string{"repo mute krz/gitbay"},
64 Run: runRepoMute})
5965}
6066
6167// notice is one thing that happened, in the shape both delivery routes
internal/control/orglabel.go +35 −11
@@ -13,25 +13,49 @@ import (
1313func init() {
1414 register(Command{Path: []string{"org", "label", "set"},
1515 Summary: "create an org label every org repository sees, or set its colour; folds in same-named repo labels",
16 Usage: "org label set <org> <label> [--color rrggbb|'']", Run: runOrgLabelSet})
16 Usage: "org label set <org> <label> [--color rrggbb|'']",
17 Flags: []Flag{
18 {"--color", "rrggbb|''", "the label's colour, or '' to clear it", ""},
19 },
20 Examples: []string{"org label set krz bug --color d73a4a"},
21 Run: runOrgLabelSet})
1722 register(Command{Path: []string{"org", "label", "list"},
18 Summary: "list an org's labels with use across the repositories you can read",
19 Usage: "org label list <org>", ReadOnly: true, Run: runOrgLabelList})
23 Summary: "list an org's labels with use across the repositories you can read",
24 Usage: "org label list <org>",
25 Examples: []string{"org label list krz"},
26 ReadOnly: true, Run: runOrgLabelList})
2027 register(Command{Path: []string{"org", "label", "remove"},
21 Summary: "remove an org label from the org and from every issue under it",
22 Usage: "org label remove <org> <label>", Run: runOrgLabelRemove})
28 Summary: "remove an org label from the org and from every issue under it",
29 Usage: "org label remove <org> <label>",
30 Examples: []string{"org label remove krz wontfix"},
31 Run: runOrgLabelRemove})
2332 register(Command{Path: []string{"org", "milestone", "create"},
2433 Summary: "create an org milestone spanning every org repository; folds in same-titled repo milestones",
25 Usage: "org milestone create <org> <title> [--description <d>] [--due YYYY-MM-DD]", Run: runOrgMilestoneCreate})
34 Usage: "org milestone create <org> <title> [--description <d>] [--due YYYY-MM-DD]",
35 Flags: []Flag{
36 {"--description", "<d>", "what the milestone covers", ""},
37 {"--due", "YYYY-MM-DD", "target date", ""},
38 },
39 Examples: []string{"org milestone create krz mobile --due 2026-12-01"},
40 Run: runOrgMilestoneCreate})
2641 register(Command{Path: []string{"org", "milestone", "list"},
2742 Summary: "list an org's milestones with progress across the repositories you can read",
28 Usage: "org milestone list <org> [--state open|closed|all]", ReadOnly: true, Run: runOrgMilestoneList})
43 Usage: "org milestone list <org> [--state open|closed|all]",
44 Flags: []Flag{
45 {"--state", "open|closed|all", "which milestones", "open"},
46 },
47 Examples: []string{"org milestone list krz --state all"},
48 ReadOnly: true, Run: runOrgMilestoneList})
2949 register(Command{Path: []string{"org", "milestone", "close"},
30 Summary: "close an org milestone",
31 Usage: "org milestone close <org> <title>", Run: runOrgMilestoneClose})
50 Summary: "close an org milestone",
51 Usage: "org milestone close <org> <title>",
52 Examples: []string{"org milestone close krz mobile"},
53 Run: runOrgMilestoneClose})
3254 register(Command{Path: []string{"org", "milestone", "reopen"},
33 Summary: "reopen an org milestone",
34 Usage: "org milestone reopen <org> <title>", Run: runOrgMilestoneReopen})
55 Summary: "reopen an org milestone",
56 Usage: "org milestone reopen <org> <title>",
57 Examples: []string{"org milestone reopen krz mobile"},
58 Run: runOrgMilestoneReopen})
3559}
3660
3761// orgReader resolves an org for a read of its labels or milestones.
internal/control/pagescmd.go +16 −8
@@ -20,17 +20,25 @@ import (
2020
2121func init() {
2222 register(Command{Path: []string{"repo", "domain", "add"},
23 Summary: "claim a custom pages domain (verify with a DNS TXT record)",
24 Usage: "repo domain add <owner/name> <domain>", Run: runDomainAdd})
23 Summary: "claim a custom pages domain (verify with a DNS TXT record)",
24 Usage: "repo domain add <owner/name> <domain>",
25 Examples: []string{"repo domain add krz/gitbay gitbay.org"},
26 Run: runDomainAdd})
2527 register(Command{Path: []string{"repo", "domain", "verify"},
26 Summary: "check the DNS challenge and activate a claim",
27 Usage: "repo domain verify <owner/name> <domain>", Run: runDomainVerify})
28 Summary: "check the DNS challenge and activate a claim",
29 Usage: "repo domain verify <owner/name> <domain>",
30 Examples: []string{"repo domain verify krz/gitbay gitbay.org"},
31 Run: runDomainVerify})
2832 register(Command{Path: []string{"repo", "domain", "remove"},
29 Summary: "remove a custom pages domain",
30 Usage: "repo domain remove <owner/name> <domain>", Run: runDomainRemove})
33 Summary: "remove a custom pages domain",
34 Usage: "repo domain remove <owner/name> <domain>",
35 Examples: []string{"repo domain remove krz/gitbay gitbay.org"},
36 Run: runDomainRemove})
3137 register(Command{Path: []string{"repo", "domain", "list"},
32 Summary: "list custom pages domains",
33 Usage: "repo domain list <owner/name>", ReadOnly: true, Run: runDomainList})
38 Summary: "list custom pages domains",
39 Usage: "repo domain list <owner/name>",
40 Examples: []string{"repo domain list krz/gitbay"},
41 ReadOnly: true, Run: runDomainList})
3442}
3543
3644// challengeLabel prefixes the domain for the ownership TXT record.
internal/control/read.go +24 −9
@@ -17,23 +17,37 @@ import (
1717
1818func init() {
1919 register(Command{
20 Path: []string{"repo", "tree"},
21 Summary: "list a directory",
22 Usage: "repo tree <owner/name> [<path>] [--ref <ref>]",
20 Path: []string{"repo", "tree"},
21 Summary: "list a directory",
22 Usage: "repo tree <owner/name> [<path>] [--ref <ref>]",
23 Flags: []Flag{
24 {"--ref", "<ref>", "branch, tag or commit to read", "the default branch"},
25 },
26 Examples: []string{"repo tree krz/gitbay internal/control"},
2327 ReadOnly: true,
2428 Run: runRepoTree,
2529 })
2630 register(Command{
27 Path: []string{"repo", "cat"},
28 Summary: "read a file",
29 Usage: "repo cat <owner/name> <path> [--ref <ref>]",
31 Path: []string{"repo", "cat"},
32 Summary: "read a file",
33 Usage: "repo cat <owner/name> <path> [--ref <ref>]",
34 Flags: []Flag{
35 {"--ref", "<ref>", "branch, tag or commit to read", "the default branch"},
36 },
37 Examples: []string{"repo cat krz/gitbay internal/control/control.go"},
3038 ReadOnly: true,
3139 Run: runRepoCat,
3240 })
3341 register(Command{
34 Path: []string{"repo", "blame"},
35 Summary: "attribute lines to commits",
36 Usage: "repo blame <owner/name> <path> [--ref <ref>] [--from <n>] [--to <n>]",
42 Path: []string{"repo", "blame"},
43 Summary: "attribute lines to commits",
44 Usage: "repo blame <owner/name> <path> [--ref <ref>] [--from <n>] [--to <n>]",
45 Flags: []Flag{
46 {"--ref", "<ref>", "branch, tag or commit to read", "the default branch"},
47 {"--from", "<n>", "first line to attribute", "1"},
48 {"--to", "<n>", "last line to attribute", "the file's last line"},
49 },
50 Examples: []string{"repo blame krz/gitbay internal/control/control.go --from 1 --to 40"},
3751 ReadOnly: true,
3852 Run: runRepoBlame,
3953 })
@@ -41,6 +55,7 @@ func init() {
4155 Path: []string{"repo", "refs"},
4256 Summary: "list branches and tags",
4357 Usage: "repo refs <owner/name>",
58 Examples: []string{"repo refs krz/gitbay"},
4459 ReadOnly: true,
4560 Run: runRepoRefs,
4661 })
internal/control/release.go +44 −10
@@ -20,33 +20,67 @@ import (
2020
2121func init() {
2222 register(Command{Path: []string{"release", "create"},
23 Summary: "create a release on a tag",
24 Usage: "release create <owner/name> <tag> [--title <t>] [--notes <n> | --file -] [--format md|org]",
23 Summary: "create a release on a tag",
24 Usage: "release create <owner/name> <tag> [--title <t>] [--notes <n> | --file -] [--format md|org]",
25 Flags: []Flag{
26 {"--title", "<t>", "the release's title", "the tag"},
27 {"--notes", "<n>", "the release notes", ""},
28 {"--file", "-", "read the release notes from stdin", ""},
29 {"--format", "md|org", "the notes' markup", "md"},
30 },
31 Examples: []string{
32 `release create krz/gitbay v1.31.0 --title "v1.31.0" --notes "flag help"`,
33 "release create krz/gitbay v1.31.0 --file - '< notes.md'",
34 },
2535 ReadsStdin: true, Run: runReleaseCreate})
2636 register(Command{Path: []string{"release", "edit"},
27 Summary: "update a release's title and notes",
28 Usage: "release edit <owner/name> <tag> [--title <t>] [--notes <n> | --file -] [--format md|org]",
37 Summary: "update a release's title and notes",
38 Usage: "release edit <owner/name> <tag> [--title <t>] [--notes <n> | --file -] [--format md|org]",
39 Flags: []Flag{
40 {"--title", "<t>", "the release's new title", ""},
41 {"--notes", "<n>", "the release's new notes", ""},
42 {"--file", "-", "read the new release notes from stdin", ""},
43 {"--format", "md|org", "the notes' markup", ""},
44 },
45 Examples: []string{`release edit krz/gitbay v1.31.0 --title "v1.31.0"`},
2946 ReadsStdin: true, Run: runReleaseEdit})
3047 register(Command{Path: []string{"release", "list"},
3148 Summary: "list releases",
32 Usage: "release list <owner/name> [--limit <n>] [--cursor <c>]", ReadOnly: true, Run: runReleaseList})
49 Usage: "release list <owner/name> [--limit <n>] [--cursor <c>]",
50 Flags: []Flag{
51 {"--limit", "<n>", "rows per page", ""},
52 {"--cursor", "<c>", "continue from the previous page", ""},
53 },
54 Examples: []string{"release list krz/gitbay --limit 10"},
55 ReadOnly: true, Run: runReleaseList})
3356 register(Command{Path: []string{"release", "show"},
34 Summary: "show a release with assets",
35 Usage: "release show <owner/name> <tag>", ReadOnly: true, Run: runReleaseShow})
57 Summary: "show a release with assets",
58 Usage: "release show <owner/name> <tag>",
59 Examples: []string{"release show krz/gitbay v1.30.0"},
60 ReadOnly: true, Run: runReleaseShow})
3661 register(Command{Path: []string{"release", "delete"},
3762 Summary: "delete a release and its assets",
38 Usage: "release delete <owner/name> <tag> --yes", Run: runReleaseDelete})
63 Usage: "release delete <owner/name> <tag> --yes",
64 Flags: []Flag{
65 {"--yes", "", "confirm the permanent delete", ""},
66 },
67 Examples: []string{"release delete krz/gitbay v1.30.0 --yes"},
68 Run: runReleaseDelete})
3969 register(Command{Path: []string{"release", "asset", "add"},
4070 Summary: "upload an asset from stdin",
4171 Usage: "release asset add <owner/name> <tag> <filename> < file",
72 Examples: []string{"release asset add krz/gitbay v1.30.0 gitbay-darwin-arm64 '< gitbay-darwin-arm64'"},
4273 ReadsStdin: true, Run: runAssetAdd})
4374 register(Command{Path: []string{"release", "asset", "get"},
4475 Summary: "write an asset to stdout",
4576 Usage: "release asset get <owner/name> <tag> <filename> > file",
77 Examples: []string{"release asset get krz/gitbay v1.30.0 gitbay-darwin-arm64 '> gitbay-darwin-arm64'"},
4678 ReadOnly: true, Run: runAssetGet})
4779 register(Command{Path: []string{"release", "asset", "remove"},
48 Summary: "remove an asset",
49 Usage: "release asset remove <owner/name> <tag> <filename>", Run: runAssetRemove})
80 Summary: "remove an asset",
81 Usage: "release asset remove <owner/name> <tag> <filename>",
82 Examples: []string{"release asset remove krz/gitbay v1.30.0 gitbay-darwin-arm64"},
83 Run: runAssetRemove})
5084}
5185
5286var assetNamePat = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._+-]{0,199}$`)
internal/control/repo.go +137 −60
@@ -28,100 +28,177 @@ func HooksDir(root string) string { return filepath.Join(root, "hooks") }
2828func init() {
2929 register(Command{Path: []string{"repo", "create"},
3030 Summary: "create a repository",
31 Usage: "repo create <owner/name> [--private]", Run: runRepoCreate})
31 Usage: "repo create <owner/name> [--private]",
32 Flags: []Flag{
33 {"--private", "", "create it private", ""},
34 },
35 Examples: []string{"repo create krz/newthing --private"},
36 Run: runRepoCreate})
3237 register(Command{Path: []string{"repo", "list"},
3338 Summary: "list repositories you own or can access",
34 Usage: "repo list [--limit <n>] [--cursor <c>]", ReadOnly: true, Run: runRepoList})
39 Usage: "repo list [--limit <n>] [--cursor <c>]",
40 Flags: []Flag{
41 {"--limit", "<n>", "rows per page", ""},
42 {"--cursor", "<c>", "continue from the previous page", ""},
43 },
44 Examples: []string{"repo list --limit 20"},
45 ReadOnly: true, Run: runRepoList})
3546 register(Command{Path: []string{"repo", "show"},
36 Summary: "show repository details",
37 Usage: "repo show <owner/name>", ReadOnly: true, Run: runRepoShow})
47 Summary: "show repository details",
48 Usage: "repo show <owner/name>",
49 Examples: []string{"repo show krz/gitbay"},
50 ReadOnly: true, Run: runRepoShow})
3851 register(Command{Path: []string{"repo", "transfer"},
39 Summary: "move a repository to another owner",
40 Usage: "repo transfer <owner/name> <new-owner> (clone URLs change)", Run: runRepoTransfer})
52 Summary: "move a repository to another owner",
53 Usage: "repo transfer <owner/name> <new-owner> (clone URLs change)",
54 Examples: []string{"repo transfer krz/gitbay krazywarez"},
55 Run: runRepoTransfer})
4156 register(Command{Path: []string{"repo", "rename"},
42 Summary: "rename a repository",
43 Usage: "repo rename <owner/name> <new-name> (clone URLs change)", Run: runRepoRename})
57 Summary: "rename a repository",
58 Usage: "repo rename <owner/name> <new-name> (clone URLs change)",
59 Examples: []string{"repo rename krz/gitbay forge"},
60 Run: runRepoRename})
4461 register(Command{Path: []string{"repo", "delete"},
4562 Summary: "delete a repository",
46 Usage: "repo delete <owner/name> --yes", Run: runRepoDelete})
63 Usage: "repo delete <owner/name> --yes",
64 Flags: []Flag{
65 {"--yes", "", "confirm the permanent delete", ""},
66 },
67 Examples: []string{"repo delete cmc/scratch --yes"},
68 Run: runRepoDelete})
4769 register(Command{Path: []string{"repo", "access", "grant"},
48 Summary: "grant access",
49 Usage: "repo access grant <owner/name> <user> read|write|admin", Run: runAccessGrant})
70 Summary: "grant access",
71 Usage: "repo access grant <owner/name> <user> read|write|admin",
72 Examples: []string{"repo access grant krz/gitbay cmc write"},
73 Run: runAccessGrant})
5074 register(Command{Path: []string{"repo", "access", "revoke"},
51 Summary: "revoke access",
52 Usage: "repo access revoke <owner/name> <user>", Run: runAccessRevoke})
75 Summary: "revoke access",
76 Usage: "repo access revoke <owner/name> <user>",
77 Examples: []string{"repo access revoke krz/gitbay cmc"},
78 Run: runAccessRevoke})
5379 register(Command{Path: []string{"repo", "access", "list"},
54 Summary: "list who can reach the repository, with the role and where it comes from",
55 Usage: "repo access list <owner/name>", ReadOnly: true, Run: runAccessList})
80 Summary: "list who can reach the repository, with the role and where it comes from",
81 Usage: "repo access list <owner/name>",
82 Examples: []string{"repo access list krz/gitbay"},
83 ReadOnly: true, Run: runAccessList})
5684 register(Command{Path: []string{"repo", "settings", "show"},
57 Summary: "show settings",
58 Usage: "repo settings show <owner/name>", ReadOnly: true, Run: runSettingsShow})
85 Summary: "show settings",
86 Usage: "repo settings show <owner/name>",
87 Examples: []string{"repo settings show krz/gitbay"},
88 ReadOnly: true, Run: runSettingsShow})
5989 register(Command{Path: []string{"repo", "settings", "protect"},
60 Summary: "protect a branch",
61 Usage: "repo settings protect <owner/name> <branch>", Run: runProtect})
90 Summary: "protect a branch",
91 Usage: "repo settings protect <owner/name> <branch>",
92 Examples: []string{"repo settings protect krz/gitbay main"},
93 Run: runProtect})
6294 register(Command{Path: []string{"repo", "settings", "unprotect"},
63 Summary: "unprotect a branch",
64 Usage: "repo settings unprotect <owner/name> <branch>", Run: runUnprotect})
95 Summary: "unprotect a branch",
96 Usage: "repo settings unprotect <owner/name> <branch>",
97 Examples: []string{"repo settings unprotect krz/gitbay main"},
98 Run: runUnprotect})
6599 register(Command{Path: []string{"repo", "settings", "protect-tag"},
66 Summary: "protect tags matching a glob (created once, never moved or deleted)",
67 Usage: "repo settings protect-tag <owner/name> <glob>", Run: runProtectTag})
100 Summary: "protect tags matching a glob (created once, never moved or deleted)",
101 Usage: "repo settings protect-tag <owner/name> <glob>",
102 Examples: []string{"repo settings protect-tag krz/gitbay 'v*'"},
103 Run: runProtectTag})
68104 register(Command{Path: []string{"repo", "settings", "unprotect-tag"},
69 Summary: "drop a protected-tag glob",
70 Usage: "repo settings unprotect-tag <owner/name> <glob>", Run: runUnprotectTag})
105 Summary: "drop a protected-tag glob",
106 Usage: "repo settings unprotect-tag <owner/name> <glob>",
107 Examples: []string{"repo settings unprotect-tag krz/gitbay 'v*'"},
108 Run: runUnprotectTag})
71109 register(Command{Path: []string{"repo", "settings", "description"},
72 Summary: "set the repository description",
73 Usage: "repo settings description <owner/name> <text> ('' clears)", Run: runSetDescription})
110 Summary: "set the repository description",
111 Usage: "repo settings description <owner/name> <text> ('' clears)",
112 Examples: []string{`repo settings description krz/gitbay "a CLI-first git forge"`},
113 Run: runSetDescription})
74114 register(Command{Path: []string{"repo", "settings", "visibility"},
75 Summary: "set repository visibility",
76 Usage: "repo settings visibility <owner/name> public|private", Run: runSetVisibility})
115 Summary: "set repository visibility",
116 Usage: "repo settings visibility <owner/name> public|private",
117 Examples: []string{"repo settings visibility krz/gitbay public"},
118 Run: runSetVisibility})
77119 register(Command{Path: []string{"repo", "settings", "website"},
78 Summary: "set the repository website",
79 Usage: "repo settings website <owner/name> <url> ('' clears)", Run: runSetWebsite})
120 Summary: "set the repository website",
121 Usage: "repo settings website <owner/name> <url> ('' clears)",
122 Examples: []string{"repo settings website krz/gitbay https://gitbay.org"},
123 Run: runSetWebsite})
80124 register(Command{Path: []string{"repo", "settings", "default-branch"},
81 Summary: "set the default branch",
82 Usage: "repo settings default-branch <owner/name> <branch>", Run: runSetDefaultBranch})
125 Summary: "set the default branch",
126 Usage: "repo settings default-branch <owner/name> <branch>",
127 Examples: []string{"repo settings default-branch krz/gitbay main"},
128 Run: runSetDefaultBranch})
83129 register(Command{Path: []string{"repo", "settings", "git-daemon"},
84 Summary: "expose over git://",
85 Usage: "repo settings git-daemon <owner/name> on|off", Run: runGitDaemon})
130 Summary: "expose over git://",
131 Usage: "repo settings git-daemon <owner/name> on|off",
132 Examples: []string{"repo settings git-daemon krz/gitbay on"},
133 Run: runGitDaemon})
86134 register(Command{Path: []string{"repo", "archive"},
87 Summary: "archive a repository (read-only: pushes and issue/MR writes refused)",
88 Usage: "repo archive <owner/name>", Run: runArchive})
135 Summary: "archive a repository (read-only: pushes and issue/MR writes refused)",
136 Usage: "repo archive <owner/name>",
137 Examples: []string{"repo archive krz/gitbay"},
138 Run: runArchive})
89139 register(Command{Path: []string{"repo", "unarchive"},
90 Summary: "unarchive a repository",
91 Usage: "repo unarchive <owner/name>", Run: runUnarchive})
140 Summary: "unarchive a repository",
141 Usage: "repo unarchive <owner/name>",
142 Examples: []string{"repo unarchive krz/gitbay"},
143 Run: runUnarchive})
92144 register(Command{Path: []string{"repo", "topics"},
93 Summary: "list topics",
94 Usage: "repo topics <owner/name>", ReadOnly: true, Run: runTopicsList})
145 Summary: "list topics",
146 Usage: "repo topics <owner/name>",
147 Examples: []string{"repo topics krz/gitbay"},
148 ReadOnly: true, Run: runTopicsList})
95149 register(Command{Path: []string{"repo", "topics", "add"},
96 Summary: "add topics",
97 Usage: "repo topics add <owner/name> <topic>...", Run: runTopicsAdd})
150 Summary: "add topics",
151 Usage: "repo topics add <owner/name> <topic>...",
152 Examples: []string{"repo topics add krz/gitbay git forge cli"},
153 Run: runTopicsAdd})
98154 register(Command{Path: []string{"repo", "topics", "remove"},
99 Summary: "remove topics",
100 Usage: "repo topics remove <owner/name> <topic>...", Run: runTopicsRemove})
155 Summary: "remove topics",
156 Usage: "repo topics remove <owner/name> <topic>...",
157 Examples: []string{"repo topics remove krz/gitbay cli"},
158 Run: runTopicsRemove})
101159 register(Command{Path: []string{"repo", "search"},
102 Summary: "find repositories by name, description, or topic",
103 Usage: "repo search <query>", ReadOnly: true, Run: runRepoSearch})
160 Summary: "find repositories by name, description, or topic",
161 Usage: "repo search <query>",
162 Examples: []string{"repo search forge"},
163 ReadOnly: true, Run: runRepoSearch})
104164 register(Command{Path: []string{"repo", "grep"},
105165 Summary: "search file contents",
106 Usage: "repo grep <owner/name> <query> [--ref <ref>]", ReadOnly: true, Run: runRepoGrep})
166 Usage: "repo grep <owner/name> <query> [--ref <ref>]",
167 Flags: []Flag{
168 {"--ref", "<ref>", "branch, tag or commit to search", "the default branch"},
169 },
170 Examples: []string{"repo grep krz/gitbay TODO"},
171 ReadOnly: true, Run: runRepoGrep})
107172 register(Command{Path: []string{"repo", "diff"},
108 Summary: "the patch between two refs, from their merge base",
109 Usage: "repo diff <owner/name> <base> <head>", ReadOnly: true, Run: runRepoDiff})
173 Summary: "the patch between two refs, from their merge base",
174 Usage: "repo diff <owner/name> <base> <head>",
175 Examples: []string{"repo diff krz/gitbay main cli-output-help"},
176 ReadOnly: true, Run: runRepoDiff})
110177 register(Command{Path: []string{"repo", "pin"},
111 Summary: "pin a repository to your dashboard",
112 Usage: "repo pin <owner/name>", Run: runRepoPin})
178 Summary: "pin a repository to your dashboard",
179 Usage: "repo pin <owner/name>",
180 Examples: []string{"repo pin krz/gitbay"},
181 Run: runRepoPin})
113182 register(Command{Path: []string{"repo", "unpin"},
114 Summary: "unpin a repository",
115 Usage: "repo unpin <owner/name>", Run: runRepoUnpin})
183 Summary: "unpin a repository",
184 Usage: "repo unpin <owner/name>",
185 Examples: []string{"repo unpin krz/gitbay"},
186 Run: runRepoUnpin})
116187 register(Command{Path: []string{"repo", "bookmark"},
117 Summary: "bookmark a repository to come back to",
118 Usage: "repo bookmark <owner/name>", Run: runRepoBookmark})
188 Summary: "bookmark a repository to come back to",
189 Usage: "repo bookmark <owner/name>",
190 Examples: []string{"repo bookmark krz/gitbay"},
191 Run: runRepoBookmark})
119192 register(Command{Path: []string{"repo", "unbookmark"},
120 Summary: "remove a bookmark",
121 Usage: "repo unbookmark <owner/name>", Run: runRepoUnbookmark})
193 Summary: "remove a bookmark",
194 Usage: "repo unbookmark <owner/name>",
195 Examples: []string{"repo unbookmark krz/gitbay"},
196 Run: runRepoUnbookmark})
122197 register(Command{Path: []string{"repo", "bookmarks"},
123 Summary: "list the repositories you have bookmarked",
124 Usage: "repo bookmarks", ReadOnly: true, Run: runRepoBookmarks})
198 Summary: "list the repositories you have bookmarked",
199 Usage: "repo bookmarks",
200 Examples: []string{"repo bookmarks"},
201 ReadOnly: true, Run: runRepoBookmarks})
125202}
126203
127204const (
internal/control/runnerrepo.go +9 −4
@@ -21,13 +21,18 @@ func init() {
2121 register(Command{Path: []string{"repo", "runner", "add"},
2222 Summary: "attach a runner's public key to a repository",
2323 Usage: "repo runner add <owner/name> < key.pub",
24 Examples: []string{"repo runner add krz/gitbay '< key.pub'"},
2425 ReadsStdin: true, Run: runRepoRunnerAdd})
2526 register(Command{Path: []string{"repo", "runner", "list"},
26 Summary: "list the runners attached to a repository",
27 Usage: "repo runner list <owner/name>", ReadOnly: true, Run: runRepoRunnerList})
27 Summary: "list the runners attached to a repository",
28 Usage: "repo runner list <owner/name>",
29 Examples: []string{"repo runner list krz/gitbay"},
30 ReadOnly: true, Run: runRepoRunnerList})
2831 register(Command{Path: []string{"repo", "runner", "remove"},
29 Summary: "detach a runner from a repository",
30 Usage: "repo runner remove <owner/name> <fingerprint>", Run: runRepoRunnerRemove})
32 Summary: "detach a runner from a repository",
33 Usage: "repo runner remove <owner/name> <fingerprint>",
34 Examples: []string{"repo runner remove krz/gitbay SHA256:abcd1234"},
35 Run: runRepoRunnerRemove})
3136}
3237
3338func runRepoRunnerAdd(c *Ctx, args []string) int {
internal/control/search.go +9 −2
@@ -12,8 +12,15 @@ import (
1212
1313func init() {
1414 register(Command{Path: []string{"search"},
15 Summary: "find repositories, issues and merge requests across the instance",
16 Usage: "search <query> [--kind repo|issue|mr]",
15 Summary: "find repositories, issues and merge requests across the instance",
16 Usage: "search <query> [--kind repo|issue|mr]",
17 Flags: []Flag{
18 {"--kind", "repo|issue|mr", "only this kind of result, may repeat", ""},
19 },
20 Examples: []string{
21 "search auth bug",
22 "search auth bug --kind issue",
23 },
1724 ReadOnly: true, Run: runSearch})
1825}
1926
internal/control/sig.go +9 −1
@@ -29,10 +29,18 @@ func init() {
2929 register(Command{Path: []string{"repo", "commit"},
3030 Summary: "show one commit with its patch",
3131 Usage: "repo commit <owner/name> <sha>",
32 Examples: []string{"repo commit krz/gitbay a1b2c3d"},
3233 ReadOnly: true, Run: runRepoCommit})
3334 register(Command{Path: []string{"repo", "log"},
3435 Summary: "commit log with signature states",
35 Usage: "repo log <owner/name> [--ref <r>] [--limit n] [--path <file>]", ReadOnly: true, Run: runRepoLog})
36 Usage: "repo log <owner/name> [--ref <r>] [--limit n] [--path <file>]",
37 Flags: []Flag{
38 {"--ref", "<r>", "branch, tag or commit to start from", "the default branch"},
39 {"--limit", "n", "rows to show", "30"},
40 {"--path", "<file>", "only commits touching this path", ""},
41 },
42 Examples: []string{"repo log krz/gitbay --limit 10"},
43 ReadOnly: true, Run: runRepoLog})
3644}
3745
3846func runPGPAdd(c *Ctx, args []string) int {
internal/control/snippet.go +38 −12
@@ -19,31 +19,57 @@ const maxSnippetFiles = 64
1919
2020func init() {
2121 register(Command{Path: []string{"snippet", "create"},
22 Summary: "create a snippet from one file on stdin",
23 Usage: "snippet create <filename> [--description <d>] [--visibility public|unlisted|private] < file",
22 Summary: "create a snippet from one file on stdin",
23 Usage: "snippet create <filename> [--description <d>] [--visibility public|unlisted|private] < file",
24 Flags: []Flag{
25 {"--description", "<d>", "one line about the snippet", ""},
26 {"--visibility", "public|unlisted|private", "who can find it", "unlisted"},
27 },
28 Examples: []string{"snippet create notes.md --visibility private '< notes.md'"},
2429 ReadsStdin: true, Run: runSnippetCreate})
2530 register(Command{Path: []string{"snippet", "show"},
26 Summary: "show a snippet's metadata and files",
27 Usage: "snippet show <id>", ReadOnly: true, Run: runSnippetShow})
31 Summary: "show a snippet's metadata and files",
32 Usage: "snippet show <id>",
33 Examples: []string{"snippet show a1b2c3"},
34 ReadOnly: true, Run: runSnippetShow})
2835 register(Command{Path: []string{"snippet", "list"},
2936 Summary: "list your snippets, or an owner's public ones",
30 Usage: "snippet list [<owner>] [--limit n] [--cursor c]", ReadOnly: true, Run: runSnippetList})
37 Usage: "snippet list [<owner>] [--limit n] [--cursor c]",
38 Flags: []Flag{
39 {"--limit", "n", "rows per page", ""},
40 {"--cursor", "c", "continue from the previous page", ""},
41 },
42 Examples: []string{"snippet list cmc"},
43 ReadOnly: true, Run: runSnippetList})
3144 register(Command{Path: []string{"snippet", "edit"},
3245 Summary: "change a snippet's description or visibility",
33 Usage: "snippet edit <id> [--description <d>] [--visibility public|unlisted|private]", Run: runSnippetEdit})
46 Usage: "snippet edit <id> [--description <d>] [--visibility public|unlisted|private]",
47 Flags: []Flag{
48 {"--description", "<d>", "one line about the snippet", ""},
49 {"--visibility", "public|unlisted|private", "who can find it", ""},
50 },
51 Examples: []string{"snippet edit a1b2c3 --visibility public"},
52 Run: runSnippetEdit})
3453 register(Command{Path: []string{"snippet", "delete"},
35 Summary: "delete a snippet and its files",
36 Usage: "snippet delete <id>", Run: runSnippetDelete})
54 Summary: "delete a snippet and its files",
55 Usage: "snippet delete <id>",
56 Examples: []string{"snippet delete a1b2c3"},
57 Run: runSnippetDelete})
3758 register(Command{Path: []string{"snippet", "file", "set"},
3859 Summary: "add a file to a snippet, or replace one, from stdin",
3960 Usage: "snippet file set <id> <filename> < file",
61 Examples: []string{"snippet file set a1b2c3 notes.md '< notes.md'"},
4062 ReadsStdin: true, Run: runSnippetFileSet})
4163 register(Command{Path: []string{"snippet", "file", "get"},
42 Summary: "write a snippet file to stdout",
43 Usage: "snippet file get <id> <filename> > file", ReadOnly: true, Run: runSnippetFileGet})
64 Summary: "write a snippet file to stdout",
65 Usage: "snippet file get <id> <filename> > file",
66 Examples: []string{"snippet file get a1b2c3 notes.md '> notes.md'"},
67 ReadOnly: true, Run: runSnippetFileGet})
4468 register(Command{Path: []string{"snippet", "file", "remove"},
45 Summary: "remove a file from a snippet",
46 Usage: "snippet file remove <id> <filename>", Run: runSnippetFileRemove})
69 Summary: "remove a file from a snippet",
70 Usage: "snippet file remove <id> <filename>",
71 Examples: []string{"snippet file remove a1b2c3 notes.md"},
72 Run: runSnippetFileRemove})
4773}
4874
4975type SnippetFileOut struct {
internal/control/status.go +14 −3
@@ -15,10 +15,21 @@ func init() {
1515 register(Command{Path: []string{"status", "set"},
1616 Summary: "report a commit status (CI)",
1717 Usage: "status set <owner/name> <sha> --context <c> --state pending|success|failure|error [--description <d>] [--url <u>]",
18 Run: runStatusSet})
18 Flags: []Flag{
19 {"--context", "<c>", "the check this status reports for", ""},
20 {"--state", "pending|success|failure|error", "the check's outcome", ""},
21 {"--description", "<d>", "short text shown beside the state", ""},
22 {"--url", "<u>", "link to the check's own output", ""},
23 },
24 Examples: []string{
25 "status set krz/gitbay a1b2c3d --context ci/build --state success",
26 },
27 Run: runStatusSet})
1928 register(Command{Path: []string{"status", "list"},
20 Summary: "statuses on a commit",
21 Usage: "status list <owner/name> <sha>", ReadOnly: true, Run: runStatusList})
29 Summary: "statuses on a commit",
30 Usage: "status list <owner/name> <sha>",
31 Examples: []string{"status list krz/gitbay a1b2c3d"},
32 ReadOnly: true, Run: runStatusList})
2233}
2334
2435var validStatusState = map[string]bool{"pending": true, "success": true, "failure": true, "error": true}
internal/control/wiki.go +2
@@ -18,6 +18,7 @@ func init() {
1818 Path: []string{"wiki", "list"},
1919 Summary: "list a repository's wiki pages",
2020 Usage: "wiki list <owner/name>",
21 Examples: []string{"wiki list krz/gitbay"},
2122 ReadOnly: true,
2223 Run: runWikiList,
2324 })
@@ -25,6 +26,7 @@ func init() {
2526 Path: []string{"wiki", "show"},
2627 Summary: "print a wiki page",
2728 Usage: "wiki show <owner/name> [<page>]",
29 Examples: []string{"wiki show krz/gitbay Quickstart"},
2830 ReadOnly: true,
2931 Run: runWikiShow,
3032 })