Skip to content

Commit

Permalink
feat(cli): delete team locks (#1903)
Browse files Browse the repository at this point in the history
Delete team locks through the CLI

Ref: SRX-BUU4S5
  • Loading branch information
miguel-crespo-fdc authored Aug 23, 2024
1 parent f7cd617 commit c9cf7e5
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 23 deletions.
2 changes: 2 additions & 0 deletions cli/pkg/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func RunCLI() ReturnCode {
return handleDeleteEnvLock(*kpClientParams, subflags)
case "delete-app-lock":
return handleDeleteAppLock(*kpClientParams, subflags)
case "delete-team-lock":
return handleDeleteTeamLock(*kpClientParams, subflags)
default:
log.Printf("unknown subcommand %s\n", subcommand)
return ReturnCodeInvalidArguments
Expand Down
10 changes: 10 additions & 0 deletions cli/pkg/cmd/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ func handleCreateAppLock(kpClientParams kuberpultClientParameters, args []string
return handleLockRequest(kpClientParams, parsedArgs)
}

func handleDeleteTeamLock(kpClientParams kuberpultClientParameters, args []string) ReturnCode {
parsedArgs, err := locks.ParseArgsDeleteTeamLock(args)

if err != nil {
log.Printf("error while parsing command line args, error: %v", err)
return ReturnCodeInvalidArguments
}
return handleLockRequest(kpClientParams, parsedArgs)
}

func handleCreateTeamLock(kpClientParams kuberpultClientParameters, args []string) ReturnCode {
parsedArgs, err := locks.ParseArgsCreateTeamLock(args)

Expand Down
32 changes: 27 additions & 5 deletions cli/pkg/locks/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,21 @@ type DeleteAppLockParameters struct {
UseDexAuthentication bool
}

type TeamLockParameters struct {
type CreateTeamLockParameters struct {
Environment string
LockId string
Message string
Team string
UseDexAuthentication bool
}

type DeleteTeamLockParameters struct {
Environment string
LockId string
Team string
UseDexAuthentication bool
}

type EnvironmentGroupLockParameters struct {
EnvironmentGroup string
LockId string
Expand Down Expand Up @@ -167,16 +174,18 @@ func (e *DeleteAppLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *TeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
func (e *CreateTeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
}
var jsonData, err = json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("Could not marshal TeamLockParameters data to json: %w\n", err)
return nil, fmt.Errorf("Could not marshal CreateTeamLockParameters data to json: %w\n", err)
}
prefix := "environments"
if e.UseDexAuthentication {
prefix = "api/environments"
}

prefix := "api/environments"
return &HttpInfo{
jsonData: jsonData,
ContentType: "application/json",
Expand All @@ -185,6 +194,19 @@ func (e *TeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *DeleteTeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
prefix := "environments"
if e.UseDexAuthentication {
prefix = "api/environments"
}
return &HttpInfo{
jsonData: []byte{},
ContentType: "application/json",
HttpMethod: http.MethodDelete,
RestPath: fmt.Sprintf("%s/%s/lock/team/%s/%s", prefix, e.Environment, e.Team, e.LockId),
}, nil
}

func (e *EnvironmentGroupLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
Expand Down
78 changes: 75 additions & 3 deletions cli/pkg/locks/team_lock_parsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func readCreateTeamLockArgs(args []string) (*CreateTeamLockCommandLineArguments,
fs.Var(&cmdArgs.lockId, "lockID", "the ID of the lock you are trying to create")
fs.Var(&cmdArgs.environment, "environment", "the environment to lock")
fs.Var(&cmdArgs.message, "message", "lock message")
fs.Var(&cmdArgs.team, "team", "application to lock")
fs.Var(&cmdArgs.team, "team", "team to lock")

if err := fs.Parse(args); err != nil {
return nil, fmt.Errorf("error while parsing command line arguments, error: %w", err)
Expand All @@ -80,11 +80,11 @@ func convertToCreateTeamLockParams(cmdArgs CreateTeamLockCommandLineArguments) (
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := TeamLockParameters{
rp := CreateTeamLockParameters{
LockId: cmdArgs.lockId.Values[0],
Environment: cmdArgs.environment.Values[0],
Team: cmdArgs.team.Values[0],
UseDexAuthentication: false, //For now there is no ambiguity as to which endpoint to use
UseDexAuthentication: true, //For now there is no ambiguity as to which endpoint to use
Message: "",
}
if len(cmdArgs.message.Values) != 0 {
Expand All @@ -104,3 +104,75 @@ func ParseArgsCreateTeamLock(args []string) (LockParameters, error) {
}
return rp, nil
}

type DeleteTeamLockCommandLineArguments struct {
environment cli_utils.RepeatedString
lockId cli_utils.RepeatedString
team cli_utils.RepeatedString
}

func argsValidDeleteTeamLock(cmdArgs *DeleteTeamLockCommandLineArguments) (result bool, errorMessage string) {
if len(cmdArgs.lockId.Values) != 1 {
return false, "the --lockID arg must be set exactly once"
}
if len(cmdArgs.environment.Values) != 1 {
return false, "the --environment arg must be set exactly once"
}
if len(cmdArgs.team.Values) != 1 {
return false, "the --team arg must be set exactly once"
}

return true, ""
}

func readDeleteTeamLockArgs(args []string) (*DeleteTeamLockCommandLineArguments, error) {
cmdArgs := DeleteTeamLockCommandLineArguments{} //exhaustruct:ignore

fs := flag.NewFlagSet("flag set", flag.ContinueOnError)

fs.Var(&cmdArgs.lockId, "lockID", "the ID of the lock you are trying to delete")
fs.Var(&cmdArgs.environment, "environment", "the environment of the lock you are trying to delete")
fs.Var(&cmdArgs.team, "team", "the team of the lock you are trying to delete")

if err := fs.Parse(args); err != nil {
return nil, fmt.Errorf("error while parsing command line arguments, error: %w", err)
}

if len(fs.Args()) != 0 { // kuberpult-cli release does not accept any positional arguments, so this is an error
return nil, fmt.Errorf("these arguments are not recognized: \"%v\"", strings.Join(fs.Args(), " "))
}

if ok, msg := argsValidDeleteTeamLock(&cmdArgs); !ok {
return nil, fmt.Errorf(msg)
}

return &cmdArgs, nil
}

// converts the intermediate representation of the command line flags into the final structure containing parameters for the release endpoint
func convertToDeleteTeamLockParams(cmdArgs DeleteTeamLockCommandLineArguments) (LockParameters, error) {
if ok, msg := argsValidDeleteTeamLock(&cmdArgs); !ok {
// this should never happen, as the validation is already peformed by the readArgs function
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := DeleteTeamLockParameters{
LockId: cmdArgs.lockId.Values[0],
Environment: cmdArgs.environment.Values[0],
Team: cmdArgs.team.Values[0],
UseDexAuthentication: true,
}
return &rp, nil
}

func ParseArgsDeleteTeamLock(args []string) (LockParameters, error) {
cmdArgs, err := readDeleteTeamLockArgs(args)
if err != nil {
return nil, fmt.Errorf("error while reading command line arguments for team lock, error: %w", err)
}
rp, err := convertToDeleteTeamLockParams(*cmdArgs)
if err != nil {
return nil, fmt.Errorf("error while creating parameters for deleting team lock, error: %w", err)
}
return rp, nil
}
179 changes: 164 additions & 15 deletions cli/pkg/locks/team_lock_parsing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,112 @@ func TestReadArgsTeamLock(t *testing.T) {
}
}

func TestReadArgsDeleteTeamLock(t *testing.T) {
type testCase struct {
name string
args []string
expectedCmdArgs *DeleteTeamLockCommandLineArguments
expectedError error
}

tcs := []testCase{
{
name: "some unrecognized positional arguments",
args: []string{"potato", "tomato"},
expectedError: errMatcher{
msg: "these arguments are not recognized: \"potato tomato\"",
},
},
{
name: "some flags that don't exist",
args: []string{"--environment", "development", "--potato", "tomato"},
expectedError: errMatcher{
msg: "error while parsing command line arguments, error: flag provided but not defined: -potato",
},
},
{
name: "nothing provided",
args: []string{},
expectedError: errMatcher{
msg: "the --lockID arg must be set exactly once",
},
},
{
name: "lockID is not provided",
args: []string{"--environment", "development", "--team", "my-team"},
expectedError: errMatcher{
msg: "the --lockID arg must be set exactly once",
},
},
{
name: "environment is not provided",
args: []string{"--team", "my-team", "--lockID", "my-lock"},
expectedError: errMatcher{
msg: "the --environment arg must be set exactly once",
},
},
{
name: "application is not provided",
args: []string{"--environment", "development", "--lockID", "my-lock"},
expectedError: errMatcher{
msg: "the --team arg must be set exactly once",
},
},
{
name: "only --lockID is properly provided but without --environment",
args: []string{"--lockID", "potato"},
expectedError: errMatcher{
msg: "the --environment arg must be set exactly once",
},
},
{
name: "delete does not accept message",
args: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock", "--message", "message"},
expectedError: errMatcher{
msg: "error while parsing command line arguments, error: flag provided but not defined: -message",
},
},
{
name: "environment, lockID and application are are specified",
args: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock"},
expectedCmdArgs: &DeleteTeamLockCommandLineArguments{
environment: cli_utils.RepeatedString{
Values: []string{
"development",
},
},
lockId: cli_utils.RepeatedString{
Values: []string{
"my-lock",
},
},
team: cli_utils.RepeatedString{
Values: []string{
"my-team",
},
},
},
},
}

for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

cmdArgs, err := readDeleteTeamLockArgs(tc.args)
// check errors
if diff := cmp.Diff(tc.expectedError, err, cmpopts.EquateErrors()); diff != "" {
t.Fatalf("error mismatch (-want, +got):\n%s", diff)
}

if diff := cmp.Diff(cmdArgs, tc.expectedCmdArgs, cmp.AllowUnexported(DeleteTeamLockCommandLineArguments{})); diff != "" {
t.Fatalf("expected args:\n %v\n, got:\n %v, diff:\n %s\n", tc.expectedCmdArgs, cmdArgs, diff)
}
})
}
}

func TestParseArgsCreateTeamLock(t *testing.T) {
type testCase struct {
name string
Expand All @@ -141,31 +247,34 @@ func TestParseArgsCreateTeamLock(t *testing.T) {
{
name: "with environment and lockID and message",
cmdArgs: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock", "--message", "message"},
expectedParams: &TeamLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "message",
Team: "my-team",
expectedParams: &CreateTeamLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "message",
Team: "my-team",
UseDexAuthentication: true,
},
},
{
name: "with environment, app and lockID and no message",
cmdArgs: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock"},
expectedParams: &TeamLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "",
Team: "my-team",
expectedParams: &CreateTeamLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "",
Team: "my-team",
UseDexAuthentication: true,
},
},
{
name: "with environment and lockID and multi word message message",
cmdArgs: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock", "--message", "this is a very long message"},
expectedParams: &TeamLockParameters{
Environment: "development",
LockId: "my-lock",
Team: "my-team",
Message: "this is a very long message",
expectedParams: &CreateTeamLockParameters{
Environment: "development",
LockId: "my-lock",
Team: "my-team",
Message: "this is a very long message",
UseDexAuthentication: true,
},
},
}
Expand All @@ -188,3 +297,43 @@ func TestParseArgsCreateTeamLock(t *testing.T) {
})
}
}

func TestParseArgsDeleteTeamLock(t *testing.T) {
type testCase struct {
name string
cmdArgs []string
expectedParams LockParameters
expectedError error
}

tcs := []testCase{
{
name: "with environment and lockID and team",
cmdArgs: []string{"--environment", "development", "--team", "my-team", "--lockID", "my-lock"},
expectedParams: &DeleteTeamLockParameters{
Environment: "development",
LockId: "my-lock",
Team: "my-team",
UseDexAuthentication: true,
},
},
}

for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

params, err := ParseArgsDeleteTeamLock(tc.cmdArgs)
// check errors
if diff := cmp.Diff(tc.expectedError, err, cmpopts.EquateErrors()); diff != "" {
t.Fatalf("error mismatch (-want, +got):\n%s", diff)
}

// check result
if diff := cmp.Diff(tc.expectedParams, params); diff != "" {
t.Fatalf("expected args:\n %v\n, got:\n %v\n, diff:\n %s\n", tc.expectedParams, params, diff)
}
})
}
}

0 comments on commit c9cf7e5

Please sign in to comment.