From 93a0d37362071129af9f09e763c0933ef2972603 Mon Sep 17 00:00:00 2001 From: qingliu Date: Mon, 6 Feb 2023 14:46:53 +0800 Subject: [PATCH 1/5] chore: make goimports fmt --- .../v1alpha1/zz_generated.deepcopy.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 2 - apis/data/v1alpha1/zz_generated.deepcopy.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 2 - .../v1alpha1/zz_generated.deepcopy.go | 2 +- .../storage/v1alpha1/zz_generated.deepcopy.go | 2 - maps/merge_test.go | 73 +++++++++---------- 7 files changed, 37 insertions(+), 48 deletions(-) diff --git a/apis/applications/v1alpha1/zz_generated.deepcopy.go b/apis/applications/v1alpha1/zz_generated.deepcopy.go index 3256c7de..909c866e 100644 --- a/apis/applications/v1alpha1/zz_generated.deepcopy.go +++ b/apis/applications/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/apis/codequality/v1alpha1/zz_generated.deepcopy.go b/apis/codequality/v1alpha1/zz_generated.deepcopy.go index 68c618eb..317e32c7 100644 --- a/apis/codequality/v1alpha1/zz_generated.deepcopy.go +++ b/apis/codequality/v1alpha1/zz_generated.deepcopy.go @@ -21,8 +21,6 @@ limitations under the License. package v1alpha1 -import () - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AnalisysMetrics) DeepCopyInto(out *AnalisysMetrics) { *out = *in diff --git a/apis/data/v1alpha1/zz_generated.deepcopy.go b/apis/data/v1alpha1/zz_generated.deepcopy.go index 1178b952..cef5ec89 100644 --- a/apis/data/v1alpha1/zz_generated.deepcopy.go +++ b/apis/data/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" ) diff --git a/apis/security/v1alpha1/zz_generated.deepcopy.go b/apis/security/v1alpha1/zz_generated.deepcopy.go index 98c6556b..88a05224 100644 --- a/apis/security/v1alpha1/zz_generated.deepcopy.go +++ b/apis/security/v1alpha1/zz_generated.deepcopy.go @@ -21,8 +21,6 @@ limitations under the License. package v1alpha1 -import () - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CVSS) DeepCopyInto(out *CVSS) { *out = *in diff --git a/apis/selection/v1alpha1/zz_generated.deepcopy.go b/apis/selection/v1alpha1/zz_generated.deepcopy.go index 90aadcbd..d43f817d 100644 --- a/apis/selection/v1alpha1/zz_generated.deepcopy.go +++ b/apis/selection/v1alpha1/zz_generated.deepcopy.go @@ -23,7 +23,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/apis/storage/v1alpha1/zz_generated.deepcopy.go b/apis/storage/v1alpha1/zz_generated.deepcopy.go index 20171f88..029eb7f8 100644 --- a/apis/storage/v1alpha1/zz_generated.deepcopy.go +++ b/apis/storage/v1alpha1/zz_generated.deepcopy.go @@ -21,8 +21,6 @@ limitations under the License. package v1alpha1 -import () - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FileMeta) DeepCopyInto(out *FileMeta) { *out = *in diff --git a/maps/merge_test.go b/maps/merge_test.go index e64800e0..0d8e9b3a 100644 --- a/maps/merge_test.go +++ b/maps/merge_test.go @@ -17,7 +17,6 @@ limitations under the License. // Package maps contains methods to operate maps of all kinds package maps - import ( "testing" @@ -27,46 +26,46 @@ import ( func TestMergeMap(t *testing.T) { table := map[string]struct { - Left map[string]string + Left map[string]string Right map[string]string Result map[string]string }{ "multiple keys and values": { Left: map[string]string{ - "a": "b", + "a": "b", }, Right: map[string]string{ - "b": "c", + "b": "c", "a": "d", }, Result: map[string]string{ - "b": "c", - "a": "d", + "b": "c", + "a": "d", }, }, "nil left": { Left: nil, Right: map[string]string{ - "b": "c", - "a": "d", + "b": "c", + "a": "d", }, Result: map[string]string{ - "b": "c", - "a": "d", + "b": "c", + "a": "d", }, }, "nil right": { Left: map[string]string{ - "a": "b", + "a": "b", }, Right: nil, Result: map[string]string{ - "a": "b", + "a": "b", }, }, "both nil": { - Left: nil, - Right: nil, + Left: nil, + Right: nil, Result: map[string]string{}, }, } @@ -81,25 +80,23 @@ func TestMergeMap(t *testing.T) { } } - - func TestMergeMapSlice(t *testing.T) { table := map[string]struct { - Left map[string][]string + Left map[string][]string Right map[string][]string Result map[string][]string }{ "multiple keys and values": { Left: map[string][]string{ - "a": {"b", "c"}, + "a": {"b", "c"}, }, Right: map[string][]string{ - "b": {"c", "d"}, + "b": {"c", "d"}, "a": {"d", "e"}, }, Result: map[string][]string{ - "b": {"c", "d"}, + "b": {"c", "d"}, "a": {"d", "e"}, }, }, @@ -110,7 +107,7 @@ func TestMergeMapSlice(t *testing.T) { "a": {"d", "e"}, }, Result: map[string][]string{ - "b": {"c", "d"}, + "b": {"c", "d"}, "a": {"d", "e"}, }, }, @@ -126,8 +123,8 @@ func TestMergeMapSlice(t *testing.T) { }, }, "both nil": { - Left: nil, - Right: nil, + Left: nil, + Right: nil, Result: map[string][]string{}, }, } @@ -142,52 +139,50 @@ func TestMergeMapSlice(t *testing.T) { } } - - func TestMergeMapMap(t *testing.T) { table := map[string]struct { - Left map[string]map[string]string + Left map[string]map[string]string Right map[string]map[string]string Result map[string]map[string]string }{ "multiple keys and values": { Left: map[string]map[string]string{ - "a": {"b":"c"}, + "a": {"b": "c"}, }, Right: map[string]map[string]string{ - "b": {"c":"d"}, + "b": {"c": "d"}, // b key in a will be replaced - "a": {"d":"e", "b": "y"}, + "a": {"d": "e", "b": "y"}, }, Result: map[string]map[string]string{ - "b": {"c":"d"}, - "a": {"d":"e", "b": "y"}, + "b": {"c": "d"}, + "a": {"d": "e", "b": "y"}, }, }, "left nil": { Left: nil, Right: map[string]map[string]string{ - "b": {"c":"d"}, - "a": {"d":"e", "b": "y"}, + "b": {"c": "d"}, + "a": {"d": "e", "b": "y"}, }, Result: map[string]map[string]string{ - "b": {"c":"d"}, - "a": {"d":"e", "b": "y"}, + "b": {"c": "d"}, + "a": {"d": "e", "b": "y"}, }, }, "right nil": { Left: map[string]map[string]string{ - "a": {"b":"c"}, + "a": {"b": "c"}, }, Right: nil, Result: map[string]map[string]string{ - "a": {"b":"c"}, + "a": {"b": "c"}, }, }, "both nil": { - Left: nil, - Right: nil, + Left: nil, + Right: nil, Result: map[string]map[string]string{}, }, } From 952bbecf971a0539f8d68eb35d7274e14998cc8a Mon Sep 17 00:00:00 2001 From: qingliu Date: Mon, 6 Feb 2023 14:48:15 +0800 Subject: [PATCH 2/5] feat: add replaces used to replace string --- regex/regex_suite_test.go | 13 ++++++++++ regex/replace.go | 49 ++++++++++++++++++++++++++++++++++++ regex/replace_test.go | 53 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 regex/regex_suite_test.go create mode 100644 regex/replace.go create mode 100644 regex/replace_test.go diff --git a/regex/regex_suite_test.go b/regex/regex_suite_test.go new file mode 100644 index 00000000..2b252015 --- /dev/null +++ b/regex/regex_suite_test.go @@ -0,0 +1,13 @@ +package regex_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestRegex(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Regex Suite") +} diff --git a/regex/replace.go b/regex/replace.go new file mode 100644 index 00000000..bc71869c --- /dev/null +++ b/regex/replace.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 The Katanomi Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package regex + +import "regexp" + +// Replace provide helper functions for replacing strings +type Replace struct { + // Regex is a regular expression used to modify the original version to generate new variants + // +optional + Regex string `json:"regex,omitempty"` + + // Replacement is the value after replacement + // +optional + Replacement string `json:"replacement,omitempty"` +} + +// Replaces is a list of Replace +type Replaces []Replace + +// ReplaceAllString replace all string +func (r *Replace) ReplaceAllString(s string) string { + re := regexp.MustCompile(r.Regex) + return re.ReplaceAllString(s, r.Replacement) +} + +// ReplaceAllString replace all string +func (rs *Replaces) ReplaceAllString(s string) string { + if rs == nil { + return s + } + for _, r := range *rs { + s = r.ReplaceAllString(s) + } + return s +} diff --git a/regex/replace_test.go b/regex/replace_test.go new file mode 100644 index 00000000..4f98947b --- /dev/null +++ b/regex/replace_test.go @@ -0,0 +1,53 @@ +/* +Copyright 2023 The Katanomi Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. +*/ +package regex + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Test.Replaces.ReplaceAllString", func() { + + // nameAsTagReplaces used to generate the tag name from the branch name. + // 1. replacing `/` and `_` to `-` + // 2. remove the ending non [0-9a-zA-Z] characters + // 3. maximum length limit is 30 (extra characters in the prefix will be removed.) + nameAsTagReplaces := &Replaces{ + // replacing `/` and `_` to `-` + {Regex: `[/_]`, Replacement: "-"}, + // remove the ending non [0-9a-zA-Z] characters + {Regex: `[^0-9a-zA-Z]*$`, Replacement: ""}, + // maximum length limit is 30 (extra characters in the prefix will be removed.) + // (?U) indicates that the regex is non-greedy regex. + {Regex: `^(?U)(.*)(.{0,30})$`, Replacement: "${2}"}, + // remove the starting non [0-9a-zA-Z] characters + {Regex: `^[^0-9a-zA-Z]*`, Replacement: ""}, + } + + DescribeTable("ReplaceAllString", + func(rs *Replaces, original, expected string) { + actual := rs.ReplaceAllString(original) + Expect(actual).To(Equal(expected)) + }, + Entry("replaces is empty", nil, "original", "original"), + Entry("contains / and _", nameAsTagReplaces, "feat/awesome_feature", "feat-awesome-feature"), + Entry("ending contains / and _", nameAsTagReplaces, "original_/-", "original"), + Entry("starting contains / and _", nameAsTagReplaces, "_/-original", "original"), + Entry("length is 1", nameAsTagReplaces, "a", "a"), + Entry("length greater than 30", nameAsTagReplaces, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), + Entry("length greater than 30", nameAsTagReplaces, "0123456789abcdefghijklmnopqrstuvwxyz/-_+ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + ) +}) From e13573c774aff42dae25dee0e7155de939be3a10 Mon Sep 17 00:00:00 2001 From: qingliu Date: Mon, 6 Feb 2023 14:48:44 +0800 Subject: [PATCH 3/5] feat: add `versionPhase` and `nameAsTag` for git branch status --- apis/meta/v1alpha1/buildmetadata_funcs.go | 22 +++++ .../meta/v1alpha1/buildmetadata_funcs_test.go | 93 +++---------------- apis/meta/v1alpha1/buildmetadata_types.go | 4 + .../testdata/gitstatus.emptymap.golden.yaml | 41 ++++++++ .../testdata/gitstatus.map.golden.yaml | 43 +++++++++ regex/replace.go | 2 +- 6 files changed, 122 insertions(+), 83 deletions(-) create mode 100644 apis/meta/v1alpha1/testdata/gitstatus.emptymap.golden.yaml create mode 100644 apis/meta/v1alpha1/testdata/gitstatus.map.golden.yaml diff --git a/apis/meta/v1alpha1/buildmetadata_funcs.go b/apis/meta/v1alpha1/buildmetadata_funcs.go index 4c09e890..a19f5da2 100644 --- a/apis/meta/v1alpha1/buildmetadata_funcs.go +++ b/apis/meta/v1alpha1/buildmetadata_funcs.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" + kregex "github.com/katanomi/pkg/regex" ksubstitute "github.com/katanomi/pkg/substitution" ) @@ -150,6 +151,8 @@ func (b *BuildRunGitStatus) GetValWithKey(ctx context.Context, path *field.Path) // stringReplacements[path.Child("version").String()] = b.Version // + stringReplacements[path.Child("versionPhase").String()] = b.VersionPhase + // variantsMap := map[string]string{} for variant, version := range b.VersionVariants { // the key is `version` not `versionVariants`, convenient for users. @@ -198,8 +201,27 @@ func (b *BuildGitBranchStatus) GetValWithKey(ctx context.Context, path *field.Pa } stringVals := map[string]string{path.String(): b.Name} stringVals[path.Child("name").String()] = b.Name + stringVals[path.Child("nameAsTag").String()] = nameAsTagReplaces.ReplaceAllString(b.Name) stringVals[path.Child("protected").String()] = strconv.FormatBool(b.Protected) stringVals[path.Child("default").String()] = strconv.FormatBool(b.Default) stringVals[path.Child("webURL").String()] = b.WebURL return stringVals } + +var ( + // nameAsTagReplaces used to generate the tag name from the branch name. + // 1. replacing `/` and `_` to `-` + // 2. remove the ending non [0-9a-zA-Z] characters + // 3. maximum length limit is 30 (extra characters in the prefix will be removed.) + nameAsTagReplaces = kregex.Replaces{ + // replacing `/` and `_` to `-` + {Regex: `[/_]`, Replacement: "-"}, + // remove the ending non [0-9a-zA-Z] characters + {Regex: `[^0-9a-zA-Z]*$`, Replacement: ""}, + // maximum length limit is 30 (extra characters in the prefix will be removed.) + // (?U) indicates that the regex is non-greedy regex. + {Regex: `^(?U)(.*)(.{0,30})$`, Replacement: "${2}"}, + // remove the starting non [0-9a-zA-Z] characters + {Regex: `^[^0-9a-zA-Z]*`, Replacement: ""}, + } +) diff --git a/apis/meta/v1alpha1/buildmetadata_funcs_test.go b/apis/meta/v1alpha1/buildmetadata_funcs_test.go index 2cf928f2..c47c40c9 100644 --- a/apis/meta/v1alpha1/buildmetadata_funcs_test.go +++ b/apis/meta/v1alpha1/buildmetadata_funcs_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/google/go-cmp/cmp" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/validation/field" @@ -78,6 +79,7 @@ var _ = Describe("Test.BuildRunGitStatus.GetValWithKey", func() { ctx context.Context gitStatus *BuildRunGitStatus actual map[string]string + expected map[string]string // // log level. It can be debug, info, warn, error, dpanic, panic, fatal. log, _ = logging.NewLogger("", "debug") @@ -86,6 +88,7 @@ var _ = Describe("Test.BuildRunGitStatus.GetValWithKey", func() { BeforeEach(func() { ctx = context.TODO() gitStatus = &BuildRunGitStatus{} + expected = map[string]string{} Expect(ktesting.LoadYAML("testdata/gitstatus.golden.yaml", &gitStatus)).To(Succeed()) }) @@ -97,96 +100,22 @@ var _ = Describe("Test.BuildRunGitStatus.GetValWithKey", func() { When("struct is empty", func() { BeforeEach(func() { gitStatus = &BuildRunGitStatus{} + ktesting.MustLoadYaml("testdata/gitstatus.emptymap.golden.yaml", &expected) }) It("should have values", func() { - Expect(actual).To(Equal(map[string]string{ - "git": "", - "git.url": "", - "git.version": "", - // - "git.revision": "", - "git.revision.raw": "", - "git.revision.id": "", - "git.revision.type": "", - // - "git.lastCommit": "", - "git.lastCommit.id": "", - "git.lastCommit.shortID": "", - "git.lastCommit.title": "", - "git.lastCommit.message": "", - "git.lastCommit.authorEmail": "", - "git.lastCommit.pushedAt": "", - "git.lastCommit.webURL": "", - // - "git.pullRequest": "", - "git.pullRequest.id": "", - "git.pullRequest.title": "", - "git.pullRequest.source": "", - "git.pullRequest.target": "", - "git.pullRequest.webURL": "", - "git.pullRequest.authorEmail": "", - "git.pullRequest.hasConflicts": "false", - // branch - "git.branch": "", - "git.branch.name": "", - "git.branch.protected": "false", - "git.branch.default": "false", - "git.branch.webURL": "", - // target - "git.target": "", - "git.target.name": "", - "git.target.protected": "false", - "git.target.default": "false", - "git.target.webURL": "", - })) + diff := cmp.Diff(actual, expected) + Expect(diff).To(BeEmpty()) }) }) When("struct is not empty", func() { + BeforeEach(func() { + ktesting.MustLoadYaml("testdata/gitstatus.map.golden.yaml", &expected) + }) It("should have values", func() { - Expect(actual).To(Equal(map[string]string{ - "git": "", - "git.url": "https://github.com/katanomi/pkg", - "git.version": "v1.2.3", - "git.version.docker": "v1.2.3", - "git.version.custom": "v1.2.3-custom", - // - "git.revision": "refs/pulls/123/head", - "git.revision.raw": "refs/pulls/123/head", - "git.revision.id": "123", - "git.revision.type": "PullRequest", - // - "git.lastCommit": "abe83942", - "git.lastCommit.id": "abe83942450308432a12e9679519795f938b2bed", - "git.lastCommit.shortID": "abe83942", - "git.lastCommit.title": "Initial commit 406", - "git.lastCommit.message": "Initial commit 406\n", - "git.lastCommit.authorEmail": "alauda@github.com", - "git.lastCommit.pushedAt": "2020-01-01T01:02:03Z", - "git.lastCommit.webURL": "https://github.com", - // - "git.pullRequest": "1", - "git.pullRequest.id": "1", - "git.pullRequest.title": "test-build ==> master", - "git.pullRequest.source": "test-build", - "git.pullRequest.target": "master", - "git.pullRequest.webURL": "https://github.com/katanomi/pkg/merge_requests/1", - "git.pullRequest.hasConflicts": "true", - "git.pullRequest.authorEmail": "alauda@github.com", - // source in pr - "git.branch": "test-build", - "git.branch.name": "test-build", - "git.branch.protected": "true", - "git.branch.default": "true", - "git.branch.webURL": "https://github.com/katanomi/pkg/tree/test", - // target in pr - "git.target": "release", - "git.target.name": "release", - "git.target.protected": "true", - "git.target.default": "false", - "git.target.webURL": "https://github.com/katanomi/pkg/tree/release", - })) + diff := cmp.Diff(actual, expected) + Expect(diff).To(BeEmpty()) }) }) diff --git a/apis/meta/v1alpha1/buildmetadata_types.go b/apis/meta/v1alpha1/buildmetadata_types.go index 6385453d..aec66a90 100644 --- a/apis/meta/v1alpha1/buildmetadata_types.go +++ b/apis/meta/v1alpha1/buildmetadata_types.go @@ -74,6 +74,10 @@ type BuildRunGitStatus struct { // BaseGitStatus is the base git status BaseGitStatus `json:",inline"` + // VersionPhase is the phase on the versionscheme that matches this git revision. + // +optional + VersionPhase string `json:"versionPhase,omitempty"` + // Version is the version generated for this git revision // +optional Version string `json:"version,omitempty"` diff --git a/apis/meta/v1alpha1/testdata/gitstatus.emptymap.golden.yaml b/apis/meta/v1alpha1/testdata/gitstatus.emptymap.golden.yaml new file mode 100644 index 00000000..9d925b48 --- /dev/null +++ b/apis/meta/v1alpha1/testdata/gitstatus.emptymap.golden.yaml @@ -0,0 +1,41 @@ +"git": "" +"git.url": "" +"git.version": "" +"git.versionPhase": "" +# +"git.revision": "" +"git.revision.raw": "" +"git.revision.id": "" +"git.revision.type": "" +# +"git.lastCommit": "" +"git.lastCommit.id": "" +"git.lastCommit.shortID": "" +"git.lastCommit.title": "" +"git.lastCommit.message": "" +"git.lastCommit.authorEmail": "" +"git.lastCommit.pushedAt": "" +"git.lastCommit.webURL": "" +# +"git.pullRequest": "" +"git.pullRequest.id": "" +"git.pullRequest.title": "" +"git.pullRequest.source": "" +"git.pullRequest.target": "" +"git.pullRequest.webURL": "" +"git.pullRequest.authorEmail": "" +"git.pullRequest.hasConflicts": "false" +# branch +"git.branch": "" +"git.branch.name": "" +"git.branch.nameAsTag": "" +"git.branch.protected": "false" +"git.branch.default": "false" +"git.branch.webURL": "" +# target +"git.target": "" +"git.target.name": "" +"git.target.nameAsTag": "" +"git.target.protected": "false" +"git.target.default": "false" +"git.target.webURL": "" diff --git a/apis/meta/v1alpha1/testdata/gitstatus.map.golden.yaml b/apis/meta/v1alpha1/testdata/gitstatus.map.golden.yaml new file mode 100644 index 00000000..8705e059 --- /dev/null +++ b/apis/meta/v1alpha1/testdata/gitstatus.map.golden.yaml @@ -0,0 +1,43 @@ +"git": "" +"git.url": "https://github.com/katanomi/pkg" +"git.versionPhase": "" +"git.version": "v1.2.3" +"git.version.docker": "v1.2.3" +"git.version.custom": "v1.2.3-custom" +# +"git.revision": "refs/pulls/123/head" +"git.revision.raw": "refs/pulls/123/head" +"git.revision.id": "123" +"git.revision.type": "PullRequest" +# +"git.lastCommit": "abe83942" +"git.lastCommit.id": "abe83942450308432a12e9679519795f938b2bed" +"git.lastCommit.shortID": "abe83942" +"git.lastCommit.title": "Initial commit 406" +"git.lastCommit.message": "Initial commit 406\n" +"git.lastCommit.authorEmail": "alauda@github.com" +"git.lastCommit.pushedAt": "2020-01-01T01:02:03Z" +"git.lastCommit.webURL": "https://github.com" +# +"git.pullRequest": "1" +"git.pullRequest.id": "1" +"git.pullRequest.title": "test-build ==> master" +"git.pullRequest.source": "test-build" +"git.pullRequest.target": "master" +"git.pullRequest.webURL": "https://github.com/katanomi/pkg/merge_requests/1" +"git.pullRequest.hasConflicts": "true" +"git.pullRequest.authorEmail": "alauda@github.com" +# +"git.branch": "test-build" +"git.branch.name": "test-build" +"git.branch.nameAsTag": "test-build" +"git.branch.protected": "true" +"git.branch.default": "true" +"git.branch.webURL": "https://github.com/katanomi/pkg/tree/test" +# +"git.target": "release" +"git.target.name": "release" +"git.target.nameAsTag": "release" +"git.target.protected": "true" +"git.target.default": "false" +"git.target.webURL": "https://github.com/katanomi/pkg/tree/release" diff --git a/regex/replace.go b/regex/replace.go index bc71869c..c85fac4a 100644 --- a/regex/replace.go +++ b/regex/replace.go @@ -17,7 +17,7 @@ package regex import "regexp" -// Replace provide helper functions for replacing strings +// Replace provides helper functions for replacing strings type Replace struct { // Regex is a regular expression used to modify the original version to generate new variants // +optional From 71d6a9ff87bd080281e06a8f2da6dfe232fc25cc Mon Sep 17 00:00:00 2001 From: qingliu Date: Mon, 6 Feb 2023 15:49:07 +0800 Subject: [PATCH 4/5] chore: add validate for replaces --- regex/regex_suite_test.go | 17 ++++- regex/replace.go | 38 +++++++++- regex/replace_test.go | 73 ++++++++++++++++++- ...laces_validation.InvalidData.original.yaml | 3 + .../replaces_validation.Valid.original.yaml | 8 ++ 5 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 regex/testdata/replaces_validation.InvalidData.original.yaml create mode 100644 regex/testdata/replaces_validation.Valid.original.yaml diff --git a/regex/regex_suite_test.go b/regex/regex_suite_test.go index 2b252015..e71d2c9d 100644 --- a/regex/regex_suite_test.go +++ b/regex/regex_suite_test.go @@ -1,4 +1,19 @@ -package regex_test +/* +Copyright 2023 The Katanomi Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. +*/ + +package regex import ( "testing" diff --git a/regex/replace.go b/regex/replace.go index c85fac4a..1af09d80 100644 --- a/regex/replace.go +++ b/regex/replace.go @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -13,9 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + package regex -import "regexp" +import ( + "regexp" + + "k8s.io/apimachinery/pkg/util/validation/field" +) // Replace provides helper functions for replacing strings type Replace struct { @@ -47,3 +52,32 @@ func (rs *Replaces) ReplaceAllString(s string) string { } return s } + +// Validate Replace validation method +func (r *Replace) Validate(fld *field.Path) field.ErrorList { + errs := field.ErrorList{} + + if r.Regex == "" { + return nil + } + _, err := regexp.Compile(r.Regex) + if err != nil { + errs = append(errs, field.Invalid(fld.Child("regex"), r.Regex, err.Error())) + } + + return errs +} + +// Validate Replaces validation method +func (r *Replaces) Validate(fld *field.Path) field.ErrorList { + errs := field.ErrorList{} + + if r == nil { + return nil + } + for i, replace := range *r { + errs = append(errs, replace.Validate(fld.Index(i))...) + } + + return errs +} diff --git a/regex/replace_test.go b/regex/replace_test.go index 4f98947b..e280ac7e 100644 --- a/regex/replace_test.go +++ b/regex/replace_test.go @@ -5,18 +5,26 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + package regex import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + + kvalidation "github.com/katanomi/pkg/apis/validation" + . "github.com/katanomi/pkg/testing" ) var _ = Describe("Test.Replaces.ReplaceAllString", func() { @@ -51,3 +59,66 @@ var _ = Describe("Test.Replaces.ReplaceAllString", func() { Entry("length greater than 30", nameAsTagReplaces, "0123456789abcdefghijklmnopqrstuvwxyz/-_+ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), ) }) + +var _ = Describe("Test.Replaces.Validate", func() { + + var ( + rs Replaces + path *field.Path + errs field.ErrorList + err error + ) + + BeforeEach(func() { + path = field.NewPath("prefix") + rs = Replaces{} + }) + + JustBeforeEach(func() { + errs = rs.Validate(path) + err = kvalidation.ReturnInvalidError(schema.GroupKind{}, "kind", errs) + }) + + Context("empty struct", func() { + It("should NOT return validation error", func() { + Expect(err).To(BeNil(), "should NOT return an error") + }) + }) + + Context("Lots of validation errors", func() { + BeforeEach(func() { + MustLoadYaml("testdata/replaces_validation.InvalidData.original.yaml", &rs) + }) + + It("should return validation error", func() { + Expect(err).ToNot(BeNil(), "should return an error") + Expect(errors.IsInvalid(err)).To(BeTrue(), "should return an invalid error") + + statusErr, _ := err.(*errors.StatusError) + Expect(statusErr.ErrStatus.Details.Causes).To(ContainElements( + metav1.StatusCause{ + Type: "FieldValueInvalid", + Message: "Invalid value: \"[abcd$\": error parsing regexp: missing closing ]: `[abcd$`", + Field: "prefix[0].regex", + }, + metav1.StatusCause{ + Type: "FieldValueInvalid", + Message: "Invalid value: \"^.0,128[.*{$\": error parsing regexp: missing closing ]: `[.*{$`", + Field: "prefix[1].regex", + }, + )) + Expect(statusErr.ErrStatus.Details.Causes).To(HaveLen(2)) + }) + }) + + Context("Valid", func() { + BeforeEach(func() { + MustLoadYaml("testdata/replaces_validation.Valid.original.yaml", &rs) + }) + + It("should not return validation error", func() { + Expect(err).To(BeNil(), "should NOT return an error") + }) + }) + +}) diff --git a/regex/testdata/replaces_validation.InvalidData.original.yaml b/regex/testdata/replaces_validation.InvalidData.original.yaml new file mode 100644 index 00000000..2fd97960 --- /dev/null +++ b/regex/testdata/replaces_validation.InvalidData.original.yaml @@ -0,0 +1,3 @@ +- regex: "[abcd$" + +- regex: "^.0,128[.*{$" diff --git a/regex/testdata/replaces_validation.Valid.original.yaml b/regex/testdata/replaces_validation.Valid.original.yaml new file mode 100644 index 00000000..dbc39d23 --- /dev/null +++ b/regex/testdata/replaces_validation.Valid.original.yaml @@ -0,0 +1,8 @@ +- regex: \+.*$ + +- regex: ^(.{0,128})(.*)$ + replacement: ${1} + +- regex: ^(.{0,128})(.*)$ + replacement: ${1} + From 24a3454f2061c0c173746df8b250e7c6ad535361 Mon Sep 17 00:00:00 2001 From: qingliu Date: Mon, 6 Feb 2023 16:11:39 +0800 Subject: [PATCH 5/5] fix: boilerplate check --- regex/regex_suite_test.go | 3 ++- regex/replace.go | 21 ++++++++++----------- regex/replace_test.go | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/regex/regex_suite_test.go b/regex/regex_suite_test.go index e71d2c9d..9a76050f 100644 --- a/regex/regex_suite_test.go +++ b/regex/regex_suite_test.go @@ -9,7 +9,8 @@ You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and limitations under the License. */ diff --git a/regex/replace.go b/regex/replace.go index 1af09d80..70219b8a 100644 --- a/regex/replace.go +++ b/regex/replace.go @@ -38,13 +38,16 @@ type Replaces []Replace // ReplaceAllString replace all string func (r *Replace) ReplaceAllString(s string) string { + if r == nil || r.Regex == "" { + return s + } re := regexp.MustCompile(r.Regex) return re.ReplaceAllString(s, r.Replacement) } // ReplaceAllString replace all string func (rs *Replaces) ReplaceAllString(s string) string { - if rs == nil { + if rs == nil || len(*rs) == 0 { return s } for _, r := range *rs { @@ -54,30 +57,26 @@ func (rs *Replaces) ReplaceAllString(s string) string { } // Validate Replace validation method -func (r *Replace) Validate(fld *field.Path) field.ErrorList { - errs := field.ErrorList{} - +func (r *Replace) Validate(fld *field.Path) (errs field.ErrorList) { if r.Regex == "" { - return nil + return } _, err := regexp.Compile(r.Regex) if err != nil { errs = append(errs, field.Invalid(fld.Child("regex"), r.Regex, err.Error())) } - return errs + return } // Validate Replaces validation method -func (r *Replaces) Validate(fld *field.Path) field.ErrorList { - errs := field.ErrorList{} - +func (r *Replaces) Validate(fld *field.Path) (errs field.ErrorList) { if r == nil { - return nil + return } for i, replace := range *r { errs = append(errs, replace.Validate(fld.Index(i))...) } - return errs + return } diff --git a/regex/replace_test.go b/regex/replace_test.go index e280ac7e..ccec1f01 100644 --- a/regex/replace_test.go +++ b/regex/replace_test.go @@ -9,7 +9,8 @@ You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and limitations under the License. */