Commit d905c69753

d905c6975328020c0277804c1a352cd5b9e57676

parent: a1e67e455d

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 07:06 UTC

flags: print a bad-flag usage line the way a usage refusal does

Ref #267

Layout: unified · split

cmd/gitbay/ssh.go +4 −4
@@ -174,11 +174,11 @@ func cliPathOf(cmd *cobra.Command) string {
174} 174}
175 175
176// withCLIPath prepends --path=<cliPath> to a server command line when the 176// withCLIPath prepends --path=<cliPath> to a server command line when the
177// CLI path differs from the server path it dispatches, so usage and help 177// CLI path is set and differs from the server path it dispatches, so
178// print a command the caller can run (#267). Dispatch strips it before 178// usage and help print a command the caller can run (#267). Dispatch
179// Lookup, as it does --term=. 179// strips it before Lookup, as it does --term=.
180func withCLIPath(cliPath, server string, argv []string) []string { 180func withCLIPath(cliPath, server string, argv []string) []string {
181 if cliPath == server { 181 if cliPath == "" || cliPath == server {
182 return argv 182 return argv
183 } 183 }
184 return append([]string{"--path=" + cliPath}, argv...) 184 return append([]string{"--path=" + cliPath}, argv...)
cmd/gitbay/term_test.go +3
@@ -99,6 +99,9 @@ func TestWithCLIPath(t *testing.T) {
99 if got := withCLIPath("keys remove", "keys remove", argv); !slices.Equal(got, argv) { 99 if got := withCLIPath("keys remove", "keys remove", argv); !slices.Equal(got, argv) {
100 t.Errorf("matching path: %v", got) 100 t.Errorf("matching path: %v", got)
101 } 101 }
102 if got := withCLIPath("", "keys remove", argv); !slices.Equal(got, argv) {
103 t.Errorf("empty cliPath: %v", got)
104 }
102 got := withCLIPath("auth keys remove", "keys remove", argv) 105 got := withCLIPath("auth keys remove", "keys remove", argv)
103 want := []string{"--path=auth keys remove", "keys", "remove", "abc"} 106 want := []string{"--path=auth keys remove", "keys", "remove", "abc"}
104 if !slices.Equal(got, want) { 107 if !slices.Equal(got, want) {
internal/control/admin.go +2 −2
@@ -137,7 +137,7 @@ func runAdminUserList(c *Ctx, args []string) int {
137 if code >= 0 { 137 if code >= 0 {
138 return code 138 return code
139 } 139 }
140 f, err := parseFlags(args, flagSpec{Values: []string{"--state"}, MaxPos: 0, 140 f, err := c.parseArgs(args, flagSpec{Values: []string{"--state"}, MaxPos: 0,
141 Usage: "admin user list [--state active|pending|disabled|admin] [--limit <n>] [--cursor <c>]"}) 141 Usage: "admin user list [--state active|pending|disabled|admin] [--limit <n>] [--cursor <c>]"})
142 if err != nil { 142 if err != nil {
143 return c.fail(protocol.ExitUsage, "%v", err) 143 return c.fail(protocol.ExitUsage, "%v", err)
@@ -410,7 +410,7 @@ func runAdminRepoList(c *Ctx, args []string) int {
410 if code >= 0 { 410 if code >= 0 {
411 return code 411 return code
412 } 412 }
413 f, err := parseFlags(args, flagSpec{Values: []string{"--owner", "--visibility"}, MaxPos: 0, 413 f, err := c.parseArgs(args, flagSpec{Values: []string{"--owner", "--visibility"}, MaxPos: 0,
414 Usage: "admin repo list [--owner <name>] [--visibility public|private] [--limit <n>] [--cursor <c>]"}) 414 Usage: "admin repo list [--owner <name>] [--visibility public|private] [--limit <n>] [--cursor <c>]"})
415 if err != nil { 415 if err != nil {
416 return c.fail(protocol.ExitUsage, "%v", err) 416 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/adminhost.go +1 −1
@@ -77,7 +77,7 @@ func runAdminUserCreate(c *Ctx, args []string) int {
77 if code := requireInstanceAdmin(c); code >= 0 { 77 if code := requireInstanceAdmin(c); code >= 0 {
78 return code 78 return code
79 } 79 }
80 f, err := parseFlags(args, flagSpec{Values: []string{"--email", "--key"}, Bools: []string{"--admin", "--verified"}, MaxPos: 1, Usage: c.Cmd.Usage}) 80 f, err := c.parseArgs(args, flagSpec{Values: []string{"--email", "--key"}, Bools: []string{"--admin", "--verified"}, MaxPos: 1, Usage: c.Cmd.Usage})
81 if err != nil { 81 if err != nil {
82 return c.fail(protocol.ExitUsage, "%v", err) 82 return c.fail(protocol.ExitUsage, "%v", err)
83 } 83 }
internal/control/audit.go +1 −1
@@ -29,7 +29,7 @@ func runAudit(c *Ctx, args []string) int {
29 return c.fail(protocol.ExitDenied, "the audit log is for instance admins; ask one") 29 return c.fail(protocol.ExitDenied, "the audit log is for instance admins; ask one")
30 } 30 }
31 f := store.AuditFilter{Limit: 100} 31 f := store.AuditFilter{Limit: 100}
32 fl, err := parseFlags(args, flagSpec{Values: []string{"--limit", "--actor", "--action", "--since"}, MaxPos: 0, Usage: c.Cmd.Usage}) 32 fl, err := c.parseArgs(args, flagSpec{Values: []string{"--limit", "--actor", "--action", "--since"}, MaxPos: 0, Usage: c.Cmd.Usage})
33 if err != nil { 33 if err != nil {
34 return c.fail(protocol.ExitUsage, "%v", err) 34 return c.fail(protocol.ExitUsage, "%v", err)
35 } 35 }
internal/control/build.go +3 −3
@@ -158,7 +158,7 @@ func runBuildList(c *Ctx, args []string) int {
158 if code >= 0 { 158 if code >= 0 {
159 return code 159 return code
160 } 160 }
161 f, err := parseFlags(args, flagSpec{Values: []string{"--ref", "--status", "--job"}, MaxPos: 1, Usage: c.Cmd.Usage}) 161 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref", "--status", "--job"}, MaxPos: 1, Usage: c.Cmd.Usage})
162 if err != nil { 162 if err != nil {
163 return c.fail(protocol.ExitUsage, "%v", err) 163 return c.fail(protocol.ExitUsage, "%v", err)
164 } 164 }
@@ -238,7 +238,7 @@ func runBuildShow(c *Ctx, args []string) int {
238} 238}
239 239
240func runBuildLog(c *Ctx, args []string) int { 240func runBuildLog(c *Ctx, args []string) int {
241 f, err := parseFlags(args, flagSpec{Bools: []string{"--follow"}, MaxPos: 2, Usage: c.Cmd.Usage}) 241 f, err := c.parseArgs(args, flagSpec{Bools: []string{"--follow"}, MaxPos: 2, Usage: c.Cmd.Usage})
242 if err != nil { 242 if err != nil {
243 return c.fail(protocol.ExitUsage, "%v", err) 243 return c.fail(protocol.ExitUsage, "%v", err)
244 } 244 }
@@ -465,7 +465,7 @@ func runRunnerNext(c *Ctx, args []string) int {
465 if code >= 0 { 465 if code >= 0 {
466 return code 466 return code
467 } 467 }
468 f, err := parseFlags(args, flagSpec{Bools: []string{"--untrusted"}, MaxPos: -1, 468 f, err := c.parseArgs(args, flagSpec{Bools: []string{"--untrusted"}, MaxPos: -1,
469 Usage: "runner next [--untrusted] [<owner/name>...]"}) 469 Usage: "runner next [--untrusted] [<owner/name>...]"})
470 if err != nil { 470 if err != nil {
471 return c.fail(protocol.ExitUsage, "%v", err) 471 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/commitfile.go +1 −1
@@ -43,7 +43,7 @@ const maxCommitFileBytes = 1 << 20
43// A repository that requires verified signatures therefore refuses the 43// A repository that requires verified signatures therefore refuses the
44// command rather than writing a commit its own policy would reject. 44// command rather than writing a commit its own policy would reject.
45func runCommitFile(c *Ctx, args []string) int { 45func runCommitFile(c *Ctx, args []string) int {
46 f, err := parseFlags(args, flagSpec{Values: []string{"--ref", "--message", "--file"}, MaxPos: -1, Usage: c.Cmd.Usage}) 46 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref", "--message", "--file"}, MaxPos: -1, Usage: c.Cmd.Usage})
47 if err != nil { 47 if err != nil {
48 return c.fail(protocol.ExitUsage, "%v", err) 48 return c.fail(protocol.ExitUsage, "%v", err)
49 } 49 }
internal/control/control_test.go +26
@@ -307,6 +307,32 @@ func TestArgumentRefusalsNameTheUsage(t *testing.T) {
307 } 307 }
308} 308}
309 309
310// TestFlagRefusalsNameTheUsage: a bad flag prints its usage the same way
311// a missing positional does, program and CLI path included (#267).
312func TestFlagRefusalsNameTheUsage(t *testing.T) {
313 cases := []struct {
314 name string
315 argv []string
316 want string
317 }{
318 {"cli", []string{"--path=auth token create", "token", "create", "--bogus"}, "unknown flag \"--bogus\"\nusage: gitbay auth token create --name <n>"},
319 {"stock ssh", []string{"token", "create", "--bogus"}, "unknown flag \"--bogus\"\nusage: ssh git@forge.test token create --name <n>"},
320 {"cli, repo", []string{"--term=80", "issue", "list", "a/b", "--bogus"}, "usage: gitbay issue list [<owner/name>]"},
321 }
322 for _, tc := range cases {
323 var out, errOut bytes.Buffer
324 c := &Ctx{Scope: "full", Stdout: &out, Stderr: &errOut}
325 c.Cfg.Server.SiteURL = "https://forge.test"
326 if code := Dispatch(c, tc.argv); code != protocol.ExitUsage {
327 t.Errorf("%s: exit %d, want %d (%s)", tc.name, code, protocol.ExitUsage, errOut.String())
328 continue
329 }
330 if !strings.Contains(errOut.String(), tc.want) {
331 t.Errorf("%s: got %q, want it to contain %q", tc.name, errOut.String(), tc.want)
332 }
333 }
334}
335
310// TestTermArgument: --term= is read only as the first argument, and 336// TestTermArgument: --term= is read only as the first argument, and
311// never over HTTP. 337// never over HTTP.
312func TestTermArgument(t *testing.T) { 338func TestTermArgument(t *testing.T) {
internal/control/deploykey.go +1 −1
@@ -37,7 +37,7 @@ func init() {
37} 37}
38 38
39func runDeployKeyAdd(c *Ctx, args []string) int { 39func runDeployKeyAdd(c *Ctx, args []string) int {
40 f, err := parseFlags(args, flagSpec{Values: []string{"--ttl"}, Bools: []string{"--rw"}, MaxPos: 1, Usage: c.Cmd.Usage}) 40 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ttl"}, Bools: []string{"--rw"}, MaxPos: 1, Usage: c.Cmd.Usage})
41 if err != nil { 41 if err != nil {
42 return c.fail(protocol.ExitUsage, "%v", err) 42 return c.fail(protocol.ExitUsage, "%v", err)
43 } 43 }
internal/control/diffcomment.go +1 −1
@@ -50,7 +50,7 @@ func init() {
50} 50}
51 51
52func runDiffComment(c *Ctx, args []string) int { 52func runDiffComment(c *Ctx, args []string) int {
53 f, err := parseFlags(args, flagSpec{Values: []string{"--path", "--line", "--reply", "--message", "--file"}, 53 f, err := c.parseArgs(args, flagSpec{Values: []string{"--path", "--line", "--reply", "--message", "--file"},
54 Bools: []string{"--old", "--pending"}, MaxPos: -1, 54 Bools: []string{"--old", "--pending"}, MaxPos: -1,
55 Usage: "mr diff-comment <owner/name> <n> --path <file> --line <l> [--old] [--pending] [--reply <id>] [--message <m> | --file -]"}) 55 Usage: "mr diff-comment <owner/name> <n> --path <file> --line <l> [--old] [--pending] [--reply <id>] [--message <m> | --file -]"})
56 if err != nil { 56 if err != nil {
internal/control/explore.go +1 −1
@@ -95,7 +95,7 @@ func runExplore(c *Ctx, args []string) int {
95// release asset get writes an asset. The web's /archive route is the 95// release asset get writes an asset. The web's /archive route is the
96// same bytes with a Content-Disposition on them. 96// same bytes with a Content-Disposition on them.
97func runRepoDownload(c *Ctx, args []string) int { 97func runRepoDownload(c *Ctx, args []string) int {
98 f, err := parseFlags(args, flagSpec{Values: []string{"--ref"}, MaxPos: -1, Usage: c.Cmd.Usage}) 98 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref"}, MaxPos: -1, Usage: c.Cmd.Usage})
99 if err != nil { 99 if err != nil {
100 return c.fail(protocol.ExitUsage, "%v", err) 100 return c.fail(protocol.ExitUsage, "%v", err)
101 } 101 }
internal/control/flags.go +15
@@ -92,6 +92,21 @@ func parseFlags(args []string, spec flagSpec) (flags, error) {
92 return f, nil 92 return f, nil
93} 93}
94 94
95// parseArgs is parseFlags for the running command, with the usage line
96// printed the way a usage refusal prints it (cmdUsage): the program in
97// front and the CLI's own path where it differs (#267). spec.Usage stays
98// the text, since some commands spell their flags out more fully there
99// than in the registered Usage.
100func (c *Ctx) parseArgs(args []string, spec flagSpec) (flags, error) {
101 usage := strings.TrimPrefix(spec.Usage, "usage: ")
102 spec.Usage = ""
103 f, err := parseFlags(args, spec)
104 if err != nil && usage != "" {
105 err = fmt.Errorf("%v\nusage: %s %s", err, c.program(), c.usageShape(c.Cmd.Path, usage))
106 }
107 return f, err
108}
109
95// pos is the nth positional argument, or "" when absent. 110// pos is the nth positional argument, or "" when absent.
96func (f flags) pos(n int) string { 111func (f flags) pos(n int) string {
97 if n < len(f.Pos) { 112 if n < len(f.Pos) {
internal/control/ghimport.go +1 −1
@@ -148,7 +148,7 @@ func attribution(src string, n int64, kind, login, date string) string {
148} 148}
149 149
150func runImportIssues(c *Ctx, args []string) int { 150func runImportIssues(c *Ctx, args []string) int {
151 f, err := parseFlags(args, flagSpec{Values: []string{"--from", "--api-base"}, Bools: []string{"--token-stdin"}, MaxPos: 1, 151 f, err := c.parseArgs(args, flagSpec{Values: []string{"--from", "--api-base"}, Bools: []string{"--token-stdin"}, MaxPos: 1,
152 Usage: "repo import-issues <owner/name> --from <owner/repo> [--api-base <url>] [--token-stdin]"}) 152 Usage: "repo import-issues <owner/name> --from <owner/repo> [--api-base <url>] [--token-stdin]"})
153 if err != nil { 153 if err != nil {
154 return c.fail(protocol.ExitUsage, "%v", err) 154 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/help.go +7 −7
@@ -168,11 +168,11 @@ func (c *Ctx) shownBelow(registered, other string) string {
168 return joinPath(append(slices.Clip(cli[:len(cli)-1]), o[len(reg)-1:]...)) 168 return joinPath(append(slices.Clip(cli[:len(cli)-1]), o[len(reg)-1:]...))
169} 169}
170 170
171// usageShape is cmd's registered usage as this caller should see it: the 171// usageShape is a usage line for the command registered at path as this
172// CLI's path in place of the registered one where they differ, and a 172// caller should see it: the CLI's path in place of the registered one
173// leading <owner/name> optional for the CLI. 173// where they differ, and a leading <owner/name> optional for the CLI.
174func (c *Ctx) usageShape(cmd Command) string { 174func (c *Ctx) usageShape(path []string, usage string) string {
175 shape := c.shownAs(joinPath(cmd.Path), cmd.Usage) 175 shape := c.shownAs(joinPath(path), usage)
176 if c.viaCLI() { 176 if c.viaCLI() {
177 shape = cliUsage(shape) 177 shape = cliUsage(shape)
178 } 178 }
@@ -182,7 +182,7 @@ func (c *Ctx) usageShape(cmd Command) string {
182// cmdUsage is the running command's usage with the program in front, as 182// cmdUsage is the running command's usage with the program in front, as
183// a usage refusal prints it. 183// a usage refusal prints it.
184func (c *Ctx) cmdUsage() string { 184func (c *Ctx) cmdUsage() string {
185 return c.program() + " " + c.usageShape(c.Cmd) 185 return c.program() + " " + c.usageShape(c.Cmd.Path, c.Cmd.Usage)
186} 186}
187 187
188func (c *Ctx) heading(w io.Writer, s string) { 188func (c *Ctx) heading(w io.Writer, s string) {
@@ -217,7 +217,7 @@ func (c *Ctx) helpVerb(w io.Writer, cmd Command, below []Command) {
217 // (notifications read <id>... | --all) has no " [--" to cut at, so 217 // (notifications read <id>... | --all) has no " [--" to cut at, so
218 // the usage prints whole. 218 // the usage prints whole.
219 registered := joinPath(cmd.Path) 219 registered := joinPath(cmd.Path)
220 shape := c.usageShape(cmd) 220 shape := c.usageShape(cmd.Path, cmd.Usage)
221 if i := strings.Index(shape, " [--"); i >= 0 { 221 if i := strings.Index(shape, " [--"); i >= 0 {
222 shape = shape[:i] + " [flags]" 222 shape = shape[:i] + " [flags]"
223 } 223 }
internal/control/identity.go +1 −1
@@ -152,7 +152,7 @@ func expiresText(t *time.Time, now time.Time) string {
152} 152}
153 153
154func runKeysAdd(c *Ctx, args []string) int { 154func runKeysAdd(c *Ctx, args []string) int {
155 f, err := parseFlags(args, flagSpec{Values: []string{"--scope", "--label", "--ttl"}, MaxPos: 0, Usage: c.Cmd.Usage}) 155 f, err := c.parseArgs(args, flagSpec{Values: []string{"--scope", "--label", "--ttl"}, MaxPos: 0, Usage: c.Cmd.Usage})
156 if err != nil { 156 if err != nil {
157 return c.fail(protocol.ExitUsage, "%v", err) 157 return c.fail(protocol.ExitUsage, "%v", err)
158 } 158 }
internal/control/import.go +1 −1
@@ -39,7 +39,7 @@ esac
39` 39`
40 40
41func runRepoImport(c *Ctx, args []string) int { 41func runRepoImport(c *Ctx, args []string) int {
42 f, err := parseFlags(args, flagSpec{Values: []string{"--from"}, Bools: []string{"--private", "--token-stdin"}, MaxPos: 1, 42 f, err := c.parseArgs(args, flagSpec{Values: []string{"--from"}, Bools: []string{"--private", "--token-stdin"}, MaxPos: 1,
43 Usage: "repo import <owner/name> --from <url> [--private] [--token-stdin]"}) 43 Usage: "repo import <owner/name> --from <url> [--private] [--token-stdin]"})
44 if err != nil { 44 if err != nil {
45 return c.fail(protocol.ExitUsage, "%v", err) 45 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/issue.go +3 −3
@@ -178,7 +178,7 @@ func issueToOut(i store.Issue, withBody bool) issueOut {
178} 178}
179 179
180func runIssueCreate(c *Ctx, args []string) int { 180func runIssueCreate(c *Ctx, args []string) int {
181 f, err := parseFlags(args, flagSpec{Values: []string{"--format", "--title", "--body", "--file"}, MaxPos: 1, 181 f, err := c.parseArgs(args, flagSpec{Values: []string{"--format", "--title", "--body", "--file"}, MaxPos: 1,
182 Usage: "issue create <owner/name> --title <t> [--body <b> | --file -] [--format md|org]"}) 182 Usage: "issue create <owner/name> --title <t> [--body <b> | --file -] [--format md|org]"})
183 if err != nil { 183 if err != nil {
184 return c.fail(protocol.ExitUsage, "%v", err) 184 return c.fail(protocol.ExitUsage, "%v", err)
@@ -231,7 +231,7 @@ func runIssueList(c *Ctx, args []string) int {
231 return code 231 return code
232 } 232 }
233 f := store.IssueFilter{State: "open"} 233 f := store.IssueFilter{State: "open"}
234 fl, err := parseFlags(args, flagSpec{Values: []string{"--state", "--label", "--assignee", "--author", "--milestone", "--search"}, MaxPos: 1, Usage: c.Cmd.Usage}) 234 fl, err := c.parseArgs(args, flagSpec{Values: []string{"--state", "--label", "--assignee", "--author", "--milestone", "--search"}, MaxPos: 1, Usage: c.Cmd.Usage})
235 if err != nil { 235 if err != nil {
236 return c.fail(protocol.ExitUsage, "%v", err) 236 return c.fail(protocol.ExitUsage, "%v", err)
237 } 237 }
@@ -371,7 +371,7 @@ func setIssueState(c *Ctx, args []string, state string) int {
371// they are accepted and reported in the returned flags, and count toward 371// they are accepted and reported in the returned flags, and count toward
372// "at least one edit was given" alongside title/body/format. 372// "at least one edit was given" alongside title/body/format.
373func editText(c *Ctx, args []string, kind string, extra ...string) (rest []string, title, body, format *string, f flags, code int) { 373func editText(c *Ctx, args []string, kind string, extra ...string) (rest []string, title, body, format *string, f flags, code int) {
374 f, err := parseFlags(args, flagSpec{Values: append([]string{"--title", "--body", "--file", "--format"}, extra...), MaxPos: -1, 374 f, err := c.parseArgs(args, flagSpec{Values: append([]string{"--title", "--body", "--file", "--format"}, extra...), MaxPos: -1,
375 Usage: kind + " edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org]"}) 375 Usage: kind + " edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org]"})
376 if err != nil { 376 if err != nil {
377 return nil, nil, nil, nil, flags{}, c.fail(protocol.ExitUsage, "%v", err) 377 return nil, nil, nil, nil, flags{}, c.fail(protocol.ExitUsage, "%v", err)
internal/control/label.go +1 −1
@@ -68,7 +68,7 @@ func runLabelList(c *Ctx, args []string) int {
68} 68}
69 69
70func runLabelSet(c *Ctx, args []string) int { 70func runLabelSet(c *Ctx, args []string) int {
71 f, err := parseFlags(args, flagSpec{Values: []string{"--color"}, MaxPos: -1, Usage: c.Cmd.Usage}) 71 f, err := c.parseArgs(args, flagSpec{Values: []string{"--color"}, MaxPos: -1, Usage: c.Cmd.Usage})
72 if err != nil { 72 if err != nil {
73 return c.fail(protocol.ExitUsage, "%v", err) 73 return c.fail(protocol.ExitUsage, "%v", err)
74 } 74 }
internal/control/migrate.go +1 −1
@@ -155,7 +155,7 @@ func migAttribution(src, kind, author, date string, n int64) string {
155// the git push that follows cannot be refused by them. Resumable: markers 155// the git push that follows cannot be refused by them. Resumable: markers
156// skip everything already imported. 156// skip everything already imported.
157func runAccountImportBundle(c *Ctx, args []string) int { 157func runAccountImportBundle(c *Ctx, args []string) int {
158 f, err := parseFlags(args, flagSpec{Values: []string{"--source"}, MaxPos: 0, Usage: "account import-bundle [--source <host>] < bundle.json"}) 158 f, err := c.parseArgs(args, flagSpec{Values: []string{"--source"}, MaxPos: 0, Usage: "account import-bundle [--source <host>] < bundle.json"})
159 if err != nil { 159 if err != nil {
160 return c.fail(protocol.ExitUsage, "%v", err) 160 return c.fail(protocol.ExitUsage, "%v", err)
161 } 161 }
internal/control/milestone.go +2 −2
@@ -62,7 +62,7 @@ func init() {
62var duePat = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`) 62var duePat = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
63 63
64func runMilestoneCreate(c *Ctx, args []string) int { 64func runMilestoneCreate(c *Ctx, args []string) int {
65 f, err := parseFlags(args, flagSpec{Values: []string{"--description", "--due"}, MaxPos: 2, 65 f, err := c.parseArgs(args, flagSpec{Values: []string{"--description", "--due"}, MaxPos: 2,
66 Usage: "milestone create <owner/name> <title> [--description <d>] [--due YYYY-MM-DD]"}) 66 Usage: "milestone create <owner/name> <title> [--description <d>] [--due YYYY-MM-DD]"})
67 if err != nil { 67 if err != nil {
68 return c.fail(protocol.ExitUsage, "%v", err) 68 return c.fail(protocol.ExitUsage, "%v", err)
@@ -93,7 +93,7 @@ func runMilestoneCreate(c *Ctx, args []string) int {
93} 93}
94 94
95func runMilestoneList(c *Ctx, args []string) int { 95func runMilestoneList(c *Ctx, args []string) int {
96 f, err := parseFlags(args, flagSpec{Values: []string{"--state"}, MaxPos: 1, Usage: "milestone list <owner/name> [--state open|closed|all]"}) 96 f, err := c.parseArgs(args, flagSpec{Values: []string{"--state"}, MaxPos: 1, Usage: "milestone list <owner/name> [--state open|closed|all]"})
97 if err != nil { 97 if err != nil {
98 return c.fail(protocol.ExitUsage, "%v", err) 98 return c.fail(protocol.ExitUsage, "%v", err)
99 } 99 }
internal/control/mirrorcmd.go +1 −1
@@ -43,7 +43,7 @@ func init() {
43} 43}
44 44
45func runMirrorAdd(c *Ctx, args []string) int { 45func runMirrorAdd(c *Ctx, args []string) int {
46 f, err := parseFlags(args, flagSpec{Values: []string{"--direction", "--username"}, Bools: []string{"--token-stdin"}, MaxPos: 2, 46 f, err := c.parseArgs(args, flagSpec{Values: []string{"--direction", "--username"}, Bools: []string{"--token-stdin"}, MaxPos: 2,
47 Usage: "repo mirror add <owner/name> <url> --direction push|pull [--username <u>] [--token-stdin]"}) 47 Usage: "repo mirror add <owner/name> <url> --direction push|pull [--username <u>] [--token-stdin]"})
48 if err != nil { 48 if err != nil {
49 return c.fail(protocol.ExitUsage, "%v", err) 49 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/mr.go +6 −6
@@ -207,7 +207,7 @@ type ForkOut struct {
207} 207}
208 208
209func runRepoFork(c *Ctx, args []string) int { 209func runRepoFork(c *Ctx, args []string) int {
210 f, err := parseFlags(args, flagSpec{Values: []string{"--name", "--owner"}, MaxPos: 1, Usage: "repo fork <owner/name> [--owner <o>] [--name <n>]"}) 210 f, err := c.parseArgs(args, flagSpec{Values: []string{"--name", "--owner"}, MaxPos: 1, Usage: "repo fork <owner/name> [--owner <o>] [--name <n>]"})
211 if err != nil { 211 if err != nil {
212 return c.fail(protocol.ExitUsage, "%v", err) 212 return c.fail(protocol.ExitUsage, "%v", err)
213 } 213 }
@@ -393,7 +393,7 @@ func mrRef(c *Ctx, args []string, perm func(store.User, store.Repo, string) bool
393func mrHeadRef(n int64) string { return fmt.Sprintf("refs/merge-requests/%d/head", n) } 393func mrHeadRef(n int64) string { return fmt.Sprintf("refs/merge-requests/%d/head", n) }
394 394
395func runMRCreate(c *Ctx, args []string) int { 395func runMRCreate(c *Ctx, args []string) int {
396 f, err := parseFlags(args, flagSpec{Values: []string{"--source", "--target", "--title", "--body", "--file", "--format"}, 396 f, err := c.parseArgs(args, flagSpec{Values: []string{"--source", "--target", "--title", "--body", "--file", "--format"},
397 Bools: []string{"--draft"}, MaxPos: 1, 397 Bools: []string{"--draft"}, MaxPos: 1,
398 Usage: "mr create <target owner/name> --source [owner/name:]<branch> --target <branch> --title <t> [--draft]"}) 398 Usage: "mr create <target owner/name> --source [owner/name:]<branch> --target <branch> --title <t> [--draft]"})
399 if err != nil { 399 if err != nil {
@@ -566,7 +566,7 @@ func runMRList(c *Ctx, args []string) int {
566 return code 566 return code
567 } 567 }
568 f := store.MRFilter{State: "open"} 568 f := store.MRFilter{State: "open"}
569 fl, err := parseFlags(args, flagSpec{Values: []string{"--state", "--label", "--author", "--milestone", "--search"}, MaxPos: 1, Usage: c.Cmd.Usage}) 569 fl, err := c.parseArgs(args, flagSpec{Values: []string{"--state", "--label", "--author", "--milestone", "--search"}, MaxPos: 1, Usage: c.Cmd.Usage})
570 if err != nil { 570 if err != nil {
571 return c.fail(protocol.ExitUsage, "%v", err) 571 return c.fail(protocol.ExitUsage, "%v", err)
572 } 572 }
@@ -1205,7 +1205,7 @@ func runMRLabel(c *Ctx, args []string) int {
1205} 1205}
1206 1206
1207func runMRMerge(c *Ctx, args []string) int { 1207func runMRMerge(c *Ctx, args []string) int {
1208 f, err := parseFlags(args, flagSpec{Values: []string{"--strategy"}, MaxPos: -1, Usage: "mr merge <owner/name> <n> [--strategy ff|merge|squash|rebase]"}) 1208 f, err := c.parseArgs(args, flagSpec{Values: []string{"--strategy"}, MaxPos: -1, Usage: "mr merge <owner/name> <n> [--strategy ff|merge|squash|rebase]"})
1209 if err != nil { 1209 if err != nil {
1210 return c.fail(protocol.ExitUsage, "%v", err) 1210 return c.fail(protocol.ExitUsage, "%v", err)
1211 } 1211 }
@@ -1775,7 +1775,7 @@ func setMRDraft(c *Ctx, args []string, draft bool) int {
1775} 1775}
1776 1776
1777func runMRClose(c *Ctx, args []string) int { 1777func runMRClose(c *Ctx, args []string) int {
1778 f, err := parseFlags(args, flagSpec{Values: []string{"--by"}, MaxPos: 2, 1778 f, err := c.parseArgs(args, flagSpec{Values: []string{"--by"}, MaxPos: 2,
1779 Usage: "mr close <owner/name> <n> [--by <m>]"}) 1779 Usage: "mr close <owner/name> <n> [--by <m>]"})
1780 if err != nil { 1780 if err != nil {
1781 return c.fail(protocol.ExitUsage, "%v", err) 1781 return c.fail(protocol.ExitUsage, "%v", err)
@@ -1907,7 +1907,7 @@ func runMRRevisions(c *Ctx, args []string) int {
1907} 1907}
1908 1908
1909func runMRRangeDiff(c *Ctx, args []string) int { 1909func runMRRangeDiff(c *Ctx, args []string) int {
1910 f, err := parseFlags(args, flagSpec{Values: []string{"--from", "--to"}, MaxPos: 2, Usage: c.Cmd.Usage}) 1910 f, err := c.parseArgs(args, flagSpec{Values: []string{"--from", "--to"}, MaxPos: 2, Usage: c.Cmd.Usage})
1911 if err != nil { 1911 if err != nil {
1912 return c.fail(protocol.ExitUsage, "%v", err) 1912 return c.fail(protocol.ExitUsage, "%v", err)
1913 } 1913 }
internal/control/notifications.go +3 −3
@@ -285,7 +285,7 @@ func runNotificationsSettingsPush(c *Ctx, args []string) int {
285const maxDeviceTokenBytes = 512 285const maxDeviceTokenBytes = 512
286 286
287func runNotificationsDeviceAdd(c *Ctx, args []string) int { 287func runNotificationsDeviceAdd(c *Ctx, args []string) int {
288 f, err := parseFlags(args, flagSpec{Values: []string{"--label"}, Usage: c.Cmd.Usage}) 288 f, err := c.parseArgs(args, flagSpec{Values: []string{"--label"}, Usage: c.Cmd.Usage})
289 if err != nil { 289 if err != nil {
290 return c.fail(protocol.ExitUsage, "%v", err) 290 return c.fail(protocol.ExitUsage, "%v", err)
291 } 291 }
@@ -389,7 +389,7 @@ func runNotificationsList(c *Ctx, args []string) int {
389 if code >= 0 { 389 if code >= 0 {
390 return code 390 return code
391 } 391 }
392 fl, err := parseFlags(rest, flagSpec{Bools: []string{"--all"}, Usage: c.Cmd.Usage}) 392 fl, err := c.parseArgs(rest, flagSpec{Bools: []string{"--all"}, Usage: c.Cmd.Usage})
393 if err != nil { 393 if err != nil {
394 return c.fail(protocol.ExitUsage, "%v", err) 394 return c.fail(protocol.ExitUsage, "%v", err)
395 } 395 }
@@ -443,7 +443,7 @@ func runNotificationsList(c *Ctx, args []string) int {
443} 443}
444 444
445func runNotificationsRead(c *Ctx, args []string) int { 445func runNotificationsRead(c *Ctx, args []string) int {
446 fl, err := parseFlags(args, flagSpec{Bools: []string{"--all"}, MaxPos: -1, Usage: c.Cmd.Usage}) 446 fl, err := c.parseArgs(args, flagSpec{Bools: []string{"--all"}, MaxPos: -1, Usage: c.Cmd.Usage})
447 if err != nil { 447 if err != nil {
448 return c.fail(protocol.ExitUsage, "%v", err) 448 return c.fail(protocol.ExitUsage, "%v", err)
449 } 449 }
internal/control/org.go +1 −1
@@ -214,7 +214,7 @@ func runOrgDelete(c *Ctx, args []string) int {
214} 214}
215 215
216func runOrgMembersAdd(c *Ctx, args []string) int { 216func runOrgMembersAdd(c *Ctx, args []string) int {
217 f, err := parseFlags(args, flagSpec{Values: []string{"--role"}, MaxPos: -1, Usage: "org members add <org> <user> [--role member|admin]"}) 217 f, err := c.parseArgs(args, flagSpec{Values: []string{"--role"}, MaxPos: -1, Usage: "org members add <org> <user> [--role member|admin]"})
218 if err != nil { 218 if err != nil {
219 return c.fail(protocol.ExitUsage, "%v", err) 219 return c.fail(protocol.ExitUsage, "%v", err)
220 } 220 }
internal/control/orglabel.go +3 −3
@@ -86,7 +86,7 @@ func orgReader(c *Ctx, name string) (store.Org, []int64, int) {
86} 86}
87 87
88func runOrgLabelSet(c *Ctx, args []string) int { 88func runOrgLabelSet(c *Ctx, args []string) int {
89 f, err := parseFlags(args, flagSpec{Values: []string{"--color"}, MaxPos: 2, Usage: c.Cmd.Usage}) 89 f, err := c.parseArgs(args, flagSpec{Values: []string{"--color"}, MaxPos: 2, Usage: c.Cmd.Usage})
90 if err != nil { 90 if err != nil {
91 return c.fail(protocol.ExitUsage, "%v", err) 91 return c.fail(protocol.ExitUsage, "%v", err)
92 } 92 }
@@ -180,7 +180,7 @@ func runOrgLabelRemove(c *Ctx, args []string) int {
180} 180}
181 181
182func runOrgMilestoneCreate(c *Ctx, args []string) int { 182func runOrgMilestoneCreate(c *Ctx, args []string) int {
183 f, err := parseFlags(args, flagSpec{Values: []string{"--description", "--due"}, MaxPos: 2, Usage: c.Cmd.Usage}) 183 f, err := c.parseArgs(args, flagSpec{Values: []string{"--description", "--due"}, MaxPos: 2, Usage: c.Cmd.Usage})
184 if err != nil { 184 if err != nil {
185 return c.fail(protocol.ExitUsage, "%v", err) 185 return c.fail(protocol.ExitUsage, "%v", err)
186 } 186 }
@@ -212,7 +212,7 @@ func runOrgMilestoneCreate(c *Ctx, args []string) int {
212} 212}
213 213
214func runOrgMilestoneList(c *Ctx, args []string) int { 214func runOrgMilestoneList(c *Ctx, args []string) int {
215 f, err := parseFlags(args, flagSpec{Values: []string{"--state"}, MaxPos: 1, Usage: "org milestone list <org> [--state open|closed|all]"}) 215 f, err := c.parseArgs(args, flagSpec{Values: []string{"--state"}, MaxPos: 1, Usage: "org milestone list <org> [--state open|closed|all]"})
216 if err != nil { 216 if err != nil {
217 return c.fail(protocol.ExitUsage, "%v", err) 217 return c.fail(protocol.ExitUsage, "%v", err)
218 } 218 }
internal/control/read.go +2 −2
@@ -110,7 +110,7 @@ func runRepoRefs(c *Ctx, args []string) int {
110const BlameSpan = 1000 110const BlameSpan = 1000
111 111
112func runRepoBlame(c *Ctx, args []string) int { 112func runRepoBlame(c *Ctx, args []string) int {
113 f, err := parseFlags(args, flagSpec{Values: []string{"--ref", "--from", "--to"}, MaxPos: -1, Usage: c.Cmd.Usage}) 113 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref", "--from", "--to"}, MaxPos: -1, Usage: c.Cmd.Usage})
114 if err != nil { 114 if err != nil {
115 return c.fail(protocol.ExitUsage, "%v", err) 115 return c.fail(protocol.ExitUsage, "%v", err)
116 } 116 }
@@ -220,7 +220,7 @@ func runRepoBlame(c *Ctx, args []string) int {
220// off argv. Positionals are returned in order so each command can name them 220// off argv. Positionals are returned in order so each command can name them
221// in its own usage message. 221// in its own usage message.
222func readArgs(c *Ctx, args []string, usage string, maxPos int) (pos []string, ref string, code int) { 222func readArgs(c *Ctx, args []string, usage string, maxPos int) (pos []string, ref string, code int) {
223 f, err := parseFlags(args, flagSpec{Values: []string{"--ref"}, MaxPos: maxPos, Usage: c.Cmd.Usage}) 223 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref"}, MaxPos: maxPos, Usage: c.Cmd.Usage})
224 if err != nil { 224 if err != nil {
225 return nil, "", c.fail(protocol.ExitUsage, "%v", err) 225 return nil, "", c.fail(protocol.ExitUsage, "%v", err)
226 } 226 }
internal/control/release.go +2 −2
@@ -111,7 +111,7 @@ func releaseRef(c *Ctx, args []string, perm func(store.User, store.Repo, string)
111} 111}
112 112
113func runReleaseCreate(c *Ctx, args []string) int { 113func runReleaseCreate(c *Ctx, args []string) int {
114 f, err := parseFlags(args, flagSpec{Values: []string{"--title", "--notes", "--file", "--format"}, MaxPos: 2, Usage: c.Cmd.Usage}) 114 f, err := c.parseArgs(args, flagSpec{Values: []string{"--title", "--notes", "--file", "--format"}, MaxPos: 2, Usage: c.Cmd.Usage})
115 if err != nil { 115 if err != nil {
116 return c.fail(protocol.ExitUsage, "%v", err) 116 return c.fail(protocol.ExitUsage, "%v", err)
117 } 117 }
@@ -183,7 +183,7 @@ func releaseToOut(r store.Release, withNotes bool) releaseOut {
183} 183}
184 184
185func runReleaseEdit(c *Ctx, args []string) int { 185func runReleaseEdit(c *Ctx, args []string) int {
186 f, err := parseFlags(args, flagSpec{Values: []string{"--title", "--notes", "--file", "--format"}, MaxPos: 2, Usage: c.Cmd.Usage}) 186 f, err := c.parseArgs(args, flagSpec{Values: []string{"--title", "--notes", "--file", "--format"}, MaxPos: 2, Usage: c.Cmd.Usage})
187 if err != nil { 187 if err != nil {
188 return c.fail(protocol.ExitUsage, "%v", err) 188 return c.fail(protocol.ExitUsage, "%v", err)
189 } 189 }
internal/control/repo.go +3 −3
@@ -249,7 +249,7 @@ func resolveRepo(c *Ctx, path string, check func(store.User, store.Repo, string)
249} 249}
250 250
251func runRepoCreate(c *Ctx, args []string) int { 251func runRepoCreate(c *Ctx, args []string) int {
252 f, err := parseFlags(args, flagSpec{Values: []string{"--description"}, Bools: []string{"--private"}, MaxPos: 1, Usage: "repo create <owner/name> [--private] [--description <text>]"}) 252 f, err := c.parseArgs(args, flagSpec{Values: []string{"--description"}, Bools: []string{"--private"}, MaxPos: 1, Usage: "repo create <owner/name> [--private] [--description <text>]"})
253 if err != nil { 253 if err != nil {
254 return c.fail(protocol.ExitUsage, "%v", err) 254 return c.fail(protocol.ExitUsage, "%v", err)
255 } 255 }
@@ -1020,7 +1020,7 @@ func MatchesRepo(q, path, desc string, topics []string) bool {
1020} 1020}
1021 1021
1022func runRepoGrep(c *Ctx, args []string) int { 1022func runRepoGrep(c *Ctx, args []string) int {
1023 f, err := parseFlags(args, flagSpec{Values: []string{"--ref"}, MaxPos: 2, Usage: "repo grep <owner/name> <query> [--ref <ref>]"}) 1023 f, err := c.parseArgs(args, flagSpec{Values: []string{"--ref"}, MaxPos: 2, Usage: "repo grep <owner/name> <query> [--ref <ref>]"})
1024 if err != nil { 1024 if err != nil {
1025 return c.fail(protocol.ExitUsage, "%v", err) 1025 return c.fail(protocol.ExitUsage, "%v", err)
1026 } 1026 }
@@ -1246,7 +1246,7 @@ func setProtect(c *Ctx, args []string, protect bool) int {
1246// base, measured from their merge base the way a merge request diff is, 1246// base, measured from their merge base the way a merge request diff is,
1247// so a base that moved on does not show up as removals (#118). 1247// so a base that moved on does not show up as removals (#118).
1248func runRepoDiff(c *Ctx, args []string) int { 1248func runRepoDiff(c *Ctx, args []string) int {
1249 f, err := parseFlags(args, flagSpec{MaxPos: 3, Usage: "repo diff <owner/name> <base> <head>"}) 1249 f, err := c.parseArgs(args, flagSpec{MaxPos: 3, Usage: "repo diff <owner/name> <base> <head>"})
1250 if err != nil || len(f.Pos) != 3 { 1250 if err != nil || len(f.Pos) != 3 {
1251 return c.usage() 1251 return c.usage()
1252 } 1252 }
internal/control/runnerrepo.go +1 −1
@@ -37,7 +37,7 @@ func init() {
37} 37}
38 38
39func runRepoRunnerAdd(c *Ctx, args []string) int { 39func runRepoRunnerAdd(c *Ctx, args []string) int {
40 f, err := parseFlags(args, flagSpec{MaxPos: 1, Usage: "repo runner add <owner/name> < key.pub"}) 40 f, err := c.parseArgs(args, flagSpec{MaxPos: 1, Usage: "repo runner add <owner/name> < key.pub"})
41 if err != nil || len(f.Pos) != 1 { 41 if err != nil || len(f.Pos) != 1 {
42 return c.usage() 42 return c.usage()
43 } 43 }
internal/control/search.go +1 −1
@@ -84,7 +84,7 @@ func Search(st *store.Store, root string, userID int64, q string, kinds []string
84} 84}
85 85
86func runSearch(c *Ctx, args []string) int { 86func runSearch(c *Ctx, args []string) int {
87 f, err := parseFlags(args, flagSpec{Multi: []string{"--kind"}, MaxPos: 1, Usage: c.Cmd.Usage}) 87 f, err := c.parseArgs(args, flagSpec{Multi: []string{"--kind"}, MaxPos: 1, Usage: c.Cmd.Usage})
88 if err != nil { 88 if err != nil {
89 return c.fail(protocol.ExitUsage, "%v", err) 89 return c.fail(protocol.ExitUsage, "%v", err)
90 } 90 }
internal/control/sig.go +1 −1
@@ -141,7 +141,7 @@ func VerifyCommitCached(st *store.Store, repo store.Repo, parsed *sig.Commit, sh
141} 141}
142 142
143func runRepoLog(c *Ctx, args []string) int { 143func runRepoLog(c *Ctx, args []string) int {
144 f, perr := parseFlags(args, flagSpec{Values: []string{"--ref", "--limit", "--path"}, MaxPos: 1, Usage: "repo log <owner/name> [--ref <r>] [--limit n] [--path <file>]"}) 144 f, perr := c.parseArgs(args, flagSpec{Values: []string{"--ref", "--limit", "--path"}, MaxPos: 1, Usage: "repo log <owner/name> [--ref <r>] [--limit n] [--path <file>]"})
145 if perr != nil { 145 if perr != nil {
146 return c.fail(protocol.ExitUsage, "%v", perr) 146 return c.fail(protocol.ExitUsage, "%v", perr)
147 } 147 }
internal/control/snippet.go +2 −2
@@ -158,7 +158,7 @@ func newSnippetID() string {
158} 158}
159 159
160func runSnippetCreate(c *Ctx, args []string) int { 160func runSnippetCreate(c *Ctx, args []string) int {
161 f, err := parseFlags(args, flagSpec{Values: []string{"--description", "--visibility"}, MaxPos: 1, Usage: c.Cmd.Usage}) 161 f, err := c.parseArgs(args, flagSpec{Values: []string{"--description", "--visibility"}, MaxPos: 1, Usage: c.Cmd.Usage})
162 if err != nil { 162 if err != nil {
163 return c.fail(protocol.ExitUsage, "%v", err) 163 return c.fail(protocol.ExitUsage, "%v", err)
164 } 164 }
@@ -287,7 +287,7 @@ func runSnippetList(c *Ctx, args []string) int {
287} 287}
288 288
289func runSnippetEdit(c *Ctx, args []string) int { 289func runSnippetEdit(c *Ctx, args []string) int {
290 f, err := parseFlags(args, flagSpec{Values: []string{"--description", "--visibility"}, MaxPos: 1, Usage: c.Cmd.Usage}) 290 f, err := c.parseArgs(args, flagSpec{Values: []string{"--description", "--visibility"}, MaxPos: 1, Usage: c.Cmd.Usage})
291 if err != nil { 291 if err != nil {
292 return c.fail(protocol.ExitUsage, "%v", err) 292 return c.fail(protocol.ExitUsage, "%v", err)
293 } 293 }
internal/control/thread.go +1 −1
@@ -77,7 +77,7 @@ func runComment(c *Ctx, args []string, t thread, noun string,
77 add func(id, userID int64, body, format string) error, 77 add func(id, userID int64, body, format string) error,
78 participants func(id int64) ([]int64, error), 78 participants func(id int64) ([]int64, error),
79) int { 79) int {
80 f, err := parseFlags(args, flagSpec{Values: []string{"--message", "--file", "--format"}, MaxPos: -1, 80 f, err := c.parseArgs(args, flagSpec{Values: []string{"--message", "--file", "--format"}, MaxPos: -1,
81 Usage: noun + " comment <owner/name> <n> [--message <m> | --file -] [--format md|org]"}) 81 Usage: noun + " comment <owner/name> <n> [--message <m> | --file -] [--format md|org]"})
82 if err != nil { 82 if err != nil {
83 return c.fail(protocol.ExitUsage, "%v", err) 83 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/token.go +2 −2
@@ -65,7 +65,7 @@ func (c *Ctx) ttlFlag(f flags) (*time.Time, int) {
65} 65}
66 66
67func runTokenCreate(c *Ctx, args []string) int { 67func runTokenCreate(c *Ctx, args []string) int {
68 f, err := parseFlags(args, flagSpec{Values: []string{"--name", "--scope", "--ttl"}, MaxPos: 0, Usage: c.Cmd.Usage}) 68 f, err := c.parseArgs(args, flagSpec{Values: []string{"--name", "--scope", "--ttl"}, MaxPos: 0, Usage: c.Cmd.Usage})
69 if err != nil { 69 if err != nil {
70 return c.fail(protocol.ExitUsage, "%v", err) 70 return c.fail(protocol.ExitUsage, "%v", err)
71 } 71 }
@@ -128,7 +128,7 @@ func runTokenList(c *Ctx, args []string) int {
128} 128}
129 129
130func runTokenRevoke(c *Ctx, args []string) int { 130func runTokenRevoke(c *Ctx, args []string) int {
131 f, err := parseFlags(args, flagSpec{Bools: []string{"--created"}, MaxPos: 1, Usage: c.Cmd.Usage}) 131 f, err := c.parseArgs(args, flagSpec{Bools: []string{"--created"}, MaxPos: 1, Usage: c.Cmd.Usage})
132 if err != nil { 132 if err != nil {
133 return c.fail(protocol.ExitUsage, "%v", err) 133 return c.fail(protocol.ExitUsage, "%v", err)
134 } 134 }
internal/control/webhook.go +2 −2
@@ -45,7 +45,7 @@ func init() {
45} 45}
46 46
47func runWebhookAdd(c *Ctx, args []string) int { 47func runWebhookAdd(c *Ctx, args []string) int {
48 f, err := parseFlags(args, flagSpec{Values: []string{"--secret", "--events"}, MaxPos: 2, Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]"}) 48 f, err := c.parseArgs(args, flagSpec{Values: []string{"--secret", "--events"}, MaxPos: 2, Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]"})
49 if err != nil { 49 if err != nil {
50 return c.fail(protocol.ExitUsage, "%v", err) 50 return c.fail(protocol.ExitUsage, "%v", err)
51 } 51 }
@@ -136,7 +136,7 @@ func runWebhookRemove(c *Ctx, args []string) int {
136} 136}
137 137
138func runWebhookDeliveries(c *Ctx, args []string) int { 138func runWebhookDeliveries(c *Ctx, args []string) int {
139 f, err := parseFlags(args, flagSpec{Values: []string{"--limit"}, MaxPos: 1, Usage: "webhook deliveries <owner/name> [--limit n]"}) 139 f, err := c.parseArgs(args, flagSpec{Values: []string{"--limit"}, MaxPos: 1, Usage: "webhook deliveries <owner/name> [--limit n]"})
140 if err != nil { 140 if err != nil {
141 return c.fail(protocol.ExitUsage, "%v", err) 141 return c.fail(protocol.ExitUsage, "%v", err)
142 } 142 }