| @@ -17,6 +17,15 @@ import ( |
| 17 | 17 | ) |
| 18 | 18 | |
| 19 | 19 | func main() { |
| 20 | if err := newRoot().Execute(); err != nil { |
| 21 | fmt.Fprintln(os.Stderr, "gitbay:", err) |
| 22 | os.Exit(protocol.ExitUsage) |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | // newRoot builds the command tree. Separate from main so the coverage |
| 27 | // test can walk it. |
| 28 | func newRoot() *cobra.Command { |
| 20 | 29 | root := &cobra.Command{ |
| 21 | 30 | Use: "gitbay", |
| 22 | 31 | Short: "CLI-first git forge client", |
| @@ -40,6 +49,12 @@ func main() { |
| 40 | 49 | passOpts{server: []string{"dashboard"}}), |
| 41 | 50 | pass("feed", "activity on repositories you can reach [--limit n] [--cursor c]", |
| 42 | 51 | passOpts{server: []string{"feed"}}), |
| 52 | pass("explore", "public repositories on this instance [--limit n] [--cursor c]", |
| 53 | passOpts{server: []string{"explore"}}), |
| 54 | group("wiki", "a repository's wiki pages", |
| 55 | pass("list", "list pages: [<owner/name>]", passOpts{server: []string{"wiki", "list"}, needsRepo: true}), |
| 56 | pass("show", "print a page: [<owner/name>] [<page>]", passOpts{server: []string{"wiki", "show"}, needsRepo: true}), |
| 57 | ), |
| 43 | 58 | repoCmd(), |
| 44 | 59 | issueCmd(), |
| 45 | 60 | milestoneCmd(), |
| @@ -57,15 +72,16 @@ func main() { |
| 57 | 72 | initCmd(), |
| 58 | 73 | pass("register", "create an account on the default instance: gitbay register --username <n> --email <a> | --invite <code>", |
| 59 | 74 | passOpts{server: []string{"register"}}), |
| 75 | pass("audit", "instance audit log (admins): [--limit <n>]", passOpts{server: []string{"audit"}}), |
| 60 | 76 | manCmd(root), |
| 61 | 77 | ) |
| 62 | | |
| 63 | | if err := root.Execute(); err != nil { |
| 64 | | fmt.Fprintln(os.Stderr, "gitbay:", err) |
| 65 | | os.Exit(protocol.ExitUsage) |
| 66 | | } |
| 78 | return root |
| 67 | 79 | } |
| 68 | 80 | |
| 81 | // serverPath is the annotation key holding a passthrough command's |
| 82 | // server-side path, so the tree can be checked against the registry. |
| 83 | const serverPath = "gitbay.server_path" |
| 84 | |
| 69 | 85 | // passOpts describes how one CLI command maps onto the server command. |
| 70 | 86 | type passOpts struct { |
| 71 | 87 | server []string // server-side command path |
| @@ -81,6 +97,7 @@ func pass(use, short string, o passOpts) *cobra.Command { |
| 81 | 97 | return &cobra.Command{ |
| 82 | 98 | Use: use, |
| 83 | 99 | Short: short, |
| 100 | Annotations: map[string]string{serverPath: strings.Join(o.server, " ")}, |
| 84 | 101 | DisableFlagParsing: true, |
| 85 | 102 | RunE: func(cmd *cobra.Command, args []string) error { |
| 86 | 103 | // cobra still owns `forge <cmd> --help`. |
| @@ -194,6 +211,7 @@ func authCmd() *cobra.Command { |
| 194 | 211 | } |
| 195 | 212 | pgpAdd := &cobra.Command{ |
| 196 | 213 | Use: "add", Short: "register an OpenPGP public key (armored, on stdin)", |
| 214 | Annotations: map[string]string{serverPath: "pgp add"}, |
| 197 | 215 | DisableFlagParsing: true, |
| 198 | 216 | RunE: func(cmd *cobra.Command, args []string) error { |
| 199 | 217 | t, err := resolveTarget() |
| @@ -245,6 +263,15 @@ func repoCmd() *cobra.Command { |
| 245 | 263 | pass("grep", "search file contents: <query> [--ref <ref>]", passOpts{server: []string{"repo", "grep"}, needsRepo: true}), |
| 246 | 264 | pass("tree", "list a directory: [<path>] [--ref <ref>]", passOpts{server: []string{"repo", "tree"}, needsRepo: true}), |
| 247 | 265 | pass("cat", "read a file: <path> [--ref <ref>]", passOpts{server: []string{"repo", "cat"}, needsRepo: true}), |
| 266 | pass("blame", "attribute lines to commits: <path> [--ref <ref>] [--from <n>] [--to <n>]", |
| 267 | passOpts{server: []string{"repo", "blame"}, needsRepo: true}), |
| 268 | pass("commit", "show one commit with its patch: <sha>", |
| 269 | passOpts{server: []string{"repo", "commit"}, needsRepo: true}), |
| 270 | pass("commit-file", "write a file and commit it: <path> [--ref <ref>] [--message <m>] --file -", |
| 271 | passOpts{server: []string{"repo", "commit-file"}, needsRepo: true, stdinOK: true}), |
| 272 | pass("refs", "list branches and tags", passOpts{server: []string{"repo", "refs"}, needsRepo: true}), |
| 273 | pass("download", "write a tar.gz of a ref to stdout: [--ref <r>] > repo.tar.gz", |
| 274 | passOpts{server: []string{"repo", "download"}, needsRepo: true}), |
| 248 | 275 | pass("pin", "pin a repository to your dashboard", passOpts{server: []string{"repo", "pin"}, needsRepo: true}), |
| 249 | 276 | pass("unpin", "unpin a repository", passOpts{server: []string{"repo", "unpin"}, needsRepo: true}), |
| 250 | 277 | pass("archive", "archive a repository (read-only)", passOpts{server: []string{"repo", "archive"}, needsRepo: true}), |
| @@ -293,6 +320,7 @@ func repoCmd() *cobra.Command { |
| 293 | 320 | pass("require-approvals", "require N fresh approvals to merge: <n>", passOpts{server: []string{"repo", "settings", "require-approvals"}, needsRepo: true}), |
| 294 | 321 | pass("require-resolved", "require threads resolved to merge: on|off", passOpts{server: []string{"repo", "settings", "require-resolved"}, needsRepo: true}), |
| 295 | 322 | pass("require-checks", "gate merges on green statuses: ... on|off", passOpts{server: []string{"repo", "settings", "require-checks"}, needsRepo: true}), |
| 323 | pass("visibility", "set repository visibility: public|private", passOpts{server: []string{"repo", "settings", "visibility"}, needsRepo: true}), |
| 296 | 324 | pass("require-signed", "require verified commit signatures: ... on|off", passOpts{server: []string{"repo", "settings", "require-signed"}, needsRepo: true}), |
| 297 | 325 | pass("description", "set the repository description: <text>", passOpts{server: []string{"repo", "settings", "description"}, needsRepo: true}), |
| 298 | 326 | pass("website", "set the repository website: <url> ('' clears)", passOpts{server: []string{"repo", "settings", "website"}, needsRepo: true}), |
| @@ -373,6 +401,7 @@ func importCmd() *cobra.Command { |
| 373 | 401 | return &cobra.Command{ |
| 374 | 402 | Use: "import", |
| 375 | 403 | Short: "server-side mirror of a foreign repo: gitbay repo import <owner/name> --from <url> [--private] [--token-stdin]", |
| 404 | Annotations: map[string]string{serverPath: "repo import"}, |
| 376 | 405 | DisableFlagParsing: true, |
| 377 | 406 | RunE: func(cmd *cobra.Command, args []string) error { |
| 378 | 407 | for _, a := range args { |