diff --git a/api/workspace.go b/api/workspace.go index cd93009..9d386ee 100644 --- a/api/workspace.go +++ b/api/workspace.go @@ -19,7 +19,16 @@ func (c *Client) ListWorkspaces(teamId int) ([]Workspace, error) { func (c *Client) GetWorkspace(workspaceId int) (Workspace, error) { workspace, _, err := c.api.WorkspacesAPI.WorkspacesGetWorkspace(c.ctx, float32(workspaceId)).Execute() - return *workspace, err + + if workspace != nil { + return *workspace, err + } + return Workspace{}, err +} + +func (c *Client) DeleteWorkspace(workspaceId int) error { + _, err := c.api.WorkspacesAPI.WorkspacesDeleteWorkspace(c.ctx, float32(workspaceId)).Execute() + return err } func (c *Client) WorkspaceStatus(workspaceId int) (*WorkspaceStatus, error) { diff --git a/cli/cmd/client.go b/cli/cmd/client.go index e5803f6..967e861 100644 --- a/cli/cmd/client.go +++ b/cli/cmd/client.go @@ -21,6 +21,7 @@ type Client interface { ExecCommand(workspaceId int, command string, workdir string, env map[string]string) (string, string, error) ListWorkspacePlans() ([]api.WorkspacePlan, error) DeployWorkspace(args api.DeployWorkspaceArgs) (*api.Workspace, error) + DeleteWorkspace(wsId int) error } func NewClient(opts GlobalOptions) (Client, error) { diff --git a/cli/cmd/create-workspace.go b/cli/cmd/create-workspace.go index b8bded8..2d21257 100644 --- a/cli/cmd/create-workspace.go +++ b/cli/cmd/create-workspace.go @@ -11,11 +11,10 @@ import ( "github.com/codesphere-cloud/cs-go/api" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) -// CreateWorkspaceCmd represents the workspace command type CreateWorkspaceCmd struct { cmd *cobra.Command Opts CreateWorkspaceOpts @@ -78,7 +77,7 @@ func AddCreateWorkspaceCmd(create *cobra.Command, opts GlobalOptions) { Use: "workspace", Short: "Create a workspace", Args: cobra.RangeArgs(1, 1), - Long: out.Long(`Create a workspace in Codesphere. + Long: io.Long(`Create a workspace in Codesphere. Specify a (private) git repository or start an empty workspace. Environment variables can be set to initialize the workspace with a specific environment. @@ -86,7 +85,7 @@ func AddCreateWorkspaceCmd(create *cobra.Command, opts GlobalOptions) { To decide which plan suits your needs, run 'cs list plans' `), - Example: out.FormatExampleCommands("create workspace my-workspace", []out.Example{ + Example: io.FormatExampleCommands("create workspace my-workspace", []io.Example{ {Cmd: "-p 20", Desc: "Create an empty workspace, using plan 20"}, {Cmd: "-r https://github.com/codesphere-cloud/landingpage-temp.git", Desc: "Create a workspace from a git repository"}, {Cmd: "-r https://github.com/codesphere-cloud/landingpage-temp.git -e DEPLOYMENT=prod -e A=B", Desc: "Create a workspace and set environment variables"}, diff --git a/cli/cmd/create.go b/cli/cmd/create.go index 580f90b..b95c2fb 100644 --- a/cli/cmd/create.go +++ b/cli/cmd/create.go @@ -7,7 +7,6 @@ import ( "github.com/spf13/cobra" ) -// CreateCmd represents the create command type CreateCmd struct { cmd *cobra.Command } diff --git a/cli/cmd/delete-workspace.go b/cli/cmd/delete-workspace.go new file mode 100644 index 0000000..48e8052 --- /dev/null +++ b/cli/cmd/delete-workspace.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "errors" + "fmt" + + "github.com/codesphere-cloud/cs-go/pkg/io" + "github.com/spf13/cobra" +) + +type Prompt interface { + InputPrompt(prompt string) string +} + +type DeleteWorkspaceCmd struct { + cmd *cobra.Command + Opts DeleteWorkspaceOpts + Prompt Prompt +} + +type DeleteWorkspaceOpts struct { + GlobalOptions + Confirmed *bool +} + +func (c *DeleteWorkspaceCmd) RunE(_ *cobra.Command, args []string) error { + wsId, err := c.Opts.GetWorkspaceId() + if err != nil { + return fmt.Errorf("failed to get workspace ID: %w", err) + } + + client, err := NewClient(c.Opts.GlobalOptions) + if err != nil { + return fmt.Errorf("failed to create Codesphere client: %w", err) + } + + return c.DeleteWorkspace(client, wsId) +} + +func AddDeleteWorkspaceCmd(delete *cobra.Command, opts GlobalOptions) { + workspace := DeleteWorkspaceCmd{ + cmd: &cobra.Command{ + Use: "workspace", + Short: "Delete workspace", + Long: io.Long(`Delete workspace after confirmation. + + Confirmation can be given interactively or with the --yes flag`), + }, + Opts: DeleteWorkspaceOpts{GlobalOptions: opts}, + Prompt: &io.Prompt{}, + } + workspace.Opts.Confirmed = workspace.cmd.Flags().Bool("yes", false, "Confirm deletion of workspace") + delete.AddCommand(workspace.cmd) + workspace.cmd.RunE = workspace.RunE +} + +func (c *DeleteWorkspaceCmd) DeleteWorkspace(client Client, wsId int) error { + + workspace, err := client.GetWorkspace(wsId) + if err != nil { + return fmt.Errorf("failed to get workspace %d: %w", wsId, err) + } + + if !*c.Opts.Confirmed { + fmt.Printf("Please confirm deletion of workspace '%s', ID %d, in team %d by entering its name:\n", workspace.Name, workspace.Id, workspace.TeamId) + confirmation := c.Prompt.InputPrompt("Confirmation delete") + + if confirmation != workspace.Name { + return errors.New("confirmation failed") + } + } + + return client.DeleteWorkspace(wsId) +} diff --git a/cli/cmd/delete.go b/cli/cmd/delete.go new file mode 100644 index 0000000..4b9f01c --- /dev/null +++ b/cli/cmd/delete.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +type DeleteCmd struct { + cmd *cobra.Command +} + +func AddDeleteCmd(rootCmd *cobra.Command, opt GlobalOptions) { + delete := DeleteCmd{ + cmd: &cobra.Command{ + Use: "delete", + Short: "Delete Codesphere resources", + Long: `Delete Codesphere resources, e.g. workspaces.`, + }, + } + rootCmd.AddCommand(delete.cmd) + + // Add child commands here + AddDeleteWorkspaceCmd(delete.cmd, opt) +} diff --git a/cli/cmd/delete_workspace_test.go b/cli/cmd/delete_workspace_test.go new file mode 100644 index 0000000..3f5a8c2 --- /dev/null +++ b/cli/cmd/delete_workspace_test.go @@ -0,0 +1,114 @@ +package cmd_test + +import ( + "errors" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/codesphere-cloud/cs-go/api" + "github.com/codesphere-cloud/cs-go/cli/cmd" +) + +var _ = Describe("CreateWorkspace", func() { + var ( + mockEnv *cmd.MockEnv + mockClient *cmd.MockClient + mockPrompt *cmd.MockPrompt + c *cmd.DeleteWorkspaceCmd + wsId int + wsName string + confirmed bool + ws api.Workspace + ) + + JustBeforeEach(func() { + mockClient = cmd.NewMockClient(GinkgoT()) + mockEnv = cmd.NewMockEnv(GinkgoT()) + mockPrompt = cmd.NewMockPrompt(GinkgoT()) + c = &cmd.DeleteWorkspaceCmd{ + Opts: cmd.DeleteWorkspaceOpts{ + GlobalOptions: cmd.GlobalOptions{ + Env: mockEnv, + WorkspaceId: &wsId, + }, + Confirmed: &confirmed, + }, + Prompt: mockPrompt, + } + }) + BeforeEach(func() { + ws = api.Workspace{ + Id: wsId, + Name: wsName, + } + }) + Context("Unconfirmed", func() { + BeforeEach(func() { + confirmed = false + wsName = "fake-ws" + }) + Context("Workspace exists", func() { + Context("Workspace name entered in confirmation prompt", func() { + It("deletes the workspace", func() { + mockClient.EXPECT().GetWorkspace(wsId).Return(ws, nil) + mockPrompt.EXPECT().InputPrompt("Confirmation delete").Return(ws.Name) + mockClient.EXPECT().DeleteWorkspace(wsId).Return(nil) + err := c.DeleteWorkspace(mockClient, wsId) + Expect(err).ToNot(HaveOccurred()) + }) + }) + Context("Wrong input entered in confirmation prompt", func() { + It("Returns an error", func() { + mockClient.EXPECT().GetWorkspace(wsId).Return(ws, nil) + mockPrompt.EXPECT().InputPrompt("Confirmation delete").Return("other-workspace") + err := c.DeleteWorkspace(mockClient, wsId) + Expect(err).To(MatchError("confirmation failed")) + }) + }) + }) + + }) + + Context("Confirmed via CLI flag", func() { + var ( + getWsErr error + ) + BeforeEach(func() { + wsId = 42 + ws = api.Workspace{} + confirmed = true + getWsErr = nil + }) + JustBeforeEach(func() { + fmt.Println(ws) + mockClient.EXPECT().GetWorkspace(wsId).Return(ws, getWsErr) + }) + Context("Workspace exists", func() { + BeforeEach(func() { + ws = api.Workspace{ + Id: wsId, + } + }) + It("Deletes the workspace", func() { + mockClient.EXPECT().DeleteWorkspace(wsId).Return(nil) + err := c.DeleteWorkspace(mockClient, wsId) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("Workspace doesn't exist", func() { + BeforeEach(func() { + ws = api.Workspace{} + getWsErr = errors.New("404") + }) + + It("Returns an error", func() { + err := c.DeleteWorkspace(mockClient, wsId) + Expect(err).To(MatchError("failed to get workspace 42: 404")) + }) + }) + }) + +}) diff --git a/cli/cmd/exec.go b/cli/cmd/exec.go index 1390ce5..61dfef0 100644 --- a/cli/cmd/exec.go +++ b/cli/cmd/exec.go @@ -9,12 +9,11 @@ import ( "strings" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) -// ExecCmd represents the exec command type ExecCmd struct { cmd *cobra.Command Opts ExecOptions @@ -44,9 +43,9 @@ func AddExecCmd(rootCmd *cobra.Command, opts GlobalOptions) { Use: "exec", Args: cobra.MinimumNArgs(1), Short: "Run a command in Codesphere workspace", - Long: out.Long(`Run a command in a Codesphere workspace. + Long: io.Long(`Run a command in a Codesphere workspace. Output will be printed to STDOUT, errors to STDERR.`), - Example: out.FormatExampleCommands("exec", []out.Example{ + Example: io.FormatExampleCommands("exec", []io.Example{ {Cmd: "-- echo hello world", Desc: "Print `hello world`"}, {Cmd: "-- find .", Desc: "List all files in workspace"}, {Cmd: "-d user -- find .", Desc: "List all files in the user directory"}, diff --git a/cli/cmd/licenses.go b/cli/cmd/licenses.go index 56e1c91..64a64d6 100644 --- a/cli/cmd/licenses.go +++ b/cli/cmd/licenses.go @@ -11,7 +11,6 @@ import ( "github.com/spf13/cobra" ) -// LicensesCmd represents the licenses command type LicensesCmd struct { cmd *cobra.Command } diff --git a/cli/cmd/list-plans.go b/cli/cmd/list-plans.go index e5de893..d0fa126 100644 --- a/cli/cmd/list-plans.go +++ b/cli/cmd/list-plans.go @@ -6,14 +6,13 @@ package cmd import ( "fmt" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/jedib0t/go-pretty/v6/table" "github.com/jedib0t/go-pretty/v6/text" "github.com/spf13/cobra" ) -// ListPlansCmd represents the plans command type ListPlansCmd struct { cmd *cobra.Command Opts GlobalOptions @@ -31,7 +30,7 @@ func (c *ListPlansCmd) RunE(_ *cobra.Command, args []string) error { return fmt.Errorf("failed to list plans: %s", err) } - t := out.GetTableWriter() + t := io.GetTableWriter() t.AppendHeader(table.Row{"ID", "Name", "On Demand", "CPU", "RAM(GiB)", "SSD(GiB)", "Price(USD)", "Max Replicas"}) t.SetColumnConfigs([]table.ColumnConfig{ {Name: "Price(USD)", Align: text.AlignRight}, @@ -71,7 +70,7 @@ func AddListPlansCmd(list *cobra.Command, opts GlobalOptions) { cmd: &cobra.Command{ Use: "plans", Short: "List available plans", - Long: out.Long(`List available workpace plans. + Long: io.Long(`List available workpace plans. When creating new workspaces you need to select a specific plan.`), }, diff --git a/cli/cmd/list-teams.go b/cli/cmd/list-teams.go index 036e83c..d1c7520 100644 --- a/cli/cmd/list-teams.go +++ b/cli/cmd/list-teams.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" @@ -24,7 +24,7 @@ func addListTeamsCmd(p *cobra.Command, opts GlobalOptions) { Use: "teams", Short: "List teams", Long: `List teams available in Codesphere`, - Example: out.FormatExampleCommands("list teams", []out.Example{ + Example: io.FormatExampleCommands("list teams", []io.Example{ {Desc: "List all teams"}, }), }, @@ -45,7 +45,7 @@ func (l *ListTeamsCmd) RunE(_ *cobra.Command, args []string) (err error) { return fmt.Errorf("failed to list teams: %w", err) } - t := out.GetTableWriter() + t := io.GetTableWriter() t.AppendHeader(table.Row{"P", "ID", "Name", "Role", "Default DC"}) for _, team := range teams { first := "" diff --git a/cli/cmd/list-workspaces.go b/cli/cmd/list-workspaces.go index ed8d085..6fd78ad 100644 --- a/cli/cmd/list-workspaces.go +++ b/cli/cmd/list-workspaces.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/codesphere-cloud/cs-go/api" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" @@ -24,7 +24,7 @@ func addListWorkspacesCmd(p *cobra.Command, opts GlobalOptions) { Use: "workspaces", Short: "List workspaces", Long: `List workspaces available in Codesphere`, - Example: out.FormatExampleCommands("list workspaces", []out.Example{ + Example: io.FormatExampleCommands("list workspaces", []io.Example{ {Cmd: "--team-id ", Desc: "List all workspaces"}, }), }, @@ -45,7 +45,7 @@ func (l *ListWorkspacesCmd) RunE(_ *cobra.Command, args []string) (err error) { return fmt.Errorf("failed to list workspaces: %w", err) } - t := out.GetTableWriter() + t := io.GetTableWriter() t.AppendHeader(table.Row{"Team ID", "ID", "Name", "Repository"}) for _, w := range workspaces { gitUrl := "" diff --git a/cli/cmd/list.go b/cli/cmd/list.go index 523da5a..f1eb7d5 100644 --- a/cli/cmd/list.go +++ b/cli/cmd/list.go @@ -4,7 +4,7 @@ package cmd import ( - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) @@ -18,7 +18,7 @@ func AddListCmd(rootCmd *cobra.Command, opts GlobalOptions) { Use: "list", Short: "List resources", Long: `List resources available in Codesphere`, - Example: out.FormatExampleCommands("list", []out.Example{ + Example: io.FormatExampleCommands("list", []io.Example{ {Cmd: "workspaces", Desc: "List all workspaces"}, }), }, diff --git a/cli/cmd/log.go b/cli/cmd/log.go index aca4801..d870537 100644 --- a/cli/cmd/log.go +++ b/cli/cmd/log.go @@ -18,7 +18,7 @@ import ( "sync" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + csio "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) @@ -58,14 +58,14 @@ func AddLogCmd(rootCmd *cobra.Command, opts GlobalOptions) { cmd: &cobra.Command{ Use: "log", Short: "Retrieve run logs from services", - Long: `You can retrieve logs based on the given scope. + Long: csio.Long(`You can retrieve logs based on the given scope. -If you provide the step number and server, it returns all logs from -all replicas of that server. + If you provide the step number and server, it returns all logs from + all replicas of that server. -If you provide a specific replica id, it will return the logs of -that replica only.`, - Example: out.FormatExampleCommands("log", []out.Example{ + If you provide a specific replica id, it will return the logs of + that replica only.`), + Example: csio.FormatExampleCommands("log", []csio.Example{ {Cmd: "-w 637128 -s app", Desc: "Get logs from a server"}, {Cmd: "-w 637128", Desc: "Get all logs of all servers"}, {Cmd: "-w 637128 -r workspace-213d7a8c-48b4-42e2-8f70-c905ab04abb5-58d657cdc5-m8rrp", Desc: "Get logs from a replica"}, diff --git a/cli/cmd/mocks.go b/cli/cmd/mocks.go index fa848e7..a19403e 100644 --- a/cli/cmd/mocks.go +++ b/cli/cmd/mocks.go @@ -36,6 +36,51 @@ func (_m *MockClient) EXPECT() *MockClient_Expecter { return &MockClient_Expecter{mock: &_m.Mock} } +// DeleteWorkspace provides a mock function for the type MockClient +func (_mock *MockClient) DeleteWorkspace(wsId int) error { + ret := _mock.Called(wsId) + + if len(ret) == 0 { + panic("no return value specified for DeleteWorkspace") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(int) error); ok { + r0 = returnFunc(wsId) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockClient_DeleteWorkspace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteWorkspace' +type MockClient_DeleteWorkspace_Call struct { + *mock.Call +} + +// DeleteWorkspace is a helper method to define mock.On call +// - wsId +func (_e *MockClient_Expecter) DeleteWorkspace(wsId interface{}) *MockClient_DeleteWorkspace_Call { + return &MockClient_DeleteWorkspace_Call{Call: _e.mock.On("DeleteWorkspace", wsId)} +} + +func (_c *MockClient_DeleteWorkspace_Call) Run(run func(wsId int)) *MockClient_DeleteWorkspace_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int)) + }) + return _c +} + +func (_c *MockClient_DeleteWorkspace_Call) Return(err error) *MockClient_DeleteWorkspace_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockClient_DeleteWorkspace_Call) RunAndReturn(run func(wsId int) error) *MockClient_DeleteWorkspace_Call { + _c.Call.Return(run) + return _c +} + // DeployWorkspace provides a mock function for the type MockClient func (_mock *MockClient) DeployWorkspace(args api.DeployWorkspaceArgs) (*api.Workspace, error) { ret := _mock.Called(args) @@ -421,6 +466,78 @@ func (_c *MockClient_SetEnvVarOnWorkspace_Call) RunAndReturn(run func(workspaceI return _c } +// NewMockPrompt creates a new instance of MockPrompt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPrompt(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPrompt { + mock := &MockPrompt{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +// MockPrompt is an autogenerated mock type for the Prompt type +type MockPrompt struct { + mock.Mock +} + +type MockPrompt_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPrompt) EXPECT() *MockPrompt_Expecter { + return &MockPrompt_Expecter{mock: &_m.Mock} +} + +// InputPrompt provides a mock function for the type MockPrompt +func (_mock *MockPrompt) InputPrompt(prompt string) string { + ret := _mock.Called(prompt) + + if len(ret) == 0 { + panic("no return value specified for InputPrompt") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func(string) string); ok { + r0 = returnFunc(prompt) + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// MockPrompt_InputPrompt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InputPrompt' +type MockPrompt_InputPrompt_Call struct { + *mock.Call +} + +// InputPrompt is a helper method to define mock.On call +// - prompt +func (_e *MockPrompt_Expecter) InputPrompt(prompt interface{}) *MockPrompt_InputPrompt_Call { + return &MockPrompt_InputPrompt_Call{Call: _e.mock.On("InputPrompt", prompt)} +} + +func (_c *MockPrompt_InputPrompt_Call) Run(run func(prompt string)) *MockPrompt_InputPrompt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockPrompt_InputPrompt_Call) Return(s string) *MockPrompt_InputPrompt_Call { + _c.Call.Return(s) + return _c +} + +func (_c *MockPrompt_InputPrompt_Call) RunAndReturn(run func(prompt string) string) *MockPrompt_InputPrompt_Call { + _c.Call.Return(run) + return _c +} + // NewMockBrowser creates a new instance of MockBrowser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockBrowser(t interface { diff --git a/cli/cmd/open-workspace.go b/cli/cmd/open-workspace.go index 1dcfb06..a617bd9 100644 --- a/cli/cmd/open-workspace.go +++ b/cli/cmd/open-workspace.go @@ -7,11 +7,10 @@ import ( "fmt" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) -// OpenWorkspaceCmd represents the workspace command type OpenWorkspaceCmd struct { cmd *cobra.Command Opts GlobalOptions @@ -41,7 +40,7 @@ func AddOpenWorkspaceCmd(open *cobra.Command, opts GlobalOptions) { Use: "workspace", Short: "Open workspace in the Codesphere IDE", Long: `Open workspace in the Codesphere IDE in your web browser.`, - Example: out.FormatExampleCommands("open workspace", []out.Example{ + Example: io.FormatExampleCommands("open workspace", []io.Example{ {Cmd: "-w 42", Desc: "open workspace 42 in web browser"}, {Cmd: "", Desc: "open workspace set by environment variable CS_WORKSPACE_ID"}, }), diff --git a/cli/cmd/open.go b/cli/cmd/open.go index aca84b7..7d04446 100644 --- a/cli/cmd/open.go +++ b/cli/cmd/open.go @@ -11,14 +11,11 @@ import ( "github.com/codesphere-cloud/cs-go/pkg/cs" ) -// OpenCmd represents the open command type OpenCmd struct { cmd *cobra.Command } func (c *OpenCmd) RunE(_ *cobra.Command, args []string) error { - //Command execution goes here - fmt.Println("Opening Codesphere IDE") return cs.NewBrowser().OpenIde("") } diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 64b080a..ac77c5d 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -81,6 +81,7 @@ func GetRootCmd() *cobra.Command { AddLicensesCmd(rootCmd) AddOpenCmd(rootCmd, opts) AddCreateCmd(rootCmd, opts) + AddDeleteCmd(rootCmd, opts) return rootCmd } diff --git a/cli/cmd/set-env-vars.go b/cli/cmd/set-env-vars.go index f86aeef..4c63f9b 100644 --- a/cli/cmd/set-env-vars.go +++ b/cli/cmd/set-env-vars.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/codesphere-cloud/cs-go/pkg/cs" - "github.com/codesphere-cloud/cs-go/pkg/out" + "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/spf13/cobra" ) @@ -27,7 +27,7 @@ func AddSetEnvVarCmd(p *cobra.Command, opts GlobalOptions) { Use: "set-env", Short: "Set environment varariables", Long: `Set environment variables in a workspace`, - Example: out.FormatExampleCommands("set-env", []out.Example{ + Example: io.FormatExampleCommands("set-env", []io.Example{ {Cmd: "--workspace --env-var foo=bar", Desc: "Set single environment variable"}, {Cmd: "--workspace --env-var foo=bar --env-var hello=world", Desc: "Set multiple environment variables"}, }), diff --git a/cli/cmd/version.go b/cli/cmd/version.go index 60dd1ed..cab3295 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version.go @@ -10,7 +10,6 @@ import ( "github.com/spf13/cobra" ) -// VersionCmd represents the version command type VersionCmd struct { cmd *cobra.Command } diff --git a/pkg/out/out.go b/pkg/io/io.go similarity index 70% rename from pkg/out/out.go rename to pkg/io/io.go index e5f8bec..db8ca1d 100644 --- a/pkg/out/out.go +++ b/pkg/io/io.go @@ -1,12 +1,14 @@ // Copyright (c) Codesphere Inc. // SPDX-License-Identifier: Apache-2.0 -package out +package io import ( + "bufio" "fmt" "os" "regexp" + "strings" "github.com/jedib0t/go-pretty/v6/table" ) @@ -44,3 +46,18 @@ func Long(in string) string { re := regexp.MustCompile("\n\t+") return re.ReplaceAllString(in, "\n") } + +type Prompt struct{} + +// Prompt for non-empty user input from STDIN +func (p *Prompt) InputPrompt(prompt string) string { + r := bufio.NewReader(os.Stdin) + for { + fmt.Printf("%s: ", prompt) + input, err := r.ReadString('\n') + input = strings.TrimSpace(input) + if input != "" || err != nil { + return input + } + } +}