diff --git a/cmd/deploycreate.go b/cmd/deploycreate.go index f4bd8ba..060820a 100644 --- a/cmd/deploycreate.go +++ b/cmd/deploycreate.go @@ -40,6 +40,29 @@ var InteractiveDeployCreate = func(ctx context.Context, input types.DeployInput, })) } +func interactiveDeployCreate(cmd *cobra.Command, input types.DeployInput) tea.Cmd { + ctx := cmd.Context() + if input.ServiceID == "" { + return command.AddToStackFunc( + ctx, + cmd, + "Create Deploy", + &input, + views.NewServiceList(ctx, views.ServiceInput{}, func(ctx context.Context, r resource.Resource) tea.Cmd { + input.ServiceID = r.ID() + return InteractiveDeployCreate(ctx, input, resource.BreadcrumbForResource(r)) + }), + ) + } + + service, err := resource.GetResource(ctx, input.ServiceID) + if err != nil { + command.Fatal(cmd, err) + } + + return InteractiveDeployCreate(ctx, input, "Create Deploy for "+resource.BreadcrumbForResource(service)) +} + func init() { deployCreateCmd.RunE = func(cmd *cobra.Command, args []string) error { var input types.DeployInput @@ -60,12 +83,7 @@ func init() { return nil } - service, err := resource.GetResource(cmd.Context(), input.ServiceID) - if err != nil { - return err - } - - InteractiveDeployCreate(cmd.Context(), input, "Create Deploy for "+resource.BreadcrumbForResource(service)) + interactiveDeployCreate(cmd, input) return nil } diff --git a/cmd/deploylist.go b/cmd/deploylist.go index 437de7f..42c2e76 100644 --- a/cmd/deploylist.go +++ b/cmd/deploylist.go @@ -2,25 +2,25 @@ package cmd import ( "context" + "fmt" tea "github.com/charmbracelet/bubbletea" "github.com/spf13/cobra" "github.com/renderinc/cli/pkg/client" + "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/dashboard" "github.com/renderinc/cli/pkg/deploy" "github.com/renderinc/cli/pkg/pointers" - "github.com/renderinc/cli/pkg/text" - - "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/resource" + "github.com/renderinc/cli/pkg/text" "github.com/renderinc/cli/pkg/tui/views" ) var deployListCmd = &cobra.Command{ Use: "list [serviceID]", Short: "List deploys for a service", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), } var InteractiveDeployList = func(ctx context.Context, input views.DeployListInput, r resource.Resource, breadcrumb string) tea.Cmd { @@ -33,6 +33,29 @@ var InteractiveDeployList = func(ctx context.Context, input views.DeployListInpu )) } +func interactiveDeployList(cmd *cobra.Command, input views.DeployListInput) tea.Cmd { + ctx := cmd.Context() + if input.ServiceID == "" { + return command.AddToStackFunc( + ctx, + cmd, + "Deploys", + &input, + views.NewServiceList(ctx, views.ServiceInput{}, func(ctx context.Context, r resource.Resource) tea.Cmd { + input.ServiceID = r.ID() + return InteractiveDeployList(ctx, input, r, resource.BreadcrumbForResource(r)) + }), + ) + } + + service, err := resource.GetResource(ctx, input.ServiceID) + if err != nil { + command.Fatal(cmd, err) + } + + return InteractiveDeployList(ctx, input, service, "Deploys for "+resource.BreadcrumbForResource(service)) +} + func commandsForDeploy(dep *client.Deploy, serviceID, serviceType string) []views.PaletteCommand { var startTime *string if dep.CreatedAt != nil { @@ -92,9 +115,11 @@ func init() { deployCmd.AddCommand(deployListCmd) deployListCmd.RunE = func(cmd *cobra.Command, args []string) error { - serviceID := args[0] - - input := views.DeployListInput{ServiceID: serviceID} + var input views.DeployListInput + err := command.ParseCommand(cmd, args, &input) + if err != nil { + return fmt.Errorf("failed to parse command: %w", err) + } if nonInteractive, err := command.NonInteractive(cmd, func() ([]*client.Deploy, error) { _, res, err := views.LoadDeployList(cmd.Context(), input, "") @@ -105,12 +130,7 @@ func init() { return nil } - r, err := resource.GetResource(cmd.Context(), serviceID) - if err != nil { - return err - } - - InteractiveDeployList(cmd.Context(), input, r, "Deploys for "+resource.BreadcrumbForResource(r)) + interactiveDeployList(cmd, input) return nil } } diff --git a/cmd/jobcreate.go b/cmd/jobcreate.go index 816753e..255360e 100644 --- a/cmd/jobcreate.go +++ b/cmd/jobcreate.go @@ -7,6 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/spf13/cobra" + "github.com/renderinc/cli/pkg/client" clientjob "github.com/renderinc/cli/pkg/client/jobs" "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/resource" @@ -17,7 +18,7 @@ import ( var jobCreateCmd = &cobra.Command{ Use: "create [serviceID]", Short: "Create a new job for a service", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), } var InteractiveJobCreate = func(ctx context.Context, input *views.JobCreateInput, breadcrumb string) tea.Cmd { @@ -35,6 +36,31 @@ var InteractiveJobCreate = func(ctx context.Context, input *views.JobCreateInput ) } +func interactiveJobCreate(cmd *cobra.Command, input *views.JobCreateInput) tea.Cmd { + ctx := cmd.Context() + if input.ServiceID == "" { + return command.AddToStackFunc( + ctx, + cmd, + "Create Job", + input, + views.NewServiceList(ctx, views.ServiceInput{ + Types: []client.ServiceType{client.WebService, client.BackgroundWorker, client.PrivateService, client.CronJob}, + }, func(ctx context.Context, r resource.Resource) tea.Cmd { + input.ServiceID = r.ID() + return InteractiveJobCreate(ctx, input, resource.BreadcrumbForResource(r)) + }), + ) + } + + service, err := resource.GetResource(ctx, input.ServiceID) + if err != nil { + command.Fatal(cmd, err) + } + + return InteractiveJobCreate(ctx, input, "Create Job for "+resource.BreadcrumbForResource(service)) +} + func init() { jobCreateCmd.RunE = func(cmd *cobra.Command, args []string) error { var input views.JobCreateInput @@ -54,12 +80,7 @@ func init() { return nil } - r, err := resource.GetResource(cmd.Context(), input.ServiceID) - if err != nil { - return err - } - - InteractiveJobCreate(cmd.Context(), &input, "Create Job "+resource.BreadcrumbForResource(r)) + interactiveJobCreate(cmd, &input) return nil } diff --git a/cmd/joblist.go b/cmd/joblist.go index 87a59dc..ff44cb9 100644 --- a/cmd/joblist.go +++ b/cmd/joblist.go @@ -7,6 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/spf13/cobra" + "github.com/renderinc/cli/pkg/client" clientjob "github.com/renderinc/cli/pkg/client/jobs" "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/job" @@ -19,7 +20,7 @@ import ( var jobListCmd = &cobra.Command{ Use: "list [serviceID]", Short: "List jobs for a service", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), } var InteractiveJobList = func(ctx context.Context, input views.JobListInput, breadcrumb string) tea.Cmd { @@ -31,6 +32,31 @@ var InteractiveJobList = func(ctx context.Context, input views.JobListInput, bre )) } +func interactiveJobList(cmd *cobra.Command, input views.JobListInput) tea.Cmd { + ctx := cmd.Context() + if input.ServiceID == "" { + return command.AddToStackFunc( + ctx, + cmd, + "Jobs", + &input, + views.NewServiceList(ctx, views.ServiceInput{ + Types: []client.ServiceType{client.WebService, client.BackgroundWorker, client.PrivateService, client.CronJob}, + }, func(ctx context.Context, r resource.Resource) tea.Cmd { + input.ServiceID = r.ID() + return InteractiveJobList(ctx, input, resource.BreadcrumbForResource(r)) + }), + ) + } + + service, err := resource.GetResource(ctx, input.ServiceID) + if err != nil { + command.Fatal(cmd, err) + } + + return InteractiveJobList(ctx, input, "Jobs for "+resource.BreadcrumbForResource(service)) +} + func commandsForJob(j *clientjob.Job) []views.PaletteCommand { var startTime *string if j.StartedAt != nil { @@ -107,12 +133,7 @@ func init() { return nil } - r, err := resource.GetResource(cmd.Context(), input.ServiceID) - if err != nil { - return err - } - - InteractiveJobList(cmd.Context(), input, "Jobs for "+resource.BreadcrumbForResource(r)) + interactiveJobList(cmd, input) return nil } } diff --git a/pkg/command/formatter.go b/pkg/command/formatter.go index d100019..1d3970b 100644 --- a/pkg/command/formatter.go +++ b/pkg/command/formatter.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "os" "strings" "github.com/spf13/cobra" @@ -49,3 +50,12 @@ func Println(cmd *cobra.Command, format string, a ...any) { panic(err) } } + +func Fatal(cmd *cobra.Command, err error) { + _, err = cmd.OutOrStderr().Write([]byte(err.Error() + "\n")) + if err != nil { + panic(err) + } + + os.Exit(1) +} diff --git a/pkg/tui/views/jobcreate.go b/pkg/tui/views/jobcreate.go index 6ab761d..7764d1e 100644 --- a/pkg/tui/views/jobcreate.go +++ b/pkg/tui/views/jobcreate.go @@ -5,13 +5,14 @@ import ( "fmt" tea "github.com/charmbracelet/bubbletea" + "github.com/spf13/cobra" + "github.com/renderinc/cli/pkg/client" clientjob "github.com/renderinc/cli/pkg/client/jobs" "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/job" "github.com/renderinc/cli/pkg/pointers" "github.com/renderinc/cli/pkg/tui" - "github.com/spf13/cobra" ) type JobCreateInput struct { diff --git a/pkg/tui/views/servicelist.go b/pkg/tui/views/servicelist.go index 28ca71d..3425f6e 100644 --- a/pkg/tui/views/servicelist.go +++ b/pkg/tui/views/servicelist.go @@ -54,6 +54,7 @@ type ServiceInput struct { Project *client.Project EnvironmentIDs []string IncludePreviews bool + Types []client.ServiceType } func listServices(ctx context.Context, in ServiceInput) ([]*service.Model, error) { @@ -70,10 +71,13 @@ func listServices(ctx context.Context, in ServiceInput) ([]*service.Model, error listInput := &client.ListServicesParams{ IncludePreviews: pointers.From(in.IncludePreviews), - Type: &[]client.ServiceType{client.WebService, client.PrivateService, client.BackgroundWorker}, Limit: pointers.From(100), } + if len(in.Types) > 0 { + listInput.Type = &in.Types + } + if len(in.EnvironmentIDs) > 0 { listInput.EnvironmentId = &in.EnvironmentIDs } diff --git a/pkg/tui/views/ssh.go b/pkg/tui/views/ssh.go index a0813cb..d3d33db 100644 --- a/pkg/tui/views/ssh.go +++ b/pkg/tui/views/ssh.go @@ -6,6 +6,7 @@ import ( "os/exec" tea "github.com/charmbracelet/bubbletea" + "github.com/renderinc/cli/pkg/client" "github.com/renderinc/cli/pkg/command" "github.com/renderinc/cli/pkg/deploy" @@ -33,6 +34,7 @@ func NewSSHView(ctx context.Context, input *SSHInput, opts ...tui.TableOption[*s serviceListInput := ServiceInput{ Project: input.Project, EnvironmentIDs: input.EnvironmentIDs, + Types: []client.ServiceType{client.WebService, client.PrivateService, client.BackgroundWorker}, } if input.ServiceID == "" {