Commit c5be40147c

c5be40147c8aaa1d088caed9161f937d9b9eac62

parent: a9749f2107

Verified · cmc

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

control: every command's flags described, with examples

Ref #254
internal/control/admin.go +57 −27
@@ -16,59 +16,89 @@ import (
1616
1717func init() {
1818 register(Command{Path: []string{"admin", "user", "list"},
19 Summary: "list accounts (instance admins)",
20 Usage: "admin user list [--state active|pending|disabled|admin] [--limit <n>] [--cursor <c>]",
19 Summary: "list accounts (instance admins)",
20 Usage: "admin user list [--state active|pending|disabled|admin] [--limit <n>] [--cursor <c>]",
21 Flags: []Flag{
22 {"--state", "active|pending|disabled|admin", "which accounts", ""},
23 {"--limit", "<n>", "rows per page", ""},
24 {"--cursor", "<c>", "continue from the previous page", ""},
25 },
26 Examples: []string{"admin user list --state pending"},
2127 ReadOnly: true, Run: runAdminUserList})
2228 register(Command{Path: []string{"admin", "user", "show"},
2329 Summary: "show an account: keys, emails, orgs, tokens, sessions (instance admins)",
2430 Usage: "admin user show <username>",
31 Examples: []string{"admin user show alice"},
2532 ReadOnly: true, Run: runAdminUserShow})
2633 register(Command{Path: []string{"admin", "user", "promote"},
27 Summary: "make an account an instance admin",
28 Usage: "admin user promote <username>",
29 Run: runAdminUserPromote})
34 Summary: "make an account an instance admin",
35 Usage: "admin user promote <username>",
36 Examples: []string{"admin user promote alice"},
37 Run: runAdminUserPromote})
3038 register(Command{Path: []string{"admin", "user", "demote"},
31 Summary: "remove instance admin from an account (never the last one)",
32 Usage: "admin user demote <username>",
33 Run: runAdminUserDemote})
39 Summary: "remove instance admin from an account (never the last one)",
40 Usage: "admin user demote <username>",
41 Examples: []string{"admin user demote alice"},
42 Run: runAdminUserDemote})
3443 register(Command{Path: []string{"admin", "runners"},
3544 Summary: "the build queue and runner accounts: last poll, scope, the build each holds (instance admins)",
3645 Usage: "admin runners",
46 Examples: []string{"admin runners"},
3747 ReadOnly: true, Run: runAdminRunners})
3848 register(Command{Path: []string{"admin", "runners", "remove"},
39 Summary: "drop a key's runner heartbeat row, e.g. one that polled once by mistake (instance admins)",
40 Usage: "admin runners remove <fingerprint>",
41 Run: runAdminRunnersForget})
49 Summary: "drop a key's runner heartbeat row, e.g. one that polled once by mistake (instance admins)",
50 Usage: "admin runners remove <fingerprint>",
51 Examples: []string{"admin runners remove SHA256:abcd1234"},
52 Run: runAdminRunnersForget})
4253 // forget is the name this shipped under in v1.18; remove is the verb
4354 // every other noun uses. Both stay for one release.
4455 register(Command{Path: []string{"admin", "runners", "forget"},
45 Summary: "alias of admin runners remove",
46 Usage: "admin runners forget <fingerprint>",
47 Run: runAdminRunnersForget})
56 Summary: "alias of admin runners remove",
57 Usage: "admin runners forget <fingerprint>",
58 Examples: []string{"admin runners forget SHA256:abcd1234"},
59 Run: runAdminRunnersForget})
4860 register(Command{Path: []string{"admin", "repo", "list"},
49 Summary: "list every repository with size and last push (instance admins)",
50 Usage: "admin repo list [--owner <name>] [--visibility public|private] [--limit <n>] [--cursor <c>]",
61 Summary: "list every repository with size and last push (instance admins)",
62 Usage: "admin repo list [--owner <name>] [--visibility public|private] [--limit <n>] [--cursor <c>]",
63 Flags: []Flag{
64 {"--owner", "<name>", "only this owner's repositories", ""},
65 {"--visibility", "public|private", "which repositories", ""},
66 {"--limit", "<n>", "rows per page", ""},
67 {"--cursor", "<c>", "continue from the previous page", ""},
68 },
69 Examples: []string{"admin repo list --owner alice"},
5170 ReadOnly: true, Run: runAdminRepoList})
5271 register(Command{Path: []string{"admin", "repo", "archive"},
53 Summary: "archive any repository (instance admins; audited)",
54 Usage: "admin repo archive <owner/name>",
55 Run: runAdminRepoArchive})
72 Summary: "archive any repository (instance admins; audited)",
73 Usage: "admin repo archive <owner/name>",
74 Examples: []string{"admin repo archive alice/old-project"},
75 Run: runAdminRepoArchive})
5676 register(Command{Path: []string{"admin", "repo", "unarchive"},
57 Summary: "unarchive any repository (instance admins; audited)",
58 Usage: "admin repo unarchive <owner/name>",
59 Run: runAdminRepoUnarchive})
77 Summary: "unarchive any repository (instance admins; audited)",
78 Usage: "admin repo unarchive <owner/name>",
79 Examples: []string{"admin repo unarchive alice/old-project"},
80 Run: runAdminRepoUnarchive})
6081 register(Command{Path: []string{"admin", "repo", "visibility"},
61 Summary: "set any repository's visibility (instance admins; audited)",
62 Usage: "admin repo visibility <owner/name> public|private",
63 Run: runAdminRepoVisibility})
82 Summary: "set any repository's visibility (instance admins; audited)",
83 Usage: "admin repo visibility <owner/name> public|private",
84 Examples: []string{"admin repo visibility alice/secret private"},
85 Run: runAdminRepoVisibility})
6486 register(Command{Path: []string{"admin", "repo", "delete"},
6587 Summary: "delete any repository (instance admins; audited)",
6688 Usage: "admin repo delete <owner/name> --yes",
67 Run: runAdminRepoDelete})
89 Flags: []Flag{
90 {"--yes", "", "confirm the permanent delete", ""},
91 },
92 Examples: []string{"admin repo delete alice/spam --yes"},
93 Run: runAdminRepoDelete})
6894 register(Command{Path: []string{"admin", "mr", "prune"},
6995 Summary: "drop merged or closed MRs' head refs and the objects only they kept, e.g. after a history rewrite (instance admins; audited)",
7096 Usage: "admin mr prune <owner/name> <n> [<n>...] --yes",
71 Run: runAdminMRPrune})
97 Flags: []Flag{
98 {"--yes", "", "confirm the permanent prune", ""},
99 },
100 Examples: []string{"admin mr prune krz/gitbay 12 13 --yes"},
101 Run: runAdminMRPrune})
72102}
73103
74104// requireInstanceAdmin gates the admin noun. -1 means proceed.
internal/control/adminhost.go +32 −13
@@ -22,32 +22,51 @@ import (
2222
2323func init() {
2424 register(Command{Path: []string{"admin", "user", "create"},
25 Summary: "create an account, optionally with a key and a verified address (instance admins)",
26 Usage: "admin user create <username> [--admin] [--email <address> [--verified]] [--key -] < key.pub",
25 Summary: "create an account, optionally with a key and a verified address (instance admins)",
26 Usage: "admin user create <username> [--admin] [--email <address> [--verified]] [--key -] < key.pub",
27 Flags: []Flag{
28 {"--admin", "", "make the account an instance admin", ""},
29 {"--email", "<address>", "an address to add", ""},
30 {"--verified", "", "mark that address verified", ""},
31 {"--key", "-", "read a public key from stdin", ""},
32 },
33 Examples: []string{"admin user create alice --email alice@example.org --key - < key.pub"},
2734 ReadsStdin: true, Run: runAdminUserCreate})
2835 register(Command{Path: []string{"admin", "user", "disable"},
29 Summary: "suspend an account: SSH, web sessions and API tokens refused until re-enabled",
30 Usage: "admin user disable <username>",
31 Run: runAdminUserDisable})
36 Summary: "suspend an account: SSH, web sessions and API tokens refused until re-enabled",
37 Usage: "admin user disable <username>",
38 Examples: []string{"admin user disable alice"},
39 Run: runAdminUserDisable})
3240 register(Command{Path: []string{"admin", "user", "enable"},
33 Summary: "restore a suspended account",
34 Usage: "admin user enable <username>",
35 Run: runAdminUserEnable})
41 Summary: "restore a suspended account",
42 Usage: "admin user enable <username>",
43 Examples: []string{"admin user enable alice"},
44 Run: runAdminUserEnable})
3645 register(Command{Path: []string{"admin", "user", "delete"},
3746 Summary: "delete an account that anchors nothing (keys, emails and sessions go with it)",
3847 Usage: "admin user delete <username> --yes",
39 Run: runAdminUserDelete})
48 Flags: []Flag{
49 {"--yes", "", "confirm the permanent delete", ""},
50 },
51 Examples: []string{"admin user delete alice --yes"},
52 Run: runAdminUserDelete})
4053 register(Command{Path: []string{"admin", "email", "verify"},
41 Summary: "mark an address verified by admin assertion",
42 Usage: "admin email verify <username> <address>",
43 Run: runAdminEmailVerify})
54 Summary: "mark an address verified by admin assertion",
55 Usage: "admin email verify <username> <address>",
56 Examples: []string{"admin email verify alice alice@example.org"},
57 Run: runAdminEmailVerify})
4458 register(Command{Path: []string{"admin", "invite"},
4559 Summary: "issue a registration invite and mail its code",
4660 Usage: "admin invite --email <address>",
47 Run: runAdminInvite})
61 Flags: []Flag{
62 {"--email", "<address>", "who the invite is for", ""},
63 },
64 Examples: []string{"admin invite --email alice@example.org"},
65 Run: runAdminInvite})
4866 register(Command{Path: []string{"admin", "stats"},
4967 Summary: "instance statistics: counts and per-repository disk usage",
5068 Usage: "admin stats",
69 Examples: []string{"admin stats"},
5170 ReadOnly: true, Run: runAdminStats})
5271}
5372
internal/control/audit.go +9 −2
@@ -12,8 +12,15 @@ import (
1212
1313func init() {
1414 register(Command{Path: []string{"audit"},
15 Summary: "instance audit log (admins)",
16 Usage: "audit [--actor <user>|-] [--action <prefix>] [--since <duration|date>] [--limit <n>]",
15 Summary: "instance audit log (admins)",
16 Usage: "audit [--actor <user>|-] [--action <prefix>] [--since <duration|date>] [--limit <n>]",
17 Flags: []Flag{
18 {"--actor", "<user>|-", "only entries by this user", ""},
19 {"--action", "<prefix>", "only actions starting with this", ""},
20 {"--since", "<duration|date>", "only entries after this", ""},
21 {"--limit", "<n>", "rows to show", "100"},
22 },
23 Examples: []string{"audit --actor alice --since 24h"},
1724 ReadOnly: true, Run: runAudit})
1825}
1926
internal/control/control.go +1
@@ -330,6 +330,7 @@ func init() {
330330 Path: []string{"help"},
331331 Summary: "list available commands",
332332 Usage: "help [<prefix>...]",
333 Examples: []string{"help", "help repo"},
333334 ReadOnly: true,
334335 Run: runHelp,
335336 })
internal/control/help_test.go −24
@@ -17,35 +17,11 @@ var usageFlag = regexp.MustCompile(`--[a-z][a-z0-9-]*`)
1717// is not something the command's own tokenizer parses.
1818var trailingRedirect = regexp.MustCompile(`^(.*?)\s+[<>]\s*\S+$`)
1919
20// helpCovered restricts TestHelpIsComplete to the path prefixes whose help
21// text this commit filled in. Task 4.3 fills the rest and removes this set.
22// "org label" and "org milestone" name the two prefixes under "org" this
23// commit covers; the rest of "org" (teams, members, profile) is not.
24// widened to every command in the next commit
25var helpCovered = []string{
26 "issue", "mr", "build", "release", "milestone", "label", "search",
27 "dashboard", "feed", "status", "wiki", "snippet", "repo",
28 "org label", "org milestone",
29}
30
31func isHelpCovered(path []string) bool {
32 joined := strings.Join(path, " ")
33 for _, prefix := range helpCovered {
34 if joined == prefix || strings.HasPrefix(joined, prefix+" ") {
35 return true
36 }
37 }
38 return false
39}
40
4120// Help is written once, in the registry. Every flag in a usage line has
4221// a description, every description names a flag in the usage line, and
4322// every command has an example that runs it.
4423func TestHelpIsComplete(t *testing.T) {
4524 for _, cmd := range Commands() {
46 if !isHelpCovered(cmd.Path) {
47 continue
48 }
4925 path := strings.Join(cmd.Path, " ")
5026 inUsage := map[string]bool{}
5127 for _, f := range usageFlag.FindAllString(cmd.Usage, -1) {
internal/control/identity.go +20 −11
@@ -18,6 +18,7 @@ func init() {
1818 Path: []string{"whoami"},
1919 Summary: "show the authenticated account",
2020 Usage: "whoami",
21 Examples: []string{"whoami"},
2122 ReadOnly: true,
2223 Run: runWhoami,
2324 })
@@ -25,27 +26,35 @@ func init() {
2526 Path: []string{"keys", "list"},
2627 Summary: "list registered SSH keys",
2728 Usage: "keys list",
29 Examples: []string{"keys list"},
2830 ReadOnly: true,
2931 Run: runKeysList,
3032 })
3133 register(Command{
32 Path: []string{"keys", "add"},
33 Summary: "register an SSH public key (authorized_keys format)",
34 Usage: "keys add [--scope full|git|runner] [--label <text>] < key.pub",
34 Path: []string{"keys", "add"},
35 Summary: "register an SSH public key (authorized_keys format)",
36 Usage: "keys add [--scope full|git|runner] [--label <text>] < key.pub",
37 Flags: []Flag{
38 {"--scope", "full|git|runner", "what the key may do", "full"},
39 {"--label", "<text>", "a name for the key", ""},
40 },
41 Examples: []string{"keys add --label laptop < key.pub"},
3542 ReadsStdin: true,
3643 Run: runKeysAdd,
3744 })
3845 register(Command{
39 Path: []string{"keys", "label"},
40 Summary: "name a key; an empty label clears it",
41 Usage: "keys label <fingerprint> [<text>]",
42 Run: runKeysLabel,
46 Path: []string{"keys", "label"},
47 Summary: "name a key; an empty label clears it",
48 Usage: "keys label <fingerprint> [<text>]",
49 Examples: []string{`keys label SHA256:abcd1234 "work laptop"`},
50 Run: runKeysLabel,
4351 })
4452 register(Command{
45 Path: []string{"keys", "remove"},
46 Summary: "remove an SSH key by fingerprint",
47 Usage: "keys remove <fingerprint>",
48 Run: runKeysRemove,
53 Path: []string{"keys", "remove"},
54 Summary: "remove an SSH key by fingerprint",
55 Usage: "keys remove <fingerprint>",
56 Examples: []string{"keys remove SHA256:abcd1234"},
57 Run: runKeysRemove,
4958 })
5059}
5160
internal/control/migrate.go +7 −2
@@ -16,10 +16,15 @@ func init() {
1616 register(Command{Path: []string{"account", "export"},
1717 Summary: "write your account bundle (profile, repos, issues, MRs) as JSON",
1818 Usage: "account export > bundle.json",
19 Examples: []string{"account export > bundle.json"},
1920 ReadOnly: true, Run: runAccountExport})
2021 register(Command{Path: []string{"account", "import-bundle"},
21 Summary: "replay an account bundle (see gitbay migrate)",
22 Usage: "account import-bundle [--source <host>] < bundle.json",
22 Summary: "replay an account bundle (see gitbay migrate)",
23 Usage: "account import-bundle [--source <host>] < bundle.json",
24 Flags: []Flag{
25 {"--source", "<host>", "the previous instance, for attribution", ""},
26 },
27 Examples: []string{"account import-bundle --source old.example.org < bundle.json"},
2328 ReadsStdin: true, Run: runAccountImportBundle})
2429}
2530
internal/control/notifications.go +36 −11
@@ -15,38 +15,63 @@ import (
1515
1616func init() {
1717 register(Command{Path: []string{"notifications", "list"},
18 Summary: "your notification inbox, newest first",
19 Usage: "notifications list [--all] [--limit <n>] [--cursor <c>]",
18 Summary: "your notification inbox, newest first",
19 Usage: "notifications list [--all] [--limit <n>] [--cursor <c>]",
20 Flags: []Flag{
21 {"--all", "", "include already-read notifications", ""},
22 {"--limit", "<n>", "rows per page", ""},
23 {"--cursor", "<c>", "continue from the previous page", ""},
24 },
25 Examples: []string{"notifications list", "notifications list --all --limit 50"},
2026 ReadOnly: true, Run: runNotificationsList})
2127 register(Command{Path: []string{"notifications", "read"},
2228 Summary: "mark notifications read",
23 Usage: "notifications read <id>... | --all", Run: runNotificationsRead})
29 Usage: "notifications read <id>... | --all",
30 Flags: []Flag{
31 {"--all", "", "mark every unread notification read", ""},
32 },
33 Examples: []string{"notifications read 12 13", "notifications read --all"},
34 Run: runNotificationsRead})
2435 register(Command{Path: []string{"notifications", "settings", "show"},
2536 Summary: "your notification preferences",
2637 Usage: "notifications settings show",
38 Examples: []string{"notifications settings show"},
2739 ReadOnly: true, Run: runNotificationsSettingsShow})
2840 register(Command{Path: []string{"notifications", "settings", "mail"},
29 Summary: "activity by mail as well as the inbox (login links are unaffected)",
30 Usage: "notifications settings mail on|off", Run: runNotificationsSettingsMail})
41 Summary: "activity by mail as well as the inbox (login links are unaffected)",
42 Usage: "notifications settings mail on|off",
43 Examples: []string{"notifications settings mail on"},
44 Run: runNotificationsSettingsMail})
3145 register(Command{Path: []string{"notifications", "settings", "watch"},
32 Summary: "every issue and merge request on repositories you can write to",
33 Usage: "notifications settings watch on|off", Run: runNotificationsSettingsWatch})
46 Summary: "every issue and merge request on repositories you can write to",
47 Usage: "notifications settings watch on|off",
48 Examples: []string{"notifications settings watch on"},
49 Run: runNotificationsSettingsWatch})
3450 register(Command{Path: []string{"notifications", "device", "add"},
3551 Summary: "register an Apple device for push, token on stdin",
3652 Usage: "notifications device add [--label <name>] < token",
53 Flags: []Flag{
54 {"--label", "<name>", "a name for the device", ""},
55 },
56 Examples: []string{"notifications device add --label iphone < token"},
3757 // Mandatory: without it control.go swaps in an empty reader and
3858 // this command stores an empty token without erroring.
3959 ReadsStdin: true, Run: runNotificationsDeviceAdd})
4060 register(Command{Path: []string{"notifications", "device", "list"},
4161 Summary: "your registered devices",
4262 Usage: "notifications device list",
63 Examples: []string{"notifications device list"},
4364 ReadOnly: true, Run: runNotificationsDeviceList})
4465 register(Command{Path: []string{"notifications", "device", "remove"},
45 Summary: "deregister a device",
46 Usage: "notifications device remove <id>", Run: runNotificationsDeviceRemove})
66 Summary: "deregister a device",
67 Usage: "notifications device remove <id>",
68 Examples: []string{"notifications device remove 4"},
69 Run: runNotificationsDeviceRemove})
4770 register(Command{Path: []string{"notifications", "settings", "push"},
48 Summary: "activity on your registered devices as well as the inbox",
49 Usage: "notifications settings push on|off", Run: runNotificationsSettingsPush})
71 Summary: "activity on your registered devices as well as the inbox",
72 Usage: "notifications settings push on|off",
73 Examples: []string{"notifications settings push on"},
74 Run: runNotificationsSettingsPush})
5075 register(Command{Path: []string{"repo", "watch"},
5176 Summary: "hear about all activity on a repository",
5277 Usage: "repo watch <owner/name>",
internal/control/org.go +28 −14
@@ -14,29 +14,43 @@ import (
1414
1515func init() {
1616 register(Command{Path: []string{"org", "create"},
17 Summary: "create an organization (you become its first admin)",
18 Usage: "org create <name>", Run: runOrgCreate})
17 Summary: "create an organization (you become its first admin)",
18 Usage: "org create <name>",
19 Examples: []string{"org create krz"}, Run: runOrgCreate})
1920 register(Command{Path: []string{"org", "list"},
20 Summary: "list organizations you belong to",
21 Usage: "org list", ReadOnly: true, Run: runOrgList})
21 Summary: "list organizations you belong to",
22 Usage: "org list",
23 Examples: []string{"org list"}, ReadOnly: true, Run: runOrgList})
2224 register(Command{Path: []string{"org", "show"},
23 Summary: "show an organization and its members",
24 Usage: "org show <name>", ReadOnly: true, Run: runOrgShow})
25 Summary: "show an organization and its members",
26 Usage: "org show <name>",
27 Examples: []string{"org show krz"}, ReadOnly: true, Run: runOrgShow})
2528 register(Command{Path: []string{"org", "rename"},
26 Summary: "rename an organization",
27 Usage: "org rename <old> <new> (clone URLs change)", Run: runOrgRename})
29 Summary: "rename an organization",
30 Usage: "org rename <old> <new> (clone URLs change)",
31 Examples: []string{"org rename krz krazywarez"}, Run: runOrgRename})
2832 register(Command{Path: []string{"org", "delete"},
2933 Summary: "delete an empty organization",
30 Usage: "org delete <name> --yes", Run: runOrgDelete})
34 Usage: "org delete <name> --yes",
35 Flags: []Flag{
36 {"--yes", "", "confirm the permanent delete", ""},
37 },
38 Examples: []string{"org delete krz --yes"}, Run: runOrgDelete})
3139 register(Command{Path: []string{"org", "members", "add"},
3240 Summary: "add or update a member",
33 Usage: "org members add <org> <user> [--role member|admin]", Run: runOrgMembersAdd})
41 Usage: "org members add <org> <user> [--role member|admin]",
42 Flags: []Flag{
43 {"--role", "member|admin", "the member's role", "member"},
44 },
45 Examples: []string{"org members add krz cmc --role admin"}, Run: runOrgMembersAdd})
3446 register(Command{Path: []string{"org", "members", "remove"},
35 Summary: "remove a member",
36 Usage: "org members remove <org> <user>", Run: runOrgMembersRemove})
47 Summary: "remove a member",
48 Usage: "org members remove <org> <user>",
49 Examples: []string{"org members remove krz cmc"}, Run: runOrgMembersRemove})
3750 register(Command{Path: []string{"org", "members", "list"},
38 Summary: "list members",
39 Usage: "org members list <org>", ReadOnly: true, Run: runOrgMembersList})
51 Summary: "list members",
52 Usage: "org members list <org>",
53 Examples: []string{"org members list krz"}, ReadOnly: true, Run: runOrgMembersList})
4054}
4155
4256// orgAdmin loads an org and requires the caller to be one of its admins.
internal/control/profile.go +17 −4
@@ -16,14 +16,27 @@ import (
1616
1717func init() {
1818 register(Command{Path: []string{"profile", "show"},
19 Summary: "show a user's or org's profile",
20 Usage: "profile show [name]", ReadOnly: true, Run: runProfileShow})
19 Summary: "show a user's or org's profile",
20 Usage: "profile show [name]",
21 Examples: []string{"profile show cmc"}, ReadOnly: true, Run: runProfileShow})
2122 register(Command{Path: []string{"profile", "set"},
2223 Summary: "set your profile",
23 Usage: "profile set [--description <d>] [--website <url>] [--link <label|url>]... ('' clears)", Run: runProfileSet})
24 Usage: "profile set [--description <d>] [--website <url>] [--link <label|url>]... ('' clears)",
25 Flags: []Flag{
26 {"--description", "<d>", "one line about you", ""},
27 {"--website", "<url>", "your website", ""},
28 {"--link", "<label|url>", "a profile link, may repeat", ""},
29 },
30 Examples: []string{`profile set --description "gitbay's author" --website https://cleberg.net`}, Run: runProfileSet})
2431 register(Command{Path: []string{"org", "profile"},
2532 Summary: "show or set an org's profile",
26 Usage: "org profile <org> [--description <d>] [--website <url>] [--link <label|url>]...", Run: runOrgProfile})
33 Usage: "org profile <org> [--description <d>] [--website <url>] [--link <label|url>]...",
34 Flags: []Flag{
35 {"--description", "<d>", "one line about the org", ""},
36 {"--website", "<url>", "the org's website", ""},
37 {"--link", "<label|url>", "a profile link, may repeat", ""},
38 },
39 Examples: []string{"org profile krz", `org profile krz --description "a self-hosted forge"`}, Run: runOrgProfile})
2740}
2841
2942// maxProfileLinks caps the free-form link list. A profile is a header,
internal/control/quota.go +6 −1
@@ -85,7 +85,12 @@ func init() {
8585 register(Command{Path: []string{"admin", "user", "limits"},
8686 Summary: "show or set an account's repository and storage caps (instance admins)",
8787 Usage: "admin user limits <username> [--repos <n>|default] [--bytes <n>|default]",
88 Run: runAdminUserLimits})
88 Flags: []Flag{
89 {"--repos", "<n>|default", "the account's repository cap", ""},
90 {"--bytes", "<n>|default", "the account's storage cap", ""},
91 },
92 Examples: []string{"admin user limits alice", "admin user limits alice --repos 50"},
93 Run: runAdminUserLimits})
8994}
9095
9196func runAdminUserLimits(c *Ctx, args []string) int {
internal/control/register.go +19 −8
@@ -20,27 +20,38 @@ func init() {
2020 register(Command{Path: []string{"register"},
2121 Summary: "create an account (only meaningful for unregistered keys)",
2222 Usage: "register --username <name> [--email <address> | --invite <code>]",
23 Flags: []Flag{
24 {"--username", "<name>", "the account's username", ""},
25 {"--email", "<address>", "for open registration", ""},
26 {"--invite", "<code>", "for invite-only registration", ""},
27 },
28 Examples: []string{"register --username cmc --email cmc@example.org"},
2329 Run: func(c *Ctx, args []string) int {
2430 return c.fail(protocol.ExitUsage,
2531 "this SSH key already belongs to %s. To register a new account, connect with the key it should use:\n ssh -F /dev/null -i <newkey> git@<host> register ...",
2632 c.User.Username)
2733 }})
2834 register(Command{Path: []string{"email", "add"},
29 Summary: "add an address and mail a verification code",
30 Usage: "email add <address>", Run: runEmailAdd})
35 Summary: "add an address and mail a verification code",
36 Usage: "email add <address>",
37 Examples: []string{"email add cmc@example.org"}, Run: runEmailAdd})
3138 register(Command{Path: []string{"email", "verify"},
32 Summary: "confirm a verification code",
33 Usage: "email verify <code>", Run: runEmailVerify})
39 Summary: "confirm a verification code",
40 Usage: "email verify <code>",
41 Examples: []string{"email verify abc123"}, Run: runEmailVerify})
3442 register(Command{Path: []string{"email", "list"},
3543 Summary: "list the addresses on your account",
3644 Usage: "email list",
45 Examples: []string{"email list"},
3746 ReadOnly: true, Run: runEmailList})
3847 register(Command{Path: []string{"email", "remove"},
39 Summary: "remove an address; not the primary, nor the last verified one",
40 Usage: "email remove <address>", Run: runEmailRemove})
48 Summary: "remove an address; not the primary, nor the last verified one",
49 Usage: "email remove <address>",
50 Examples: []string{"email remove old@example.org"}, Run: runEmailRemove})
4151 register(Command{Path: []string{"email", "primary"},
42 Summary: "make a verified address the primary",
43 Usage: "email primary <address>", Run: runEmailPrimary})
52 Summary: "make a verified address the primary",
53 Usage: "email primary <address>",
54 Examples: []string{"email primary cmc@example.org"}, Run: runEmailPrimary})
4455}
4556
4657func runEmailList(c *Ctx, args []string) int {
internal/control/sig.go +10 −6
@@ -18,14 +18,18 @@ import (
1818
1919func init() {
2020 register(Command{Path: []string{"pgp", "add"},
21 Summary: "register an OpenPGP public key (armored)",
22 Usage: "pgp add < key.asc", ReadsStdin: true, Run: runPGPAdd})
21 Summary: "register an OpenPGP public key (armored)",
22 Usage: "pgp add < key.asc",
23 Examples: []string{"pgp add < key.asc"},
24 ReadsStdin: true, Run: runPGPAdd})
2325 register(Command{Path: []string{"pgp", "list"},
24 Summary: "list registered OpenPGP keys",
25 Usage: "pgp list", ReadOnly: true, Run: runPGPList})
26 Summary: "list registered OpenPGP keys",
27 Usage: "pgp list",
28 Examples: []string{"pgp list"}, ReadOnly: true, Run: runPGPList})
2629 register(Command{Path: []string{"pgp", "remove"},
27 Summary: "remove an OpenPGP key by fingerprint",
28 Usage: "pgp remove <fingerprint>", Run: runPGPRemove})
30 Summary: "remove an OpenPGP key by fingerprint",
31 Usage: "pgp remove <fingerprint>",
32 Examples: []string{"pgp remove ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234"}, Run: runPGPRemove})
2933 register(Command{Path: []string{"repo", "commit"},
3034 Summary: "show one commit with its patch",
3135 Usage: "repo commit <owner/name> <sha>",
internal/control/teams.go +27 −18
@@ -14,32 +14,41 @@ import (
1414
1515func init() {
1616 register(Command{Path: []string{"org", "team", "create"},
17 Summary: "create a team",
18 Usage: "org team create <org> <team>", Run: runTeamCreate})
17 Summary: "create a team",
18 Usage: "org team create <org> <team>",
19 Examples: []string{"org team create krz maintainers"}, Run: runTeamCreate})
1920 register(Command{Path: []string{"org", "team", "delete"},
20 Summary: "delete a team (its grants with it)",
21 Usage: "org team delete <org> <team>", Run: runTeamDelete})
21 Summary: "delete a team (its grants with it)",
22 Usage: "org team delete <org> <team>",
23 Examples: []string{"org team delete krz maintainers"}, Run: runTeamDelete})
2224 register(Command{Path: []string{"org", "team", "list"},
23 Summary: "list an org's teams",
24 Usage: "org team list <org>", ReadOnly: true, Run: runTeamList})
25 Summary: "list an org's teams",
26 Usage: "org team list <org>",
27 Examples: []string{"org team list krz"}, ReadOnly: true, Run: runTeamList})
2528 register(Command{Path: []string{"org", "team", "show"},
26 Summary: "show a team's members and grants",
27 Usage: "org team show <org> <team>", ReadOnly: true, Run: runTeamShow})
29 Summary: "show a team's members and grants",
30 Usage: "org team show <org> <team>",
31 Examples: []string{"org team show krz maintainers"}, ReadOnly: true, Run: runTeamShow})
2832 register(Command{Path: []string{"org", "team", "add"},
29 Summary: "add org members to a team",
30 Usage: "org team add <org> <team> <user>...", Run: runTeamAdd})
33 Summary: "add org members to a team",
34 Usage: "org team add <org> <team> <user>...",
35 Examples: []string{"org team add krz maintainers cmc"}, Run: runTeamAdd})
3136 register(Command{Path: []string{"org", "team", "remove"},
32 Summary: "remove members from a team",
33 Usage: "org team remove <org> <team> <user>...", Run: runTeamRemove})
37 Summary: "remove members from a team",
38 Usage: "org team remove <org> <team> <user>...",
39 Examples: []string{"org team remove krz maintainers cmc"}, Run: runTeamRemove})
3440 register(Command{Path: []string{"org", "team", "grant"},
35 Summary: "grant a team a role on an org repo",
36 Usage: "org team grant <org> <team> <owner/name> read|write|admin", Run: runTeamGrant})
41 Summary: "grant a team a role on an org repo",
42 Usage: "org team grant <org> <team> <owner/name> read|write|admin",
43 Examples: []string{"org team grant krz maintainers krz/gitbay write"}, Run: runTeamGrant})
3744 register(Command{Path: []string{"org", "team", "revoke"},
38 Summary: "revoke a team's grant",
39 Usage: "org team revoke <org> <team> <owner/name>", Run: runTeamRevoke})
45 Summary: "revoke a team's grant",
46 Usage: "org team revoke <org> <team> <owner/name>",
47 Examples: []string{"org team revoke krz maintainers krz/gitbay"}, Run: runTeamRevoke})
4048 register(Command{Path: []string{"org", "settings", "members-role"},
41 Summary: "role plain membership implies on every org repo",
42 Usage: "org settings members-role <org> write|read|none (default write)", Run: runOrgMembersRole})
49 Summary: "role plain membership implies on every org repo",
50 Usage: "org settings members-role <org> write|read|none (default write)",
51 Examples: []string{"org settings members-role krz read"}, Run: runOrgMembersRole})
4352}
4453
4554// orgAdminRef resolves an org and requires the caller to admin it.
internal/control/theme.go +4 −2
@@ -11,10 +11,12 @@ func init() {
1111 register(Command{Path: []string{"web", "theme", "show"},
1212 Summary: "the colour scheme the web UI uses for you",
1313 Usage: "web theme show",
14 Examples: []string{"web theme show"},
1415 ReadOnly: true, Run: runWebThemeShow})
1516 register(Command{Path: []string{"web", "theme", "set"},
16 Summary: "follow the browser's scheme, or force light or dark",
17 Usage: "web theme set system|light|dark", Run: runWebThemeSet})
17 Summary: "follow the browser's scheme, or force light or dark",
18 Usage: "web theme set system|light|dark",
19 Examples: []string{"web theme set dark"}, Run: runWebThemeSet})
1820}
1921
2022// themes are the values the layout knows how to stamp. system is the
internal/control/token.go +14 −6
@@ -16,14 +16,22 @@ func init() {
1616 register(Command{Path: []string{"token", "create"},
1717 Summary: "mint an API token (shown once)",
1818 Usage: "token create --name <n> [--scope full|read] [--ttl 30d|720h]",
19 Run: runTokenCreate})
19 Flags: []Flag{
20 {"--name", "<n>", "the token's name", ""},
21 {"--scope", "full|read", "what the token may do", "full"},
22 {"--ttl", "30d|720h", "how long the token is valid", "never expires"},
23 },
24 Examples: []string{"token create --name laptop --scope read --ttl 30d"},
25 Run: runTokenCreate})
2026 register(Command{Path: []string{"token", "list"},
21 Summary: "list API tokens",
22 Usage: "token list", ReadOnly: true, Run: runTokenList})
27 Summary: "list API tokens",
28 Usage: "token list",
29 Examples: []string{"token list"}, ReadOnly: true, Run: runTokenList})
2330 register(Command{Path: []string{"token", "revoke"},
24 Summary: "revoke an API token by name",
25 Usage: "token revoke <name>",
26 Run: runTokenRevoke})
31 Summary: "revoke an API token by name",
32 Usage: "token revoke <name>",
33 Examples: []string{"token revoke laptop"},
34 Run: runTokenRevoke})
2735}
2836
2937// parseTTL accepts Go durations plus a day suffix ("30d").
internal/control/web.go +11 −5
@@ -14,14 +14,20 @@ func newStoredToken() (token, hash string, err error) { return store.NewToken()
1414
1515func init() {
1616 register(Command{Path: []string{"web", "login"},
17 Summary: "mint a one-time browser login URL",
18 Usage: "web login", Run: runWebLogin})
17 Summary: "mint a one-time browser login URL",
18 Usage: "web login",
19 Examples: []string{"web login"}, Run: runWebLogin})
1920 register(Command{Path: []string{"web", "sessions", "list"},
20 Summary: "list your browser sessions",
21 Usage: "web sessions list", ReadOnly: true, Run: runWebSessionsList})
21 Summary: "list your browser sessions",
22 Usage: "web sessions list",
23 Examples: []string{"web sessions list"}, ReadOnly: true, Run: runWebSessionsList})
2224 register(Command{Path: []string{"web", "sessions", "revoke"},
2325 Summary: "end a browser session, or all of them",
24 Usage: "web sessions revoke <id>|--all", Run: runWebSessionsRevoke})
26 Usage: "web sessions revoke <id>|--all",
27 Flags: []Flag{
28 {"--all", "", "revoke every browser session", ""},
29 },
30 Examples: []string{"web sessions revoke --all"}, Run: runWebSessionsRevoke})
2531}
2632
2733func runWebSessionsList(c *Ctx, args []string) int {
internal/control/webhook.go +22 −8
@@ -15,19 +15,33 @@ import (
1515func init() {
1616 register(Command{Path: []string{"webhook", "add"},
1717 Summary: "add a webhook",
18 Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]", Run: runWebhookAdd})
18 Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]",
19 Flags: []Flag{
20 {"--secret", "<s>", "signs deliveries so the receiver can verify them", ""},
21 {"--events", "push,issue.created|*", "which events to send", "*"},
22 },
23 Examples: []string{"webhook add krz/gitbay https://ci.example.org/hook --events push"},
24 Run: runWebhookAdd})
1925 register(Command{Path: []string{"webhook", "list"},
20 Summary: "list webhooks",
21 Usage: "webhook list <owner/name>", ReadOnly: true, Run: runWebhookList})
26 Summary: "list webhooks",
27 Usage: "webhook list <owner/name>",
28 Examples: []string{"webhook list krz/gitbay"}, ReadOnly: true, Run: runWebhookList})
2229 register(Command{Path: []string{"webhook", "remove"},
23 Summary: "remove a webhook",
24 Usage: "webhook remove <owner/name> <id>", Run: runWebhookRemove})
30 Summary: "remove a webhook",
31 Usage: "webhook remove <owner/name> <id>",
32 Examples: []string{"webhook remove krz/gitbay 3"}, Run: runWebhookRemove})
2533 register(Command{Path: []string{"webhook", "deliveries"},
2634 Summary: "recent deliveries",
27 Usage: "webhook deliveries <owner/name> [--limit n]", ReadOnly: true, Run: runWebhookDeliveries})
35 Usage: "webhook deliveries <owner/name> [--limit n]",
36 Flags: []Flag{
37 {"--limit", "n", "rows to show", "20"},
38 },
39 Examples: []string{"webhook deliveries krz/gitbay --limit 50"},
40 ReadOnly: true, Run: runWebhookDeliveries})
2841 register(Command{Path: []string{"webhook", "redeliver"},
29 Summary: "queue a delivery again",
30 Usage: "webhook redeliver <owner/name> <delivery-id>", Run: runWebhookRedeliver})
42 Summary: "queue a delivery again",
43 Usage: "webhook redeliver <owner/name> <delivery-id>",
44 Examples: []string{"webhook redeliver krz/gitbay 42"}, Run: runWebhookRedeliver})
3145}
3246
3347func runWebhookAdd(c *Ctx, args []string) int {