Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions pkg/registry/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func (csv *ClusterServiceVersion) GetVersion() (string, error) {
// GetRelease returns the release of the CSV
//
// If not defined, the function returns an empty string.
// The release field can be either a string or a number.
func (csv *ClusterServiceVersion) GetRelease() (string, error) {
var objmap map[string]*json.RawMessage
if err := json.Unmarshal(csv.Spec, &objmap); err != nil {
Expand All @@ -198,12 +199,24 @@ func (csv *ClusterServiceVersion) GetRelease() (string, error) {
return "", nil
}

// Try to unmarshal as string first (the expected type)
var r string
if err := json.Unmarshal(*rawValue, &r); err != nil {
return "", err
if err := json.Unmarshal(*rawValue, &r); err == nil {
return r, nil
}

// If string unmarshal fails, try as a number and convert to string
var num float64
if err := json.Unmarshal(*rawValue, &num); err == nil {
// Format as integer if it's a whole number, otherwise as float
if num == float64(int64(num)) {
return fmt.Sprintf("%d", int64(num)), nil
}
return fmt.Sprintf("%g", num), nil
}

return r, nil
// If both attempts fail, return an error
return "", fmt.Errorf("release field must be a string or number")
}

// GetSkipRange returns the skiprange of the CSV
Expand Down
95 changes: 95 additions & 0 deletions pkg/registry/csv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,101 @@ func TestClusterServiceVersion_GetVersion(t *testing.T) {
}
}

func TestClusterServiceVersion_GetRelease(t *testing.T) {
type fields struct {
TypeMeta metav1.TypeMeta
ObjectMeta metav1.ObjectMeta
Spec json.RawMessage
}
tests := []struct {
name string
fields fields
want string
wantErr bool
}{
{
name: "string release",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": "1.0.0"}`),
},
want: "1.0.0",
},
{
name: "integer numeric release",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": 20250104}`),
},
want: "20250104",
},
{
name: "float numeric release",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": 0.20250104}`),
},
want: "0.20250104",
},
{
name: "large integer release",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": 20250104235959}`),
},
want: "20250104235959",
},
{
name: "no release field",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"other": "field"}`),
},
want: "",
},
{
name: "null release",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": null}`),
},
want: "",
},
{
name: "invalid release type",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: json.RawMessage(`{"release": true}`),
},
wantErr: true,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth exercising the {"release": ""} case?

}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
csv := &ClusterServiceVersion{
TypeMeta: tt.fields.TypeMeta,
ObjectMeta: tt.fields.ObjectMeta,
Spec: tt.fields.Spec,
}
got, err := csv.GetRelease()
if (err != nil) != tt.wantErr {
t.Errorf("GetRelease() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("GetRelease() got = %v, want %v", got, tt.want)
}
})
}
}

func TestClusterServiceVersion_GetRelatedImages(t *testing.T) {
type fields struct {
TypeMeta metav1.TypeMeta
Expand Down