Skip to content

Commit

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

Ref: SRX-BUU4S5
  • Loading branch information
miguel-crespo-fdc authored Aug 22, 2024
1 parent 415cd9a commit f7cd617
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 8 deletions.
2 changes: 2 additions & 0 deletions cli/pkg/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ func RunCLI() ReturnCode {
return handleCreateGroupLock(*kpClientParams, subflags)
case "delete-env-lock":
return handleDeleteEnvLock(*kpClientParams, subflags)
case "delete-app-lock":
return handleDeleteAppLock(*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 @@ -73,6 +73,16 @@ func handleCreateEnvLock(kpClientParams kuberpultClientParameters, args []string
return handleLockRequest(kpClientParams, parsedArgs)
}

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

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

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

Expand Down
72 changes: 71 additions & 1 deletion cli/pkg/locks/app_lock_parsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func convertToCreateAppLockParams(cmdArgs CreateAppLockCommandLineArguments) (Lo
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := AppLockParameters{
rp := CreateAppLockParameters{
LockId: cmdArgs.lockId.Values[0],
Environment: cmdArgs.environment.Values[0],
Application: cmdArgs.application.Values[0],
Expand All @@ -102,3 +102,73 @@ func ParseArgsCreateAppLock(args []string) (LockParameters, error) {
}
return rp, nil
}

type DeleteAppLockCommandLineArguments struct {
environment cli_utils.RepeatedString
lockId cli_utils.RepeatedString
application cli_utils.RepeatedString
}

func argsValidDeleteAppLock(cmdArgs *DeleteAppLockCommandLineArguments) (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.application.Values) != 1 {
return false, "the --application arg must be set exactly once"
}

return true, ""
}

func readDeleteAppLockArgs(args []string) (*DeleteAppLockCommandLineArguments, error) {
cmdArgs := DeleteAppLockCommandLineArguments{} //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.application, "application", "the application 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 := argsValidDeleteAppLock(&cmdArgs); !ok {
return nil, fmt.Errorf(msg)
}

return &cmdArgs, nil
}

func convertToDeleteAppLockParams(cmdArgs DeleteAppLockCommandLineArguments) (LockParameters, error) {
if ok, msg := argsValidDeleteAppLock(&cmdArgs); !ok {
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := DeleteAppLockParameters{
LockId: cmdArgs.lockId.Values[0],
Environment: cmdArgs.environment.Values[0],
Application: cmdArgs.application.Values[0],
UseDexAuthentication: false,
}
return &rp, nil
}

func ParseArgsDeleteAppLock(args []string) (LockParameters, error) {
cmdArgs, err := readDeleteAppLockArgs(args)
if err != nil {
return nil, fmt.Errorf("error while reading command line arguments for deleting an app lock, error: %w", err)
}
rp, err := convertToDeleteAppLockParams(*cmdArgs)
if err != nil {
return nil, fmt.Errorf("error while creating parameters for deleting an application lock, error: %w", err)
}
return rp, nil
}
151 changes: 148 additions & 3 deletions cli/pkg/locks/app_lock_parsing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,112 @@ func TestReadArgsAppLock(t *testing.T) {
}
}

func TestReadArgsDeleteAppLock(t *testing.T) {
type testCase struct {
name string
args []string
expectedCmdArgs *DeleteAppLockCommandLineArguments
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", "--application", "my-app"},
expectedError: errMatcher{
msg: "the --lockID arg must be set exactly once",
},
},
{
name: "environment is not provided",
args: []string{"--application", "my-app", "--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 --application 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: "message is not accepted by delete",
args: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock", "--message", "\"my message\""},
expectedError: errMatcher{
msg: "error while parsing command line arguments, error: flag provided but not defined: -message",
},
},
{
name: "environment, lockID and application are specified",
args: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock"},
expectedCmdArgs: &DeleteAppLockCommandLineArguments{
environment: cli_utils.RepeatedString{
Values: []string{
"development",
},
},
lockId: cli_utils.RepeatedString{
Values: []string{
"my-lock",
},
},
application: cli_utils.RepeatedString{
Values: []string{
"my-app",
},
},
},
},
}

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

cmdArgs, err := readDeleteAppLockArgs(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(DeleteAppLockCommandLineArguments{})); diff != "" {
t.Fatalf("expected args:\n %v\n, got:\n %v, diff:\n %s\n", tc.expectedCmdArgs, cmdArgs, diff)
}
})
}
}

