Skip to content

Commit d1361e8

Browse files
committed
Update Version regex to support ranges
Fixes #345 Add positive and negative test cases. Signed-off-by: Todd Short <[email protected]>
1 parent 2114da6 commit d1361e8

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

api/v1alpha1/operator_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type OperatorSpec struct {
2929
PackageName string `json:"packageName"`
3030

3131
//+kubebuilder:validation:MaxLength:=64
32-
//+kubebuilder:validation:Pattern=^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$
32+
//+kubebuilder:validation:Pattern=`^(\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|[x|X|\*])(\.(0|[1-9]\d*|x|X|\*]))?(\.(0|[1-9]\d*|x|X|\*))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)((?:\s+|,\s*|\s*\|\|\s*)(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|x|X|\*])(\.(0|[1-9]\d*|x|X|\*))?(\.(0|[1-9]\d*|x|X|\*]))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)*$`
3333
//+kubebuilder:Optional
3434
// Version is an optional semver constraint on the package version. If not specified, the latest version available of the package will be installed.
3535
// If specified, the specific version of the package will be installed so long as it is available in any of the content sources available.

config/crd/bases/operators.operatorframework.io_operators.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ spec:
5151
sources available. Examples: 1.2.3, 1.0.0-alpha, 1.0.0-rc.1 \n For
5252
more information on semver, please see https://semver.org/"
5353
maxLength: 64
54-
pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$
54+
pattern: ^(\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|[x|X|\*])(\.(0|[1-9]\d*|x|X|\*]))?(\.(0|[1-9]\d*|x|X|\*))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)((?:\s+|,\s*|\s*\|\|\s*)(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|x|X|\*])(\.(0|[1-9]\d*|x|X|\*))?(\.(0|[1-9]\d*|x|X|\*]))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)*$
5555
type: string
5656
required:
5757
- packageName

internal/controllers/admission_test.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ var _ = Describe("Operator Spec Validations", func() {
6161
"1.2.3-pre+bad_metadata",
6262
"1.2.-3",
6363
".1.2.3",
64+
"<<1.2.3",
65+
">>1.2.3",
66+
">~1.2.3",
67+
"==1.2.3",
68+
"=!1.2.3",
69+
"!1.2.3",
70+
"1.Y",
71+
">1.2.3 && <2.3.4",
72+
">1.2.3;<2.3.4",
73+
"1.2.3 - 2.3.4",
6474
}
6575
for _, invalidSemver := range invalidSemvers {
6676
err := cl.Create(ctx, operator(operatorsv1alpha1.OperatorSpec{
@@ -69,7 +79,54 @@ var _ = Describe("Operator Spec Validations", func() {
6979
}))
7080

7181
Expect(err).To(HaveOccurred(), "expected error for invalid semver %q", invalidSemver)
72-
Expect(err.Error()).To(ContainSubstring("spec.version in body should match '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))?$'"))
82+
// Don't need to include the whole regex, this should be enough to match the MasterMinds regex
83+
Expect(err.Error()).To(ContainSubstring("spec.version in body should match '^(\\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\\^)"))
84+
}
85+
})
86+
It("should pass if a valid semver range given", func() {
87+
validSemvers := []string{
88+
">=1.2.3",
89+
"=>1.2.3",
90+
">= 1.2.3",
91+
">=v1.2.3",
92+
">= v1.2.3",
93+
"<=1.2.3",
94+
"=<1.2.3",
95+
"=1.2.3",
96+
"!=1.2.3",
97+
"<1.2.3",
98+
">1.2.3",
99+
"~1.2.2",
100+
"~>1.2.3",
101+
"^1.2.3",
102+
"1.2.3",
103+
"v1.2.3",
104+
"1.x",
105+
"1.X",
106+
"1.*",
107+
"1.2.x",
108+
"1.2.X",
109+
"1.2.*",
110+
">=1.2.3 <2.3.4",
111+
">=1.2.3,<2.3.4",
112+
">=1.2.3, <2.3.4",
113+
"<1.2.3||>2.3.4",
114+
"<1.2.3|| >2.3.4",
115+
"<1.2.3 ||>2.3.4",
116+
"<1.2.3 || >2.3.4",
117+
">1.0.0,<1.2.3 || >2.1.0",
118+
"<1.2.3-abc >2.3.4-def",
119+
"<1.2.3-abc+def >2.3.4-ghi+jkl",
120+
}
121+
for _, validSemver := range validSemvers {
122+
op := operator(operatorsv1alpha1.OperatorSpec{
123+
PackageName: "package",
124+
Version: validSemver,
125+
})
126+
err := cl.Create(ctx, op)
127+
Expect(err).NotTo(HaveOccurred(), "expected success for semver range '%q': %w", validSemver, err)
128+
err = cl.Delete(ctx, op)
129+
Expect(err).NotTo(HaveOccurred(), "unexpected error deleting valid semver '%q': %w", validSemver, err)
73130
}
74131
})
75132
It("should fail if an invalid channel name is given", func() {

0 commit comments

Comments
 (0)