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 {
174174}
175175
176176// 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
178// print a command the caller can run (#267). Dispatch strips it before
179// Lookup, as it does --term=.
177// CLI path is set and differs from the server path it dispatches, so
178// usage and help print a command the caller can run (#267). Dispatch
179// strips it before Lookup, as it does --term=.
180180func withCLIPath(cliPath, server string, argv []string) []string {
181 if cliPath == server {
181 if cliPath == "" || cliPath == server {
182182 return argv
183183 }
184184 return append([]string{"--path=" + cliPath}, argv...)
cmd/gitbay/term_test.go +3
@@ -99,6 +99,9 @@ func TestWithCLIPath(t *testing.T) {
9999 if got := withCLIPath("keys remove", "keys remove", argv); !slices.Equal(got, argv) {
100100 t.Errorf("matching path: %v", got)
101101 }
102 if got := withCLIPath("", "keys remove", argv); !slices.Equal(got, argv) {
103 t.Errorf("empty cliPath: %v", got)
104 }
102105 got := withCLIPath("auth keys remove", "keys remove", argv)
103106 want := []string{"--path=auth keys remove", "keys", "remove", "abc"}
104107 if !slices.Equal(got, want) {
internal/control/admin.go +2 −2
@@ -137,7 +137,7 @@ func runAdminUserList(c *Ctx, args []string) int {
137137 if code >= 0 {
138138 return code
139139 }
140 f, err := parseFlags(args, flagSpec{Values: []string{"--state"}, MaxPos: 0,
140 f, err := c.parseArgs(args, flagSpec{Values: []string{"--state"}, MaxPos: 0,
141141 Usage: "admin user list [--state active|pending|disabled|admin] [--limit <n>] [--cursor <c>]"})
142142 if err != nil {
143143 return c.fail(protocol.ExitUsage, "%v", err)
@@ -410,7 +410,7 @@ func runAdminRepoList(c *Ctx, args []string) int {
410410 if code >= 0 {
411411 return code
412412 }
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,
414414 Usage: "admin repo list [--owner <name>] [--visibility public|private] [--limit <n>] [--cursor <c>]"})
415415 if err != nil {
416416 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/adminhost.go +1 −1
@@ -77,7 +77,7 @@ func runAdminUserCreate(c *Ctx, args []string) int {
7777 if code := requireInstanceAdmin(c); code >= 0 {
7878 return code
7979 }
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})
8181 if err != nil {
8282 return c.fail(protocol.ExitUsage, "%v", err)
8383 }
internal/control/audit.go +1 −1
@@ -29,7 +29,7 @@ func runAudit(c *Ctx, args []string) int {
2929 return c.fail(protocol.ExitDenied, "the audit log is for instance admins; ask one")
3030 }
3131 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})
3333 if err != nil {
3434 return c.fail(protocol.ExitUsage, "%v", err)
3535 }
internal/control/build.go +3 −3
@@ -158,7 +158,7 @@ func runBuildList(c *Ctx, args []string) int {
158158 if code >= 0 {
159159 return code
160160 }
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})
162162 if err != nil {
163163 return c.fail(protocol.ExitUsage, "%v", err)
164164 }
@@ -238,7 +238,7 @@ func runBuildShow(c *Ctx, args []string) int {
238238}
239239
240240func 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})
242242 if err != nil {
243243 return c.fail(protocol.ExitUsage, "%v", err)
244244 }
@@ -465,7 +465,7 @@ func runRunnerNext(c *Ctx, args []string) int {
465465 if code >= 0 {
466466 return code
467467 }
468 f, err := parseFlags(args, flagSpec{Bools: []string{"--untrusted"}, MaxPos: -1,
468 f, err := c.parseArgs(args, flagSpec{Bools: []string{"--untrusted"}, MaxPos: -1,
469469 Usage: "runner next [--untrusted] [<owner/name>...]"})
470470 if err != nil {
471471 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/commitfile.go +1 −1
@@ -43,7 +43,7 @@ const maxCommitFileBytes = 1 << 20
4343// A repository that requires verified signatures therefore refuses the
4444// command rather than writing a commit its own policy would reject.
4545func 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})
4747 if err != nil {
4848 return c.fail(protocol.ExitUsage, "%v", err)
4949 }
internal/control/control_test.go +26
@@ -307,6 +307,32 @@ func TestArgumentRefusalsNameTheUsage(t *testing.T) {
307307 }
308308}
309309
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
310336// TestTermArgument: --term= is read only as the first argument, and
311337// never over HTTP.
312338func TestTermArgument(t *testing.T) {
internal/control/deploykey.go +1 −1
@@ -37,7 +37,7 @@ func init() {
3737}
3838
3939func 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})
4141 if err != nil {
4242 return c.fail(protocol.ExitUsage, "%v", err)
4343 }
internal/control/diffcomment.go +1 −1
@@ -50,7 +50,7 @@ func init() {
5050}
5151
5252func 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"},
5454 Bools: []string{"--old", "--pending"}, MaxPos: -1,
5555 Usage: "mr diff-comment <owner/name> <n> --path <file> --line <l> [--old] [--pending] [--reply <id>] [--message <m> | --file -]"})
5656 if err != nil {
internal/control/explore.go +1 −1
@@ -95,7 +95,7 @@ func runExplore(c *Ctx, args []string) int {
9595// release asset get writes an asset. The web's /archive route is the
9696// same bytes with a Content-Disposition on them.
9797func 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})
9999 if err != nil {
100100 return c.fail(protocol.ExitUsage, "%v", err)
101101 }
internal/control/flags.go +15
@@ -92,6 +92,21 @@ func parseFlags(args []string, spec flagSpec) (flags, error) {
9292 return f, nil
9393}
9494
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
95110// pos is the nth positional argument, or "" when absent.
96111func (f flags) pos(n int) string {
97112 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 {
148148}
149149
150150func 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,
152152 Usage: "repo import-issues <owner/name> --from <owner/repo> [--api-base <url>] [--token-stdin]"})
153153 if err != nil {
154154 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 {
168168 return joinPath(append(slices.Clip(cli[:len(cli)-1]), o[len(reg)-1:]...))
169169}
170170
171// usageShape is cmd's registered usage as this caller should see it: the
172// CLI's path in place of the registered one where they differ, and a
173// leading <owner/name> optional for the CLI.
174func (c *Ctx) usageShape(cmd Command) string {
175 shape := c.shownAs(joinPath(cmd.Path), cmd.Usage)
171// usageShape is a usage line for the command registered at path as this
172// caller should see it: the CLI's path in place of the registered one
173// where they differ, and a leading <owner/name> optional for the CLI.
174func (c *Ctx) usageShape(path []string, usage string) string {
175 shape := c.shownAs(joinPath(path), usage)
176176 if c.viaCLI() {
177177 shape = cliUsage(shape)
178178 }
@@ -182,7 +182,7 @@ func (c *Ctx) usageShape(cmd Command) string {
182182// cmdUsage is the running command's usage with the program in front, as
183183// a usage refusal prints it.
184184func (c *Ctx) cmdUsage() string {
185 return c.program() + " " + c.usageShape(c.Cmd)
185 return c.program() + " " + c.usageShape(c.Cmd.Path, c.Cmd.Usage)
186186}
187187
188188func (c *Ctx) heading(w io.Writer, s string) {
@@ -217,7 +217,7 @@ func (c *Ctx) helpVerb(w io.Writer, cmd Command, below []Command) {
217217 // (notifications read <id>... | --all) has no " [--" to cut at, so
218218 // the usage prints whole.
219219 registered := joinPath(cmd.Path)
220 shape := c.usageShape(cmd)
220 shape := c.usageShape(cmd.Path, cmd.Usage)
221221 if i := strings.Index(shape, " [--"); i >= 0 {
222222 shape = shape[:i] + " [flags]"
223223 }
internal/control/identity.go +1 −1
@@ -152,7 +152,7 @@ func expiresText(t *time.Time, now time.Time) string {
152152}
153153
154154func 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})
156156 if err != nil {
157157 return c.fail(protocol.ExitUsage, "%v", err)
158158 }
internal/control/import.go +1 −1
@@ -39,7 +39,7 @@ esac
3939`
4040
4141func 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,
4343 Usage: "repo import <owner/name> --from <url> [--private] [--token-stdin]"})
4444 if err != nil {
4545 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 {
178178}
179179
180180func 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,
182182 Usage: "issue create <owner/name> --title <t> [--body <b> | --file -] [--format md|org]"})
183183 if err != nil {
184184 return c.fail(protocol.ExitUsage, "%v", err)
@@ -231,7 +231,7 @@ func runIssueList(c *Ctx, args []string) int {
231231 return code
232232 }
233233 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})
235235 if err != nil {
236236 return c.fail(protocol.ExitUsage, "%v", err)
237237 }
@@ -371,7 +371,7 @@ func setIssueState(c *Ctx, args []string, state string) int {
371371// they are accepted and reported in the returned flags, and count toward
372372// "at least one edit was given" alongside title/body/format.
373373func 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,
375375 Usage: kind + " edit <owner/name> <n> [--title <t>] [--body <b> | --file -] [--format md|org]"})
376376 if err != nil {
377377 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 {
6868}
6969
7070func 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})
7272 if err != nil {
7373 return c.fail(protocol.ExitUsage, "%v", err)
7474 }
internal/control/migrate.go +1 −1
@@ -155,7 +155,7 @@ func migAttribution(src, kind, author, date string, n int64) string {
155155// the git push that follows cannot be refused by them. Resumable: markers
156156// skip everything already imported.
157157func 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"})
159159 if err != nil {
160160 return c.fail(protocol.ExitUsage, "%v", err)
161161 }
internal/control/milestone.go +2 −2
@@ -62,7 +62,7 @@ func init() {
6262var duePat = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
6363
6464func 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,
6666 Usage: "milestone create <owner/name> <title> [--description <d>] [--due YYYY-MM-DD]"})
6767 if err != nil {
6868 return c.fail(protocol.ExitUsage, "%v", err)
@@ -93,7 +93,7 @@ func runMilestoneCreate(c *Ctx, args []string) int {
9393}
9494
9595func 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]"})
9797 if err != nil {
9898 return c.fail(protocol.ExitUsage, "%v", err)
9999 }
internal/control/mirrorcmd.go +1 −1
@@ -43,7 +43,7 @@ func init() {
4343}
4444
4545func 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,
4747 Usage: "repo mirror add <owner/name> <url> --direction push|pull [--username <u>] [--token-stdin]"})
4848 if err != nil {
4949 return c.fail(protocol.ExitUsage, "%v", err)
internal/control/mr.go +6 −6
@@ -207,7 +207,7 @@ type ForkOut struct {
207207}
208208
209209func 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>]"})
211211 if err != nil {
212212 return c.fail(protocol.ExitUsage, "%v", err)
213213 }
@@ -393,7 +393,7 @@ func mrRef(c *Ctx, args []string, perm func(store.User, store.Repo, string) bool
393393func mrHeadRef(n int64) string { return fmt.Sprintf("refs/merge-requests/%d/head", n) }
394394
395395func 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"},
397397 Bools: []string{"--draft"}, MaxPos: 1,
398398 Usage: "mr create <target owner/name> --source [owner/name:]<branch> --target <branch> --title <t> [--draft]"})
399399 if err != nil {
@@ -566,7 +566,7 @@ func runMRList(c *Ctx, args []string) int {
566566 return code
567567 }
568568 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})
570570 if err != nil {
571571 return c.fail(protocol.ExitUsage, "%v", err)
572572 }
@@ -1205,7 +1205,7 @@ func runMRLabel(c *Ctx, args []string) int {
12051205}
12061206
12071207func 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]"})
12091209 if err != nil {
12101210 return c.fail(protocol.ExitUsage, "%v", err)
12111211 }
@@ -1775,7 +1775,7 @@ func setMRDraft(c *Ctx, args []string, draft bool) int {
17751775}
17761776
17771777func 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,
17791779 Usage: "mr close <owner/name> <n> [--by <m>]"})
17801780 if err != nil {
17811781 return c.fail(protocol.ExitUsage, "%v", err)
@@ -1907,7 +1907,7 @@ func runMRRevisions(c *Ctx, args []string) int {
19071907}
19081908
19091909func 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})
19111911 if err != nil {
19121912 return c.fail(protocol.ExitUsage, "%v", err)
19131913 }
internal/control/notifications.go +3 −3
@@ -285,7 +285,7 @@ func runNotificationsSettingsPush(c *Ctx, args []string) int {
285285const maxDeviceTokenBytes = 512
286286
287287func 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})
289289 if err != nil {
290290 return c.fail(protocol.ExitUsage, "%v", err)
291291 }
@@ -389,7 +389,7 @@ func runNotificationsList(c *Ctx, args []string) int {
389389 if code >= 0 {
390390 return code
391391 }
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})
393393 if err != nil {
394394 return c.fail(protocol.ExitUsage, "%v", err)
395395 }
@@ -443,7 +443,7 @@ func runNotificationsList(c *Ctx, args []string) int {
443443}
444444
445445func 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})
447447 if err != nil {
448448 return c.fail(protocol.ExitUsage, "%v", err)
449449 }
internal/control/org.go +1 −1
@@ -214,7 +214,7 @@ func runOrgDelete(c *Ctx, args []string) int {
214214}
215215
216216func 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]"})
218218 if err != nil {
219219 return c.fail(protocol.ExitUsage, "%v", err)
220220 }
internal/control/orglabel.go +3 −3
@@ -86,7 +86,7 @@ func orgReader(c *Ctx, name string) (store.Org, []int64, int) {
8686}
8787
8888func 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})
9090 if err != nil {
9191 return c.fail(protocol.ExitUsage, "%v", err)
9292 }
@@ -180,7 +180,7 @@ func runOrgLabelRemove(c *Ctx, args []string) int {
180180}
181181
182182func 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})
184184 if err != nil {
185185 return c.fail(protocol.ExitUsage, "%v", err)
186186 }
@@ -212,7 +212,7 @@ func runOrgMilestoneCreate(c *Ctx, args []string) int {
212212}
213213
214214func 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]"})
216216 if err != nil {
217217 return c.fail(protocol.ExitUsage, "%v", err)
218218 }
internal/control/read.go +2 −2
@@ -110,7 +110,7 @@ func runRepoRefs(c *Ctx, args []string) int {
110110const BlameSpan = 1000
111111
112112func 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})
114114 if err != nil {
115115 return c.fail(protocol.ExitUsage, "%v", err)
116116 }
@@ -220,7 +220,7 @@ func runRepoBlame(c *Ctx, args []string) int {
220220// off argv. Positionals are returned in order so each command can name them
221221// in its own usage message.
222222func 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})
224224 if err != nil {
225225 return nil, "", c.fail(protocol.ExitUsage, "%v", err)
226226 }
internal/control/release.go +2 −2
@@ -111,7 +111,7 @@ func releaseRef(c *Ctx, args []string, perm func(store.User, store.Repo, string)
111111}
112112
113113func 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})
115115 if err != nil {
116116 return c.fail(protocol.ExitUsage, "%v", err)
117117 }
@@ -183,7 +183,7 @@ func releaseToOut(r store.Release, withNotes bool) releaseOut {
183183}
184184
185185func 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})
187187 if err != nil {
188188 return c.fail(protocol.ExitUsage, "%v", err)
189189 }
internal/control/repo.go +3 −3
@@ -249,7 +249,7 @@ func resolveRepo(c *Ctx, path string, check func(store.User, store.Repo, string)
249249}
250250
251251func 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>]"})
253253 if err != nil {
254254 return c.fail(protocol.ExitUsage, "%v", err)
255255 }
@@ -1020,7 +1020,7 @@ func MatchesRepo(q, path, desc string, topics []string) bool {
10201020}
10211021
10221022func 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>]"})
10241024 if err != nil {
10251025 return c.fail(protocol.ExitUsage, "%v", err)
10261026 }
@@ -1246,7 +1246,7 @@ func setProtect(c *Ctx, args []string, protect bool) int {
12461246// base, measured from their merge base the way a merge request diff is,
12471247// so a base that moved on does not show up as removals (#118).
12481248func 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>"})
12501250 if err != nil || len(f.Pos) != 3 {
12511251 return c.usage()
12521252 }
internal/control/runnerrepo.go +1 −1
@@ -37,7 +37,7 @@ func init() {
3737}
3838
3939func 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"})
4141 if err != nil || len(f.Pos) != 1 {
4242 return c.usage()
4343 }
internal/control/search.go +1 −1
@@ -84,7 +84,7 @@ func Search(st *store.Store, root string, userID int64, q string, kinds []string
8484}
8585
8686func 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})
8888 if err != nil {
8989 return c.fail(protocol.ExitUsage, "%v", err)
9090 }
internal/control/sig.go +1 −1
@@ -141,7 +141,7 @@ func VerifyCommitCached(st *store.Store, repo store.Repo, parsed *sig.Commit, sh
141141}
142142
143143func 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>]"})
145145 if perr != nil {
146146 return c.fail(protocol.ExitUsage, "%v", perr)
147147 }
internal/control/snippet.go +2 −2
@@ -158,7 +158,7 @@ func newSnippetID() string {
158158}
159159
160160func 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})
162162 if err != nil {
163163 return c.fail(protocol.ExitUsage, "%v", err)
164164 }
@@ -287,7 +287,7 @@ func runSnippetList(c *Ctx, args []string) int {
287287}
288288
289289func 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})
291291 if err != nil {
292292 return c.fail(protocol.ExitUsage, "%v", err)
293293 }
internal/control/thread.go +1 −1
@@ -77,7 +77,7 @@ func runComment(c *Ctx, args []string, t thread, noun string,
7777 add func(id, userID int64, body, format string) error,
7878 participants func(id int64) ([]int64, error),
7979) 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,
8181 Usage: noun + " comment <owner/name> <n> [--message <m> | --file -] [--format md|org]"})
8282 if err != nil {
8383 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) {
6565}
6666
6767func 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})
6969 if err != nil {
7070 return c.fail(protocol.ExitUsage, "%v", err)
7171 }
@@ -128,7 +128,7 @@ func runTokenList(c *Ctx, args []string) int {
128128}
129129
130130func 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})
132132 if err != nil {
133133 return c.fail(protocol.ExitUsage, "%v", err)
134134 }
internal/control/webhook.go +2 −2
@@ -45,7 +45,7 @@ func init() {
4545}
4646
4747func 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|*]"})
4949 if err != nil {
5050 return c.fail(protocol.ExitUsage, "%v", err)
5151 }
@@ -136,7 +136,7 @@ func runWebhookRemove(c *Ctx, args []string) int {
136136}
137137
138138func 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]"})
140140 if err != nil {
141141 return c.fail(protocol.ExitUsage, "%v", err)
142142 }