From 3d7e38ae61bc78446e25e8949ab4c88a7d9d3e23 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 25 Nov 2022 14:03:18 +1100 Subject: [PATCH] refactor: support null for build-image in deploytargets (#251) --- cmd/deploytarget.go | 11 ++- cmd/helpers.go | 21 ++++++ cmd/helpers_test.go | 74 ++++++++++++++++++++- docs/commands/lagoon_update_deploytarget.md | 2 +- go.mod | 1 + go.sum | 2 + internal/schema/deploytarget.go | 6 ++ 7 files changed, 112 insertions(+), 5 deletions(-) diff --git a/cmd/deploytarget.go b/cmd/deploytarget.go index b7d26f4e..59fe8785 100644 --- a/cmd/deploytarget.go +++ b/cmd/deploytarget.go @@ -192,7 +192,12 @@ var updateDeployTargetCmd = &cobra.Command{ if err != nil { return err } - buildImage, err := cmd.Flags().GetString("build-image") + // since there needs to be a way to unset the build image (using `null`) + // use this helper function to get the `null` representation + // the buildimage field in the schema is *null.String so that it is omit if it is empty + // but if it is set to "" to clear the value, will pass the json `null` representation + // or if set to a string, will pass this into the payload + buildImage, err := flagStringNullValueOrNil(cmd.Flags(), "build-image") if err != nil { return err } @@ -220,8 +225,8 @@ var updateDeployTargetCmd = &cobra.Command{ ConsoleURL: consoleURL, SSHHost: sshHost, SSHPort: sshPort, - BuildImage: buildImage, }, + BuildImage: buildImage, } if yesNo(fmt.Sprintf("You are attempting to update '%d' DeployTarget, are you sure?", updateDeployTarget.ID)) { updateDeployTargetResponse, err := lagoon.UpdateDeployTarget(context.TODO(), updateDeployTarget, lc) @@ -339,5 +344,5 @@ func init() { updateDeployTargetCmd.Flags().StringP("cloud-region", "", "", "DeployTarget cloud region") updateDeployTargetCmd.Flags().StringP("ssh-host", "", "", "DeployTarget ssh host") updateDeployTargetCmd.Flags().StringP("ssh-port", "", "", "DeployTarget ssh port") - updateDeployTargetCmd.Flags().StringP("build-image", "", "", "DeployTarget build image to use (if different to the default)") + updateDeployTargetCmd.Flags().StringP("build-image", "", "", "DeployTarget build image to use (if different to the default, use \"\" to clear)") } diff --git a/cmd/helpers.go b/cmd/helpers.go index bee67f79..7176566a 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -5,6 +5,9 @@ import ( "fmt" "regexp" "strings" + + "github.com/guregu/null" + "github.com/spf13/pflag" ) // makeSafe ensures that any string is dns safe @@ -32,3 +35,21 @@ func hashString(s string) string { bs := h.Sum(nil) return fmt.Sprintf("%x", bs) } + +func flagStringNullValueOrNil(flags *pflag.FlagSet, flag string) (*null.String, error) { + flagValue, err := flags.GetString(flag) + if err != nil { + return nil, err + } + changed := flags.Changed(flag) + if changed && flagValue == "" { + // if the flag is defined, and is empty value, return a `null` string + return &null.String{}, nil + } else if changed { + // otherwise set the flag to be the value from the flag + value := null.StringFrom(flagValue) + return &value, nil + } + // if not defined, return nil + return nil, nil +} diff --git a/cmd/helpers_test.go b/cmd/helpers_test.go index f0164e7f..59524a25 100644 --- a/cmd/helpers_test.go +++ b/cmd/helpers_test.go @@ -1,6 +1,12 @@ package cmd -import "testing" +import ( + "reflect" + "testing" + + "github.com/guregu/null" + "github.com/spf13/pflag" +) func Test_makeSafe(t *testing.T) { tests := []struct { @@ -92,3 +98,69 @@ func Test_shortenEnvironment(t *testing.T) { }) } } + +func Test_flagStringNullValueOrNil(t *testing.T) { + type args struct { + flags map[string]interface{} + flag string + } + tests := []struct { + name string + args args + want *null.String + wantErr bool + }{ + { + name: "test1", + args: args{ + flags: map[string]interface{}{ + "build-image": nil, + }, + flag: "build-image", + }, + want: nil, + }, + { + name: "test1", + args: args{ + flags: map[string]interface{}{ + "build-image": "", + }, + flag: "build-image", + }, + want: &null.String{}, + }, + { + name: "test1", + args: args{ + flags: map[string]interface{}{ + "build-image": "buildimage", + }, + flag: "build-image", + }, + want: func() *null.String { + l := null.StringFrom("buildimage") + return &l + }(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + flags := &pflag.FlagSet{} + for k, v := range tt.args.flags { + flags.StringP(k, "", "", "") + if v != nil { + flags.Set(k, v.(string)) + } + } + got, err := flagStringNullValueOrNil(flags, tt.args.flag) + if (err != nil) != tt.wantErr { + t.Errorf("flagStringNullValueOrNil() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("flagStringNullValueOrNil() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/docs/commands/lagoon_update_deploytarget.md b/docs/commands/lagoon_update_deploytarget.md index 7a532443..20310564 100644 --- a/docs/commands/lagoon_update_deploytarget.md +++ b/docs/commands/lagoon_update_deploytarget.md @@ -13,7 +13,7 @@ lagoon update deploytarget [flags] ### Options ``` - --build-image string DeployTarget build image to use (if different to the default) + --build-image string DeployTarget build image to use (if different to the default, use "" to clear) --cloud-provider string DeployTarget cloud provider --cloud-region string DeployTarget cloud region --console-url string DeployTarget console URL diff --git a/go.mod b/go.mod index 46408c09..ac8d34ce 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( require ( github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/google/go-querystring v1.0.0 // indirect + github.com/guregu/null v4.0.0+incompatible github.com/matryer/is v1.2.0 // indirect // workaround for https://github.com/manifoldco/promptui/issues/98 github.com/nicksnyder/go-i18n v1.10.1 // indirect diff --git a/go.sum b/go.sum index f1d49e87..8dde0886 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/guregu/null v4.0.0+incompatible h1:4zw0ckM7ECd6FNNddc3Fu4aty9nTlpkkzH7dPn4/4Gw= +github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= diff --git a/internal/schema/deploytarget.go b/internal/schema/deploytarget.go index dc1e6476..077a02cf 100644 --- a/internal/schema/deploytarget.go +++ b/internal/schema/deploytarget.go @@ -1,5 +1,9 @@ package schema +import ( + "github.com/guregu/null" +) + type DeployTarget struct { AddDeployTargetInput } @@ -24,6 +28,8 @@ type AddDeployTargetInput struct { // UpdateDeployTargetInput is based on the input to addDeployTarget. type UpdateDeployTargetInput struct { AddDeployTargetInput + // `null` is valid graphql, use a pointer to allow `nil` to be empty + BuildImage *null.String `json:"buildImage,omitempty"` } type UpdateDeployTargetResponse struct {