Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion api/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions cli/cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 3 additions & 4 deletions cli/cmd/create-workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -78,15 +77,15 @@ 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.
The command will wait for the workspace to become running or a timeout is reached.

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"},
Expand Down
1 change: 0 additions & 1 deletion cli/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/spf13/cobra"
)

// CreateCmd represents the create command
type CreateCmd struct {
cmd *cobra.Command
}
Expand Down
74 changes: 74 additions & 0 deletions cli/cmd/delete-workspace.go
Original file line number Diff line number Diff line change
@@ -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)
}
23 changes: 23 additions & 0 deletions cli/cmd/delete.go
Original file line number Diff line number Diff line change
@@ -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)
}
114 changes: 114 additions & 0 deletions cli/cmd/delete_workspace_test.go
Original file line number Diff line number Diff line change
@@ -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"))
})
})
})

})
7 changes: 3 additions & 4 deletions cli/cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"},
Expand Down
1 change: 0 additions & 1 deletion cli/cmd/licenses.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/spf13/cobra"
)

// LicensesCmd represents the licenses command
type LicensesCmd struct {
cmd *cobra.Command
}
Expand Down
7 changes: 3 additions & 4 deletions cli/cmd/list-plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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},
Expand Down Expand Up @@ -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.`),
},
Expand Down
6 changes: 3 additions & 3 deletions cli/cmd/list-teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"},
}),
},
Expand All @@ -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 := ""
Expand Down
Loading