diff --git a/cmd/ghcs/code.go b/cmd/ghcs/code.go index 4880436ed..ac5bffe8b 100644 --- a/cmd/ghcs/code.go +++ b/cmd/ghcs/code.go @@ -14,8 +14,9 @@ import ( func NewCodeCmd() *cobra.Command { return &cobra.Command{ - Use: "code", - Short: "Open a GitHub Codespace in VSCode.", + Use: "code []", + Short: "Open a Codespace in VS Code", + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var codespaceName string if len(args) > 0 { diff --git a/cmd/ghcs/create.go b/cmd/ghcs/create.go index b4a4fcb1f..bb2e18eff 100644 --- a/cmd/ghcs/create.go +++ b/cmd/ghcs/create.go @@ -19,7 +19,8 @@ var repo, branch, machine string func newCreateCmd() *cobra.Command { createCmd := &cobra.Command{ Use: "create", - Short: "Create a GitHub Codespace.", + Short: "Create a Codespace", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return Create() }, diff --git a/cmd/ghcs/delete.go b/cmd/ghcs/delete.go index d625a1ca3..d79bcc448 100644 --- a/cmd/ghcs/delete.go +++ b/cmd/ghcs/delete.go @@ -2,7 +2,6 @@ package main import ( "context" - "errors" "fmt" "os" @@ -14,8 +13,9 @@ import ( func NewDeleteCmd() *cobra.Command { deleteCmd := &cobra.Command{ - Use: "delete", - Short: "Delete a GitHub Codespace.", + Use: "delete []", + Short: "Delete a Codespace", + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var codespaceName string if len(args) > 0 { @@ -27,22 +27,18 @@ func NewDeleteCmd() *cobra.Command { deleteAllCmd := &cobra.Command{ Use: "all", - Short: "delete all codespaces", - Long: "delete all codespaces for the user with the current token", + Short: "Delete all Codespaces for the current user", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return DeleteAll() }, } deleteByRepoCmd := &cobra.Command{ - Use: "repo REPO_NAME", - Short: "delete all codespaces for the repo", - Long: `delete all the codespaces that the user with the current token has in this repo. -This includes all codespaces in all states.`, + Use: "repo ", + Short: "Delete all Codespaces for a repository", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errors.New("A Repository name is required.") - } return DeleteByRepo(args[0]) }, } diff --git a/cmd/ghcs/list.go b/cmd/ghcs/list.go index acc01b7ad..27b11d4fd 100644 --- a/cmd/ghcs/list.go +++ b/cmd/ghcs/list.go @@ -19,7 +19,8 @@ func NewListCmd() *cobra.Command { listCmd := &cobra.Command{ Use: "list", - Short: "List GitHub Codespaces you have on your account.", + Short: "List your Codespaces", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return List(opts) }, diff --git a/cmd/ghcs/logs.go b/cmd/ghcs/logs.go index 45fd8bca8..dd8664597 100644 --- a/cmd/ghcs/logs.go +++ b/cmd/ghcs/logs.go @@ -16,8 +16,9 @@ func NewLogsCmd() *cobra.Command { var tail bool logsCmd := &cobra.Command{ - Use: "logs", + Use: "logs []", Short: "Access Codespace logs", + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var codespaceName string if len(args) > 0 { diff --git a/cmd/ghcs/main.go b/cmd/ghcs/main.go index a2617788a..58037437a 100644 --- a/cmd/ghcs/main.go +++ b/cmd/ghcs/main.go @@ -1,33 +1,46 @@ package main import ( + "errors" "fmt" + "io" "os" "github.com/spf13/cobra" ) func main() { - Execute() + if err := rootCmd.Execute(); err != nil { + explainError(os.Stderr, err) + os.Exit(1) + } } var Version = "DEV" var rootCmd = &cobra.Command{ - Use: "ghcs", - Short: "Unofficial GitHub Codespaces CLI.", - Long: "Unofficial CLI tool to manage and interact with GitHub Codespaces.", + Use: "ghcs", + Long: `Unofficial CLI tool to manage GitHub Codespaces. + +Running commands requires the GITHUB_TOKEN environment variable to be set to a +token to access the GitHub API with.`, Version: Version, + + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if os.Getenv("GITHUB_TOKEN") == "" { + return tokenError + } + return nil + }, } -func Execute() { - if os.Getenv("GITHUB_TOKEN") == "" { - fmt.Fprintln(os.Stderr, "The GITHUB_TOKEN environment variable is required. Create a Personal Access Token at https://github.com/settings/tokens/new?scopes=repo and make sure to enable SSO for the GitHub organization after creating the token.") - os.Exit(1) - } +var tokenError = errors.New("GITHUB_TOKEN is missing") - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) +func explainError(w io.Writer, err error) { + if errors.Is(err, tokenError) { + fmt.Fprintln(w, "The GITHUB_TOKEN environment variable is required. Create a Personal Access Token at https://github.com/settings/tokens/new?scopes=repo") + fmt.Fprintln(w, "Make sure to enable SSO for your organizations after creating the token.") + return } + // fmt.Fprintf(w, "%v\n", err) } diff --git a/cmd/ghcs/ports.go b/cmd/ghcs/ports.go index 1d5d5ff9f..6bbf05091 100644 --- a/cmd/ghcs/ports.go +++ b/cmd/ghcs/ports.go @@ -28,7 +28,8 @@ func NewPortsCmd() *cobra.Command { portsCmd := &cobra.Command{ Use: "ports", - Short: "Forward ports from a GitHub Codespace.", + Short: "List ports in a Codespace", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return Ports(opts) }, @@ -168,14 +169,10 @@ func getDevContainer(ctx context.Context, apiClient *api.API, codespace *api.Cod func NewPortsPublicCmd() *cobra.Command { return &cobra.Command{ - Use: "public", - Short: "public", - Long: "public", + Use: "public ", + Short: "Mark port as public", + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - if len(args) < 2 { - return errors.New("[codespace_name] [source] port number are required.") - } - log := output.NewLogger(os.Stdout, os.Stderr, false) return updatePortVisibility(log, args[0], args[1], true) }, @@ -184,14 +181,10 @@ func NewPortsPublicCmd() *cobra.Command { func NewPortsPrivateCmd() *cobra.Command { return &cobra.Command{ - Use: "private", - Short: "private", - Long: "private", + Use: "private ", + Short: "Mark port as private", + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - if len(args) < 2 { - return errors.New("[codespace_name] [source] port number are required.") - } - log := output.NewLogger(os.Stdout, os.Stderr, false) return updatePortVisibility(log, args[0], args[1], false) }, @@ -247,14 +240,10 @@ func updatePortVisibility(log *output.Logger, codespaceName, sourcePort string, func NewPortsForwardCmd() *cobra.Command { return &cobra.Command{ - Use: "forward", - Short: "forward", - Long: "forward", + Use: "forward ", + Short: "Forward port", + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { - if len(args) < 3 { - return errors.New("[codespace_name] [source] [dst] port number are required.") - } - log := output.NewLogger(os.Stdout, os.Stderr, false) return forwardPort(log, args[0], args[1], args[2]) }, diff --git a/cmd/ghcs/ssh.go b/cmd/ghcs/ssh.go index 01e575781..1754f968a 100644 --- a/cmd/ghcs/ssh.go +++ b/cmd/ghcs/ssh.go @@ -21,14 +21,15 @@ func NewSSHCmd() *cobra.Command { sshCmd := &cobra.Command{ Use: "ssh", - Short: "SSH into a GitHub Codespace, for use with running tests/editing in vim, etc.", + Short: "SSH into a Codespace", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return SSH(sshProfile, codespaceName, sshServerPort) }, } - sshCmd.Flags().StringVarP(&sshProfile, "profile", "", "", "SSH Profile") - sshCmd.Flags().IntVarP(&sshServerPort, "server-port", "", 0, "SSH Server Port") + sshCmd.Flags().StringVarP(&sshProfile, "profile", "", "", "The `name` of the SSH profile to use") + sshCmd.Flags().IntVarP(&sshServerPort, "server-port", "", 0, "SSH server port number") sshCmd.Flags().StringVarP(&codespaceName, "codespace", "c", "", "The `name` of the Codespace to use") return sshCmd