diff --git a/cmd/ghcs/code.go b/cmd/ghcs/code.go index 81dbdbb2c..fd71da74f 100644 --- a/cmd/ghcs/code.go +++ b/cmd/ghcs/code.go @@ -57,8 +57,9 @@ func Code(codespaceName string, useInsiders bool) error { codespaceName = codespace.Name } - if err := open.Run(vscodeProtocolURL(codespaceName, useInsiders)); err != nil { - return fmt.Errorf("error opening vscode URL") + url := vscodeProtocolURL(codespaceName, useInsiders) + if err := open.Run(url); err != nil { + return fmt.Errorf("error opening vscode URL %s: %s. (Is VSCode installed?)", url, err) } return nil diff --git a/cmd/ghcs/create.go b/cmd/ghcs/create.go index 6b6d10511..c789b4136 100644 --- a/cmd/ghcs/create.go +++ b/cmd/ghcs/create.go @@ -199,11 +199,11 @@ func getRepoName(repo string) (string, error) { repoSurvey := []*survey.Question{ { Name: "repository", - Prompt: &survey.Input{Message: "Repository"}, + Prompt: &survey.Input{Message: "Repository:"}, Validate: survey.Required, }, } - err := survey.Ask(repoSurvey, &repo) + err := ask(repoSurvey, &repo) return repo, err } @@ -216,11 +216,11 @@ func getBranchName(branch string) (string, error) { branchSurvey := []*survey.Question{ { Name: "branch", - Prompt: &survey.Input{Message: "Branch"}, + Prompt: &survey.Input{Message: "Branch:"}, Validate: survey.Required, }, } - err := survey.Ask(branchSurvey, &branch) + err := ask(branchSurvey, &branch) return branch, err } @@ -273,7 +273,7 @@ func getMachineName(ctx context.Context, machine string, user *api.User, repo *a } var skuAnswers struct{ SKU string } - if err := survey.Ask(skuSurvey, &skuAnswers); err != nil { + if err := ask(skuSurvey, &skuAnswers); err != nil { return "", fmt.Errorf("error getting SKU: %v", err) } @@ -282,3 +282,8 @@ func getMachineName(ctx context.Context, machine string, user *api.User, repo *a return machine, nil } + +// ask asks survery questions using standard options. +func ask(qs []*survey.Question, response interface{}) error { + return survey.Ask(qs, response, survey.WithShowCursor(true)) +} diff --git a/cmd/ghcs/ports.go b/cmd/ghcs/ports.go index ed8c2c55e..7d9ba6bdc 100644 --- a/cmd/ghcs/ports.go +++ b/cmd/ghcs/ports.go @@ -19,11 +19,17 @@ import ( "golang.org/x/sync/errgroup" ) +// PortOptions represents the options accepted by the ports command. type PortsOptions struct { + // CodespaceName is the name of the codespace, optional. CodespaceName string - AsJSON bool + + // AsJSON dictates whether the command returns a json output or not, optional. + AsJSON bool } +// NewPortsCmd returns a Cobra "ports" command that displays a table of available ports, +// according to the specified flags. func NewPortsCmd() *cobra.Command { opts := &PortsOptions{} @@ -32,7 +38,7 @@ func NewPortsCmd() *cobra.Command { Short: "List ports in a Codespace", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - return Ports(opts) + return ports(opts) }, } @@ -50,7 +56,7 @@ func init() { rootCmd.AddCommand(NewPortsCmd()) } -func Ports(opts *PortsOptions) error { +func ports(opts *PortsOptions) error { apiClient := api.New(os.Getenv("GITHUB_TOKEN")) ctx := context.Background() log := output.NewLogger(os.Stdout, os.Stderr, opts.AsJSON) @@ -87,7 +93,7 @@ func Ports(opts *PortsOptions) error { } table := output.NewTable(os.Stdout, opts.AsJSON) - table.SetHeader([]string{"Label", "Source Port", "Destination Port", "Public", "Browse URL"}) + table.SetHeader([]string{"Label", "Port", "Public", "Browse URL"}) for _, port := range ports { sourcePort := strconv.Itoa(port.SourcePort) var portName string @@ -100,7 +106,6 @@ func Ports(opts *PortsOptions) error { table.Append([]string{ portName, sourcePort, - strconv.Itoa(port.DestinationPort), strings.ToUpper(strconv.FormatBool(port.IsPublic)), fmt.Sprintf("https://%s-%s.githubpreview.dev/", codespace.Name, sourcePort), }) @@ -168,6 +173,8 @@ func getDevContainer(ctx context.Context, apiClient *api.API, codespace *api.Cod return ch } +// NewPortsPublicCmd returns a Cobra "ports public" subcommand, which makes a given port public. +// to make a given port public. func NewPortsPublicCmd() *cobra.Command { return &cobra.Command{ Use: "public ", @@ -180,6 +187,7 @@ func NewPortsPublicCmd() *cobra.Command { } } +// NewPortsPrivateCmd returns a Cobra "ports private" subcommand, which makes a given port private. func NewPortsPrivateCmd() *cobra.Command { return &cobra.Command{ Use: "private ", @@ -239,6 +247,8 @@ func updatePortVisibility(log *output.Logger, codespaceName, sourcePort string, return nil } +// NewPortsForwardCmd returns a Cobra "ports forward" subcommand, which forwards a set of +// port pairs from the codespace to localhost. func NewPortsForwardCmd() *cobra.Command { return &cobra.Command{ Use: "forward :",