From 25493e5004c225fb97e4730498bc69480b090d41 Mon Sep 17 00:00:00 2001 From: Gilbert Scheiblhofer Date: Sun, 7 Jul 2024 14:29:58 +0200 Subject: [PATCH 1/4] added string transform join Signed-off-by: Gilbert Scheiblhofer --- input/v1beta1/resources_transforms.go | 10 +++++++ transforms.go | 27 +++++++++++++++++++ transforms_test.go | 38 +++++++++++++++++++++++++++ validate.go | 4 +++ 4 files changed, 79 insertions(+) diff --git a/input/v1beta1/resources_transforms.go b/input/v1beta1/resources_transforms.go index 632822b..152a53e 100644 --- a/input/v1beta1/resources_transforms.go +++ b/input/v1beta1/resources_transforms.go @@ -208,6 +208,7 @@ const ( StringTransformTypeTrimPrefix StringTransformType = "TrimPrefix" StringTransformTypeTrimSuffix StringTransformType = "TrimSuffix" StringTransformTypeRegexp StringTransformType = "Regexp" + StringTransformTypeJoin StringTransformType = "Join" ) // StringConversionType converts a string. @@ -257,6 +258,15 @@ type StringTransform struct { // Extract a match from the input using a regular expression. // +optional Regexp *StringTransformRegexp `json:"regexp,omitempty"` + + // Join the input strings. + Join *StringTransformJoin `json:"join,omitempty"` +} + +// A StringTransformJoin joins the input strings. +type StringTransformJoin struct { + // Separator to join the input strings. + Separator string `json:"separator"` } // A StringTransformRegexp extracts a match from the input using a regular diff --git a/transforms.go b/transforms.go index c1a20c5..6a7ac0c 100644 --- a/transforms.go +++ b/transforms.go @@ -50,6 +50,8 @@ const ( errStringTransformTypeConvert = "string transform of type %s convert is not set" errStringTransformTypeTrim = "string transform of type %s trim is not set" errStringTransformTypeRegexp = "string transform of type %s regexp is not set" + errStringTransformTypeJoin = "string transform of type %s join is not set" + errStringTransformTypeJoinFailed = "could not parse input array" errStringTransformTypeRegexpFailed = "could not compile regexp" errStringTransformTypeRegexpNoMatch = "regexp %q had no matches for group %d" errStringConvertTypeFailed = "type %s is not supported for string convert" @@ -287,6 +289,11 @@ func ResolveString(t *v1beta1.StringTransform, input any) (string, error) { return "", errors.Errorf(errStringTransformTypeRegexp, string(t.Type)) } return stringRegexpTransform(input, *t.Regexp) + case v1beta1.StringTransformTypeJoin: + if t.Join == nil { + return "", errors.Errorf(errStringTransformTypeJoin, string(t.Type)) + } + return stringJoinTransform(input, *t.Join) default: return "", errors.Errorf(errStringTransformTypeFailed, string(t.Type)) } @@ -351,6 +358,26 @@ func stringTrimTransform(input any, t v1beta1.StringTransformType, trim string) return str } +func stringJoinTransform(input any, r v1beta1.StringTransformJoin) (string, error) { + arr, ok := input.([]interface{}) + if !ok { + return "", errors.New(errStringTransformTypeJoinFailed) + } + if len(arr) == 0 { + return "", nil + } + + var result string + for _, v := range arr { + result += fmt.Sprintf("%v%s", v, r.Separator) + } + if len(r.Separator) > 0 { + return result[:len(result)-1], nil + } else { + return result, nil + } +} + func stringRegexpTransform(input any, r v1beta1.StringTransformRegexp) (string, error) { re, err := regexp.Compile(r.Match) if err != nil { diff --git a/transforms_test.go b/transforms_test.go index be328e1..ca436af 100644 --- a/transforms_test.go +++ b/transforms_test.go @@ -639,6 +639,7 @@ func TestStringResolve(t *testing.T) { convert *v1beta1.StringConversionType trim *string regexp *v1beta1.StringTransformRegexp + join *v1beta1.StringTransformJoin i any } type want struct { @@ -1003,6 +1004,42 @@ func TestStringResolve(t *testing.T) { err: errors.Wrap(errors.New("json: unsupported type: func()"), errMarshalJSON), }, }, + "JoinString": { + args: args{ + stype: v1beta1.StringTransformTypeJoin, + join: &v1beta1.StringTransformJoin{ + Separator: ",", + }, + i: []interface{}{"cross", "plane"}, + }, + want: want{ + o: "cross,plane", + }, + }, + "JoinStringEmptySeparator": { + args: args{ + stype: v1beta1.StringTransformTypeJoin, + join: &v1beta1.StringTransformJoin{ + Separator: "", + }, + i: []interface{}{"cross", "plane"}, + }, + want: want{ + o: "crossplane", + }, + }, + "JoinStringDifferentTypes": { + args: args{ + stype: v1beta1.StringTransformTypeJoin, + join: &v1beta1.StringTransformJoin{ + Separator: "-", + }, + i: []interface{}{"cross", "plane", 42}, + }, + want: want{ + o: "cross-plane-42", + }, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { @@ -1012,6 +1049,7 @@ func TestStringResolve(t *testing.T) { Convert: tc.convert, Trim: tc.trim, Regexp: tc.regexp, + Join: tc.join, } got, err := ResolveString(tr, tc.i) diff --git a/validate.go b/validate.go index 6165f3a..ce3c379 100644 --- a/validate.go +++ b/validate.go @@ -382,6 +382,10 @@ func ValidateStringTransform(s *v1beta1.StringTransform) *field.Error { //nolint if _, err := regexp.Compile(s.Regexp.Match); err != nil { return field.Invalid(field.NewPath("regexp", "match"), s.Regexp.Match, "invalid regexp") } + case v1beta1.StringTransformTypeJoin: + if s.Join == nil { + return field.Required(field.NewPath("join"), "join transform requires a join") + } default: return field.Invalid(field.NewPath("type"), s.Type, "unknown string transform type") } From 3c2bcc0f5ade2f33a700654bd4d12bf7a8fffed2 Mon Sep 17 00:00:00 2001 From: Gilbert Scheiblhofer Date: Sun, 7 Jul 2024 18:04:41 +0200 Subject: [PATCH 2/4] transform-join: fixed linting Signed-off-by: Gilbert Scheiblhofer --- transforms.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/transforms.go b/transforms.go index 6a7ac0c..93d7d33 100644 --- a/transforms.go +++ b/transforms.go @@ -267,7 +267,7 @@ func unmarshalJSON(j extv1.JSON, output *any) error { } // ResolveString resolves a String transform. -func ResolveString(t *v1beta1.StringTransform, input any) (string, error) { +func ResolveString(t *v1beta1.StringTransform, input any) (string, error) { //nolint:gocyclo // This is a long but simple/same-y switch. switch t.Type { case v1beta1.StringTransformTypeFormat: if t.Format == nil { @@ -373,9 +373,9 @@ func stringJoinTransform(input any, r v1beta1.StringTransformJoin) (string, erro } if len(r.Separator) > 0 { return result[:len(result)-1], nil - } else { - return result, nil - } + } + + return result, nil } func stringRegexpTransform(input any, r v1beta1.StringTransformRegexp) (string, error) { From dd8772faebb01bba33b5b0b79a92fe38803d5780 Mon Sep 17 00:00:00 2001 From: Gilbert Scheiblhofer Date: Mon, 8 Jul 2024 12:15:00 +0200 Subject: [PATCH 3/4] fixed linting(2) Signed-off-by: Gilbert Scheiblhofer --- transforms.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transforms.go b/transforms.go index 93d7d33..90c7ad2 100644 --- a/transforms.go +++ b/transforms.go @@ -373,8 +373,8 @@ func stringJoinTransform(input any, r v1beta1.StringTransformJoin) (string, erro } if len(r.Separator) > 0 { return result[:len(result)-1], nil - } - + } + return result, nil } From 9f1d81afd4e188834accc0ab917045a401179f0c Mon Sep 17 00:00:00 2001 From: Gilbert Scheiblhofer Date: Tue, 23 Jul 2024 21:27:23 +0200 Subject: [PATCH 4/4] transform join: added generated code Signed-off-by: Gilbert Scheiblhofer --- input/v1beta1/zz_generated.deepcopy.go | 20 ++++++++++++++ .../input/pt.fn.crossplane.io_resources.yaml | 27 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/input/v1beta1/zz_generated.deepcopy.go b/input/v1beta1/zz_generated.deepcopy.go index bd97bd7..0160fae 100644 --- a/input/v1beta1/zz_generated.deepcopy.go +++ b/input/v1beta1/zz_generated.deepcopy.go @@ -537,6 +537,11 @@ func (in *StringTransform) DeepCopyInto(out *StringTransform) { *out = new(StringTransformRegexp) (*in).DeepCopyInto(*out) } + if in.Join != nil { + in, out := &in.Join, &out.Join + *out = new(StringTransformJoin) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StringTransform. @@ -549,6 +554,21 @@ func (in *StringTransform) DeepCopy() *StringTransform { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StringTransformJoin) DeepCopyInto(out *StringTransformJoin) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StringTransformJoin. +func (in *StringTransformJoin) DeepCopy() *StringTransformJoin { + if in == nil { + return nil + } + out := new(StringTransformJoin) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StringTransformRegexp) DeepCopyInto(out *StringTransformRegexp) { *out = *in diff --git a/package/input/pt.fn.crossplane.io_resources.yaml b/package/input/pt.fn.crossplane.io_resources.yaml index a077022..078df85 100644 --- a/package/input/pt.fn.crossplane.io_resources.yaml +++ b/package/input/pt.fn.crossplane.io_resources.yaml @@ -318,6 +318,15 @@ spec: Format the input using a Go format string. See https://golang.org/pkg/fmt/ for details. type: string + join: + description: Join the input strings. + properties: + separator: + description: Separator to join the input strings. + type: string + required: + - separator + type: object regexp: description: Extract a match from the input using a regular expression. @@ -674,6 +683,15 @@ spec: Format the input using a Go format string. See https://golang.org/pkg/fmt/ for details. type: string + join: + description: Join the input strings. + properties: + separator: + description: Separator to join the input strings. + type: string + required: + - separator + type: object regexp: description: Extract a match from the input using a regular expression. @@ -1092,6 +1110,15 @@ spec: Format the input using a Go format string. See https://golang.org/pkg/fmt/ for details. type: string + join: + description: Join the input strings. + properties: + separator: + description: Separator to join the input strings. + type: string + required: + - separator + type: object regexp: description: Extract a match from the input using a regular expression.