Commit 3fc5fe7f24

3fc5fe7f247636086983ad0bbc48a16cd7f0010a

parent: 99ec0bbcaf

Verified · cmc

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

control: examples redirect like a shell

Ref #254
internal/control/commitfile.go +1 −1
@@ -23,7 +23,7 @@ func init() {
2323 {"--file", "-", "read the new content from stdin", ""},
2424 },
2525 Examples: []string{
26 `repo commit-file krz/gitbay CHANGELOG.org --ref main --message "note the release" --file - '< CHANGELOG.org'`,
26 `repo commit-file krz/gitbay CHANGELOG.org --ref main --message "note the release" --file - < CHANGELOG.org`,
2727 },
2828 ReadsStdin: true,
2929 Run: runCommitFile,
internal/control/deploykey.go +1 −1
@@ -19,7 +19,7 @@ func init() {
1919 Flags: []Flag{
2020 {"--rw", "", "the key may push, not just fetch", ""},
2121 },
22 Examples: []string{"repo deploy-key add krz/gitbay '< key.pub'"},
22 Examples: []string{"repo deploy-key add krz/gitbay < key.pub"},
2323 ReadsStdin: true, Run: runDeployKeyAdd})
2424 register(Command{Path: []string{"repo", "deploy-key", "list"},
2525 Summary: "list deploy keys",
internal/control/diffcomment.go +1 −1
@@ -29,7 +29,7 @@ func init() {
2929 },
3030 Examples: []string{
3131 `mr diff-comment krz/gitbay 431 --path internal/control/build.go --line 42 --message "why is this a switch"`,
32 "mr diff-comment krz/gitbay 431 --reply 12 --file - '< notes.md'",
32 "mr diff-comment krz/gitbay 431 --reply 12 --file - < notes.md",
3333 },
3434 ReadsStdin: true, Run: runDiffComment})
3535 register(Command{Path: []string{"mr", "threads"},
internal/control/explore.go +1 −1
@@ -31,7 +31,7 @@ func init() {
3131 Flags: []Flag{
3232 {"--ref", "<r>", "branch, tag or commit to archive", ""},
3333 },
34 Examples: []string{"repo download krz/gitbay --ref main '> gitbay.tar.gz'"},
34 Examples: []string{"repo download krz/gitbay --ref main > gitbay.tar.gz"},
3535 ReadOnly: true,
3636 Run: runRepoDownload,
3737 })
internal/control/help_test.go +11 −1
@@ -11,6 +11,12 @@ import (
1111
1212var usageFlag = regexp.MustCompile(`--[a-z][a-z0-9-]*`)
1313
14// trailingRedirect strips a shell redirect an example ends with, the way a
15// person's shell would before gitbay ever sees argv: protocol.Tokenize
16// rejects a bare < or > as a shell metacharacter, so the redirected part
17// is not something the command's own tokenizer parses.
18var trailingRedirect = regexp.MustCompile(`^(.*?)\s+[<>]\s*\S+$`)
19
1420// helpCovered restricts TestHelpIsComplete to the path prefixes whose help
1521// text this commit filled in. Task 4.3 fills the rest and removes this set.
1622// "org label" and "org milestone" name the two prefixes under "org" this
@@ -66,7 +72,11 @@ func TestHelpIsComplete(t *testing.T) {
6672 t.Errorf("%s: no example", path)
6773 }
6874 for _, ex := range cmd.Examples {
69 argv, err := protocol.Tokenize(ex)
75 toParse := ex
76 if m := trailingRedirect.FindStringSubmatch(ex); m != nil {
77 toParse = m[1]
78 }
79 argv, err := protocol.Tokenize(toParse)
7080 if err != nil {
7181 t.Errorf("%s: example %q: %v", path, ex, err)
7282 continue
internal/control/issue.go +3 −3
@@ -26,7 +26,7 @@ func init() {
2626 },
2727 Examples: []string{
2828 `issue create krz/gitbay --title "crash on empty repo" --body "steps to reproduce..."`,
29 "issue create krz/gitbay --title notes --file - '< notes.md'",
29 "issue create krz/gitbay --title notes --file - < notes.md",
3030 },
3131 ReadsStdin: true, Run: runIssueCreate})
3232 register(Command{Path: []string{"issue", "list"},
@@ -63,7 +63,7 @@ func init() {
6363 },
6464 Examples: []string{
6565 `issue edit krz/gitbay 42 --title "crash on empty repo, take two"`,
66 "issue edit krz/gitbay 42 --file - '< notes.md'",
66 "issue edit krz/gitbay 42 --file - < notes.md",
6767 },
6868 ReadsStdin: true, Run: runIssueEdit})
6969 register(Command{Path: []string{"issue", "comment"},
@@ -76,7 +76,7 @@ func init() {
7676 },
7777 Examples: []string{
7878 `issue comment krz/gitbay 42 --message "can't reproduce on main"`,
79 "issue comment krz/gitbay 42 --file - '< notes.md'",
79 "issue comment krz/gitbay 42 --file - < notes.md",
8080 },
8181 ReadsStdin: true, Run: runIssueComment})
8282 register(Command{Path: []string{"issue", "close"},
internal/control/mr.go +1 −1
@@ -71,7 +71,7 @@ func init() {
7171 },
7272 Examples: []string{
7373 `mr create krz/gitbay --source cli-output-help --target main --title "control: flag help"`,
74 "mr create krz/gitbay --source cli-output-help --target main --title notes --file - '< notes.md'",
74 "mr create krz/gitbay --source cli-output-help --target main --title notes --file - < notes.md",
7575 },
7676 ReadsStdin: true, Run: runMRCreate})
7777 register(Command{Path: []string{"mr", "range-diff"},
internal/control/release.go +3 −3
@@ -30,7 +30,7 @@ func init() {
3030 },
3131 Examples: []string{
3232 `release create krz/gitbay v1.31.0 --title "v1.31.0" --notes "flag help"`,
33 "release create krz/gitbay v1.31.0 --file - '< notes.md'",
33 "release create krz/gitbay v1.31.0 --file - < notes.md",
3434 },
3535 ReadsStdin: true, Run: runReleaseCreate})
3636 register(Command{Path: []string{"release", "edit"},
@@ -69,12 +69,12 @@ func init() {
6969 register(Command{Path: []string{"release", "asset", "add"},
7070 Summary: "upload an asset from stdin",
7171 Usage: "release asset add <owner/name> <tag> <filename> < file",
72 Examples: []string{"release asset add krz/gitbay v1.30.0 gitbay-darwin-arm64 '< gitbay-darwin-arm64'"},
72 Examples: []string{"release asset add krz/gitbay v1.30.0 gitbay-darwin-arm64 < gitbay-darwin-arm64"},
7373 ReadsStdin: true, Run: runAssetAdd})
7474 register(Command{Path: []string{"release", "asset", "get"},
7575 Summary: "write an asset to stdout",
7676 Usage: "release asset get <owner/name> <tag> <filename> > file",
77 Examples: []string{"release asset get krz/gitbay v1.30.0 gitbay-darwin-arm64 '> gitbay-darwin-arm64'"},
77 Examples: []string{"release asset get krz/gitbay v1.30.0 gitbay-darwin-arm64 > gitbay-darwin-arm64"},
7878 ReadOnly: true, Run: runAssetGet})
7979 register(Command{Path: []string{"release", "asset", "remove"},
8080 Summary: "remove an asset",
internal/control/runnerrepo.go +1 −1
@@ -21,7 +21,7 @@ func init() {
2121 register(Command{Path: []string{"repo", "runner", "add"},
2222 Summary: "attach a runner's public key to a repository",
2323 Usage: "repo runner add <owner/name> < key.pub",
24 Examples: []string{"repo runner add krz/gitbay '< key.pub'"},
24 Examples: []string{"repo runner add krz/gitbay < key.pub"},
2525 ReadsStdin: true, Run: runRepoRunnerAdd})
2626 register(Command{Path: []string{"repo", "runner", "list"},
2727 Summary: "list the runners attached to a repository",
internal/control/snippet.go +3 −3
@@ -25,7 +25,7 @@ func init() {
2525 {"--description", "<d>", "one line about the snippet", ""},
2626 {"--visibility", "public|unlisted|private", "who can find it", "unlisted"},
2727 },
28 Examples: []string{"snippet create notes.md --visibility private '< notes.md'"},
28 Examples: []string{"snippet create notes.md --visibility private < notes.md"},
2929 ReadsStdin: true, Run: runSnippetCreate})
3030 register(Command{Path: []string{"snippet", "show"},
3131 Summary: "show a snippet's metadata and files",
@@ -58,12 +58,12 @@ func init() {
5858 register(Command{Path: []string{"snippet", "file", "set"},
5959 Summary: "add a file to a snippet, or replace one, from stdin",
6060 Usage: "snippet file set <id> <filename> < file",
61 Examples: []string{"snippet file set a1b2c3 notes.md '< notes.md'"},
61 Examples: []string{"snippet file set a1b2c3 notes.md < notes.md"},
6262 ReadsStdin: true, Run: runSnippetFileSet})
6363 register(Command{Path: []string{"snippet", "file", "get"},
6464 Summary: "write a snippet file to stdout",
6565 Usage: "snippet file get <id> <filename> > file",
66 Examples: []string{"snippet file get a1b2c3 notes.md '> notes.md'"},
66 Examples: []string{"snippet file get a1b2c3 notes.md > notes.md"},
6767 ReadOnly: true, Run: runSnippetFileGet})
6868 register(Command{Path: []string{"snippet", "file", "remove"},
6969 Summary: "remove a file from a snippet",