func TestParseArgsCreateAppLock(t *testing.T) {
type testCase struct {
name string
Expand All @@ -141,7 +247,7 @@ func TestParseArgsCreateAppLock(t *testing.T) {
{
name: "with environment and lockID and message",
cmdArgs: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock", "--message", "message"},
expectedParams: &AppLockParameters{
expectedParams: &CreateAppLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "message",
Expand All @@ -151,7 +257,7 @@ func TestParseArgsCreateAppLock(t *testing.T) {
{
name: "with environment, app and lockID and no message",
cmdArgs: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock"},
expectedParams: &AppLockParameters{
expectedParams: &CreateAppLockParameters{
Environment: "development",
LockId: "my-lock",
Message: "",
Expand All @@ -162,7 +268,7 @@ func TestParseArgsCreateAppLock(t *testing.T) {
{
name: "with environment and lockID and multi word message message",
cmdArgs: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock", "--message", "this is a very long message"},
expectedParams: &AppLockParameters{
expectedParams: &CreateAppLockParameters{
Environment: "development",
LockId: "my-lock",
Application: "my-app",
Expand All @@ -189,3 +295,42 @@ func TestParseArgsCreateAppLock(t *testing.T) {
})
}
}

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

tcs := []testCase{
{
name: "with environment, lockID and app",
cmdArgs: []string{"--environment", "development", "--application", "my-app", "--lockID", "my-lock"},
expectedParams: &DeleteAppLockParameters{
Environment: "development",
LockId: "my-lock",
Application: "my-app",
},
},
}

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

params, err := ParseArgsDeleteAppLock(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)
}
})
}
}
33 changes: 29 additions & 4 deletions cli/pkg/locks/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ type DeleteEnvironmentLockParameters struct {
UseDexAuthentication bool
}

type AppLockParameters struct {
type CreateAppLockParameters struct {
Environment string
LockId string
Message string
Application string
UseDexAuthentication bool
}
type DeleteAppLockParameters struct {
Environment string
LockId string
Application string
UseDexAuthentication bool
}

type TeamLockParameters struct {
Environment string
Expand Down Expand Up @@ -98,13 +104,15 @@ func (e *CreateEnvironmentLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
}

var jsonData, err = json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("Could not EnvironmentLockParameters data to json: %w\n", err)
}

prefix := "environments"
if e.UseDexAuthentication {
prefix = "api/environments"
}
return &HttpInfo{
jsonData: jsonData,
ContentType: "application/json",
Expand All @@ -126,15 +134,18 @@ func (e *DeleteEnvironmentLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *AppLockParameters) FillHttpInfo() (*HttpInfo, error) {
func (e *CreateAppLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
}
var jsonData, err = json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("Could not marshal AppLockParameters data to json: %w\n", err)
return nil, fmt.Errorf("Could not marshal CreateAppLockParameters data to json: %w\n", err)
}
prefix := "environments"
if e.UseDexAuthentication {
prefix = "api/environments"
}
return &HttpInfo{
jsonData: jsonData,
ContentType: "application/json",
Expand All @@ -143,6 +154,19 @@ func (e *AppLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *DeleteAppLockParameters) 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/applications/%s/locks/%s", prefix, e.Environment, e.Application, e.LockId),
}, nil
}

func (e *TeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
Expand All @@ -151,6 +175,7 @@ func (e *TeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
if err != nil {
return nil, fmt.Errorf("Could not marshal TeamLockParameters data to json: %w\n", err)
}

prefix := "api/environments"
return &HttpInfo{
jsonData: jsonData,
Expand Down

0 comments on commit f7cd617

Please sign in to comment.