Skip to content

Commit

Permalink
chore: fix space create flags (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
benPearce1 authored Oct 31, 2022
1 parent 1953205 commit fd498eb
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 42 deletions.
12 changes: 12 additions & 0 deletions pkg/cmd/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ func NewDependencies(f factory.Factory, cmd *cobra.Command) *Dependencies {
panic(err)
}

return newDependencies(f, cmd, client)
}

func NewSystemDependencies(f factory.Factory, cmd *cobra.Command) *Dependencies {
client, err := f.GetSystemClient()
if err != nil {
panic(err)
}
return newDependencies(f, cmd, client)
}

func newDependencies(f factory.Factory, cmd *cobra.Command, client *client.Client) *Dependencies {
return &Dependencies{
Ask: f.Ask,
CmdPath: cmd.CommandPath(),
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/projectgroup/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func PromptMissing(opts *CreateOptions) error {
if opts.Description.Value == "" {
if err := opts.Ask(&survey.Input{
Message: messagePrefix + "Description",
Help: "A short, memorable, unique name for this project.",
Help: "A short, memorable, description for this project group.",
}, &opts.Description.Value); err != nil {
return err
}
Expand Down
211 changes: 170 additions & 41 deletions pkg/cmd/space/create/create.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package create

import (
"errors"
"fmt"
"github.com/OctopusDeploy/cli/pkg/cmd"
"github.com/OctopusDeploy/cli/pkg/cmd/tenant/shared"
"github.com/OctopusDeploy/cli/pkg/util"
"io"
"github.com/OctopusDeploy/cli/pkg/util/flag"
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/MakeNowJust/heredoc/v2"
Expand All @@ -12,93 +16,162 @@ import (
"github.com/OctopusDeploy/cli/pkg/output"
"github.com/OctopusDeploy/cli/pkg/question"
"github.com/OctopusDeploy/cli/pkg/validation"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/spaces"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/teams"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/users"
"github.com/spf13/cobra"
)

const (
FlagName = "name"
FlagDescription = "description"
FlagTeam = "team"
FlagUser = "user"
)

type CreateFlags struct {
Name *flag.Flag[string]
Description *flag.Flag[string]
Teams *flag.Flag[[]string]
Users *flag.Flag[[]string]
}

type CreateOptions struct {
*cmd.Dependencies
*CreateFlags
GetAllSpacesCallback shared.GetAllSpacesCallback
GetAllTeamsCallback shared.GetAllTeamsCallback
GetAllUsersCallback shared.GetAllUsersCallback
}

func NewCreateOptions(f factory.Factory, flags *CreateFlags, dependencies *cmd.Dependencies) *CreateOptions {
client, err := f.GetSystemClient()
dependencies.Client = client // override the default space client
if err != nil {
panic(err)
}
return &CreateOptions{
CreateFlags: flags,
Dependencies: dependencies,
GetAllSpacesCallback: func() ([]*spaces.Space, error) { return shared.GetAllSpaces(*client) },
GetAllTeamsCallback: func() ([]*teams.Team, error) { return shared.GetAllTeams(*client) },
GetAllUsersCallback: func() ([]*users.User, error) { return shared.GetAllUsers(*client) },
}
}

func NewCreateFlags() *CreateFlags {
return &CreateFlags{
Name: flag.New[string](FlagName, false),
Description: flag.New[string](FlagDescription, false),
Teams: flag.New[[]string](FlagTeam, false),
Users: flag.New[[]string](FlagUser, false),
}
}

func NewCmdCreate(f factory.Factory) *cobra.Command {
createFlags := NewCreateFlags()
cmd := &cobra.Command{
Use: "create",
Short: "Creates a space in an instance of Octopus Deploy",
Long: "Creates a space in an instance of Octopus Deploy.",
Example: fmt.Sprintf(heredoc.Doc(`
$ %s space create"
`), constants.ExecutableName),
RunE: func(cmd *cobra.Command, args []string) error {
return createRun(f, cmd.OutOrStdout())
RunE: func(c *cobra.Command, args []string) error {
opts := NewCreateOptions(f, createFlags, cmd.NewSystemDependencies(f, c))

return createRun(opts)
},
}

flags := cmd.Flags()
flags.StringVarP(&createFlags.Name.Value, createFlags.Name.Name, "n", "", "Name of the space")
flags.StringVarP(&createFlags.Description.Value, createFlags.Description.Name, "d", "", "Description of the space")
flags.StringSliceVarP(&createFlags.Teams.Value, createFlags.Teams.Name, "t", nil, "The teams to manage the space (can be specified multiple times)")
flags.StringSliceVarP(&createFlags.Users.Value, createFlags.Users.Name, "u", nil, "The users to manage the space (can be specified multiple times)")

return cmd
}

func createRun(f factory.Factory, _ io.Writer) error {
systemClient, err := f.GetSystemClient()
if err != nil {
return err
func createRun(opts *CreateOptions) error {
if !opts.NoPrompt {
if err := PromptMissing(opts); err != nil {
return err
}
}
space := spaces.NewSpace(opts.Name.Value)

existingSpaces, err := systemClient.Spaces.GetAll()
allTeams, err := opts.Client.Teams.GetAll()
if err != nil {
return err
}

spaceNames := util.SliceTransform(existingSpaces, func(s *spaces.Space) string { return s.Name })

var name string
err = f.Ask(&survey.Input{
Help: "The name of the space being created.",
Message: "Name",
}, &name, survey.WithValidator(survey.ComposeValidators(
survey.MaxLength(20),
survey.MinLength(1),
survey.Required,
validation.NotEquals(spaceNames, "a space with this name already exists"),
)))
allUsers, err := opts.Client.Users.GetAll()
if err != nil {
return err
}
space := spaces.NewSpace(name)

selectedTeams, err := selectTeams(f.Ask, systemClient, existingSpaces, "Select one or more teams to manage this space:")
if err != nil {
return err
}
for _, team := range opts.Teams.Value {
team, err := findTeam(allTeams, team)
if err != nil {
return err
}

for _, team := range selectedTeams {
space.SpaceManagersTeams = append(space.SpaceManagersTeams, team.ID)
}

selectedUsers, err := selectUsers(f.Ask, systemClient, "Select one or more users to manage this space:")
if err != nil {
return err
}
for _, user := range opts.Users.Value {
user, err := findUser(allUsers, user)
if err != nil {
return err
}

for _, user := range selectedUsers {
space.SpaceManagersTeamMembers = append(space.SpaceManagersTeams, user.ID)
space.SpaceManagersTeamMembers = append(space.SpaceManagersTeamMembers, user.GetID())
}

createdSpace, err := systemClient.Spaces.Add(space)
space.Description = opts.Description.Value

createdSpace, err := opts.Client.Spaces.Add(space)
if err != nil {
return err
}

fmt.Printf("%s The space, \"%s\" %s was created successfully.\n", output.Green("✔"), createdSpace.Name, output.Dimf("(%s)", createdSpace.ID))

if !opts.NoPrompt {
autoCmd := flag.GenerateAutomationCmd(opts.CmdPath, opts.Name, opts.Description, opts.Teams, opts.Users)
fmt.Fprintf(opts.Out, "\nAutomation Command: %s\n", autoCmd)
}
return nil
}

func selectTeams(ask question.Asker, client *client.Client, existingSpaces []*spaces.Space, message string) ([]*teams.Team, error) {
systemTeams, err := client.Teams.Get(teams.TeamsQuery{
IncludeSystem: true,
})
func findTeam(allTeams []*teams.Team, identifier string) (*teams.Team, error) {
for _, team := range allTeams {
if strings.EqualFold(identifier, team.ID) || strings.EqualFold(identifier, team.Name) {
return team, nil
}
}

return nil, errors.New(fmt.Sprintf("Cannot find team '%s'", identifier))
}

func findUser(allUsers []*users.User, identifier string) (*users.User, error) {
for _, user := range allUsers {
if strings.EqualFold(identifier, user.ID) || strings.EqualFold(identifier, user.Username) || strings.EqualFold(identifier, user.DisplayName) {
return user, nil
}
}

return nil, errors.New(fmt.Sprintf("Cannot find user '%s'", identifier))
}

func selectTeams(ask question.Asker, getAllTeamsCallback shared.GetAllTeamsCallback, existingSpaces []*spaces.Space, message string) ([]*teams.Team, error) {
systemTeams, err := getAllTeamsCallback()
if err != nil {
return []*teams.Team{}, err
}

return question.MultiSelectMap(ask, message, systemTeams.Items, func(team *teams.Team) string {
return question.MultiSelectMap(ask, message, systemTeams, func(team *teams.Team) string {
if len(team.SpaceID) == 0 {
return fmt.Sprintf("%s %s", team.Name, output.Dim("(System Team)"))
}
Expand All @@ -111,8 +184,8 @@ func selectTeams(ask question.Asker, client *client.Client, existingSpaces []*sp
}, false)
}

func selectUsers(ask question.Asker, client *client.Client, message string) ([]*users.User, error) {
existingUsers, err := client.Users.GetAll()
func selectUsers(ask question.Asker, getAllUsersCallback shared.GetAllUsersCallback, message string) ([]*users.User, error) {
existingUsers, err := getAllUsersCallback()
if err != nil {
return nil, err
}
Expand All @@ -121,3 +194,59 @@ func selectUsers(ask question.Asker, client *client.Client, message string) ([]*
return fmt.Sprintf("%s %s", existingUser.DisplayName, output.Dimf("(%s)", existingUser.Username))
}, false)
}

func PromptMissing(opts *CreateOptions) error {
existingSpaces, err := opts.GetAllSpacesCallback()
if err != nil {
return err
}

spaceNames := util.SliceTransform(existingSpaces, func(s *spaces.Space) string { return s.Name })
if opts.Name.Value == "" {
err = opts.Ask(&survey.Input{
Help: "The name of the space being created.",
Message: "Name",
}, &opts.Name.Value, survey.WithValidator(survey.ComposeValidators(
survey.MaxLength(20),
survey.MinLength(1),
survey.Required,
validation.NotEquals(spaceNames, "a space with this name already exists"),
)))
if err != nil {
return err
}
}

if opts.Description.Value == "" {
if err := opts.Ask(&survey.Input{
Message: "Description",
Help: "A short, memorable, description for this space.",
}, &opts.Description.Value); err != nil {
return err
}
}

if len(opts.Teams.Value) == 0 {
selectedTeams, err := selectTeams(opts.Ask, opts.GetAllTeamsCallback, existingSpaces, "Select one or more teams to manage this space:")
if err != nil {
return err
}

for _, team := range selectedTeams {
opts.Teams.Value = append(opts.Teams.Value, team.Name)
}
}

if len(opts.Users.Value) == 0 {
selectedUsers, err := selectUsers(opts.Ask, opts.GetAllUsersCallback, "Select one or more users to manage this space:")
if err != nil {
return err
}

for _, user := range selectedUsers {
opts.Users.Value = append(opts.Users.Value, user.Username)
}
}

return nil
}
Loading

0 comments on commit fd498eb

Please sign in to comment.