Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): delete group locks #1904

Merged
merged 18 commits into from
Aug 23, 2024
Merged
2 changes: 2 additions & 0 deletions cli/pkg/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func RunCLI() ReturnCode {
return handleDeleteAppLock(*kpClientParams, subflags)
case "delete-team-lock":
return handleDeleteTeamLock(*kpClientParams, subflags)
case "delete-group-lock":
return handleDeleteGroupLock(*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 @@ -123,6 +123,16 @@ func handleCreateGroupLock(kpClientParams kuberpultClientParameters, args []stri
return handleLockRequest(kpClientParams, parsedArgs)
}

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

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

func handleLockRequest(kpClientParams kuberpultClientParameters, parsedArgs locks.LockParameters) ReturnCode {
authParams := kutil.AuthenticationParameters{
IapToken: kpClientParams.iapToken,
Expand Down
70 changes: 69 additions & 1 deletion cli/pkg/locks/group_lock_parsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func convertToCreateGroupLockParams(cmdArgs CreateEnvGroupLockCommandLineArgumen
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := EnvironmentGroupLockParameters{
rp := CreateEnvironmentGroupLockParameters{
LockId: cmdArgs.lockId.Values[0],
EnvironmentGroup: cmdArgs.environmentGroup.Values[0],
UseDexAuthentication: false, //For now there is no ambiguity as to which endpoint to use
Expand All @@ -99,3 +99,71 @@ func ParseArgsCreateGroupLock(args []string) (LockParameters, error) {

return rp, nil
}

type DeleteEnvGroupLockCommandLineArguments struct {
environmentGroup cli_utils.RepeatedString
lockId cli_utils.RepeatedString
}

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

return true, ""
}

// takes the raw command line flags and converts them to an intermediate represnetations for easy validation
func readDeleteGroupLockArgs(args []string) (*DeleteEnvGroupLockCommandLineArguments, error) {
cmdArgs := DeleteEnvGroupLockCommandLineArguments{} //exhaustruct:ignore

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

fs.Var(&cmdArgs.environmentGroup, "environment-group", "the environment-group of the lock you are trying to delete")
fs.Var(&cmdArgs.lockId, "lockID", "the ID 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 := argsValidDeleteEnvGroupLock(&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 create lock endpoint
func convertToDeleteGroupLockParams(cmdArgs DeleteEnvGroupLockCommandLineArguments) (LockParameters, error) {
if ok, msg := argsValidDeleteEnvGroupLock(&cmdArgs); !ok {
// this should never happen, as the validation is already performed by the readArgs function
return nil, fmt.Errorf("the provided command line arguments structure is invalid, cause: %s", msg)
}

rp := DeleteEnvironmentGroupLockParameters{
LockId: cmdArgs.lockId.Values[0],
EnvironmentGroup: cmdArgs.environmentGroup.Values[0],
UseDexAuthentication: false, //For now there is no ambiguity as to which endpoint to use
}
return &rp, nil
}

func ParseArgsDeleteGroupLock(args []string) (LockParameters, error) {
cmdArgs, err := readDeleteGroupLockArgs(args)
if err != nil {
return nil, fmt.Errorf("error while reading command line arguments for deleting an environment group lock, error: %w", err)
}
rp, err := convertToDeleteGroupLockParams(*cmdArgs)
if err != nil {
return nil, fmt.Errorf("error while creating parameters for deleting an environment group lock, error: %w", err)
}

return rp, nil
}
124 changes: 121 additions & 3 deletions cli/pkg/locks/group_lock_parsing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,86 @@ func TestReadGroupLockArgs(t *testing.T) {
}
}

func TestReadDeleteGroupLockArgs(t *testing.T) {
type testCase struct {
name string
args []string
expectedCmdArgs *DeleteEnvGroupLockCommandLineArguments
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-group", "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: "only --environment-group is properly provided but without --lockID",
args: []string{"--environment-group", "potato"},
expectedError: errMatcher{
msg: "the --lockID arg must be set exactly once",
},
},
{
name: "only --lockID is properly provided but without --environment-group",
args: []string{"--lockID", "potato"},
expectedError: errMatcher{
msg: "the --environment-group arg must be set exactly once",
},
},
{
name: "--environment-group and lockID",
args: []string{"--environment-group", "development", "--lockID", "my-lock"},
expectedCmdArgs: &DeleteEnvGroupLockCommandLineArguments{
environmentGroup: cli_utils.RepeatedString{
Values: []string{
"development",
},
},
lockId: cli_utils.RepeatedString{
Values: []string{
"my-lock",
},
},
},
},
}

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

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

func TestParseEnvGroupArgs(t *testing.T) {
type testCase struct {
name string
Expand All @@ -139,7 +219,7 @@ func TestParseEnvGroupArgs(t *testing.T) {
{
name: "with environment and lockID and message",
cmdArgs: []string{"--environment-group", "development", "--lockID", "my-lock", "--message", "message"},
expectedParams: &EnvironmentGroupLockParameters{
expectedParams: &CreateEnvironmentGroupLockParameters{
EnvironmentGroup: "development",
LockId: "my-lock",
Message: "message",
Expand All @@ -148,7 +228,7 @@ func TestParseEnvGroupArgs(t *testing.T) {
{
name: "with environment and lockID and no message",
cmdArgs: []string{"--environment-group", "development", "--lockID", "my-lock"},
expectedParams: &EnvironmentGroupLockParameters{
expectedParams: &CreateEnvironmentGroupLockParameters{
EnvironmentGroup: "development",
LockId: "my-lock",
Message: "",
Expand All @@ -158,7 +238,7 @@ func TestParseEnvGroupArgs(t *testing.T) {
{
name: "with environment and lockID and multi word message message",
cmdArgs: []string{"--environment-group", "development", "--lockID", "my-lock", "--message", "this is a very long message"},
expectedParams: &EnvironmentGroupLockParameters{
expectedParams: &CreateEnvironmentGroupLockParameters{
EnvironmentGroup: "development",
LockId: "my-lock",
Message: "this is a very long message",
Expand All @@ -184,3 +264,41 @@ func TestParseEnvGroupArgs(t *testing.T) {
})
}
}

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

tcs := []testCase{
{
name: "with environment groups and lockID",
cmdArgs: []string{"--environment-group", "development", "--lockID", "my-lock"},
expectedParams: &DeleteEnvironmentGroupLockParameters{
EnvironmentGroup: "development",
LockId: "my-lock",
},
},
}

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

params, err := ParseArgsDeleteGroupLock(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)
}
})
}
}
26 changes: 22 additions & 4 deletions cli/pkg/locks/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,17 @@ type DeleteTeamLockParameters struct {
UseDexAuthentication bool
}

type EnvironmentGroupLockParameters struct {
type CreateEnvironmentGroupLockParameters struct {
EnvironmentGroup string
LockId string
Message string
UseDexAuthentication bool
}
type DeleteEnvironmentGroupLockParameters struct {
EnvironmentGroup string
LockId string
UseDexAuthentication bool
}

type LockJsonData struct {
Message string `json:"message"`
Expand Down Expand Up @@ -111,11 +116,11 @@ 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"
Expand Down Expand Up @@ -207,13 +212,13 @@ func (e *DeleteTeamLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *EnvironmentGroupLockParameters) FillHttpInfo() (*HttpInfo, error) {
func (e *CreateEnvironmentGroupLockParameters) FillHttpInfo() (*HttpInfo, error) {
d := LockJsonData{
Message: e.Message,
}
var jsonData, err = json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("Could not marshal EnvironmentGroupLockParameters data to json: %w\n", err)
return nil, fmt.Errorf("Could not marshal CreateEnvironmentGroupLockParameters data to json: %w\n", err)
}
prefix := "environment-groups"
if e.UseDexAuthentication {
Expand All @@ -227,6 +232,19 @@ func (e *EnvironmentGroupLockParameters) FillHttpInfo() (*HttpInfo, error) {
}, nil
}

func (e *DeleteEnvironmentGroupLockParameters) FillHttpInfo() (*HttpInfo, error) {
prefix := "environment-groups"
if e.UseDexAuthentication {
prefix = "api/environment-groups"
}
return &HttpInfo{
jsonData: []byte{},
ContentType: "application/json",
HttpMethod: http.MethodDelete,
RestPath: fmt.Sprintf("%s/%s/locks/%s", prefix, e.EnvironmentGroup, e.LockId),
}, nil
}

func createHttpRequest(url string, authParams kutil.AuthenticationParameters, requestInfo *HttpInfo) (*http.Request, error) {
urlStruct, err := urllib.Parse(url)
if err != nil {
Expand Down
Loading