diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go index 8fc4c6ee666..4bdac75344f 100644 --- a/pkg/apis/pipeline/v1beta1/openapi_generated.go +++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go @@ -1135,7 +1135,7 @@ func schema_pkg_apis_pipeline_v1beta1_ParamSpec(ref common.ReferenceCallback) co }, "type": { SchemaProps: spec.SchemaProps{ - Description: "Type is the user-specified type of the parameter. The possible types are currently \"string\" and \"array\", and \"string\" is the default.", + Description: "Type is the user-specified type of the parameter. The possible types are currently \"string\", \"array\" and \"object\", and \"string\" is the default.", Type: []string{"string"}, Format: "", }, @@ -2928,7 +2928,8 @@ func schema_pkg_apis_pipeline_v1beta1_PropertySpec(ref common.ReferenceCallback) return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "PropertySpec defines the struct for object keys", + Type: []string{"object"}, Properties: map[string]spec.Schema{ "type": { SchemaProps: spec.SchemaProps{ diff --git a/pkg/apis/pipeline/v1beta1/param_context.go b/pkg/apis/pipeline/v1beta1/param_context.go index a2d3882f310..1a4f0cdcee2 100644 --- a/pkg/apis/pipeline/v1beta1/param_context.go +++ b/pkg/apis/pipeline/v1beta1/param_context.go @@ -86,6 +86,7 @@ func addContextParamSpec(ctx context.Context, in []ParamSpec) context.Context { Name: p.Name, Type: p.Type, Description: p.Description, + Properties: p.Properties, Default: p.Default, } out[p.Name] = cps @@ -161,6 +162,7 @@ func getContextParamSpecs(ctx context.Context) []ParamSpec { Name: ps.Name, Type: ps.Type, Description: ps.Description, + Properties: ps.Properties, Default: ps.Default, }) } diff --git a/pkg/apis/pipeline/v1beta1/param_types.go b/pkg/apis/pipeline/v1beta1/param_types.go index ab8e1877561..6bc299cd94f 100644 --- a/pkg/apis/pipeline/v1beta1/param_types.go +++ b/pkg/apis/pipeline/v1beta1/param_types.go @@ -38,7 +38,7 @@ type ParamSpec struct { // Name declares the name by which a parameter is referenced. Name string `json:"name"` // Type is the user-specified type of the parameter. The possible types - // are currently "string" and "array", and "string" is the default. + // are currently "string", "array" and "object", and "string" is the default. // +optional Type ParamType `json:"type,omitempty"` // Description is a user-facing description of the parameter that may be @@ -55,6 +55,7 @@ type ParamSpec struct { Default *ArrayOrString `json:"default,omitempty"` } +// PropertySpec defines the struct for object keys type PropertySpec struct { Type ParamType `json:"type,omitempty"` } @@ -62,7 +63,13 @@ type PropertySpec struct { // SetDefaults set the default type func (pp *ParamSpec) SetDefaults(ctx context.Context) { if pp != nil && pp.Type == "" { - if pp.Default != nil { + // if the properties section is not empty, set object as the parameter type + if pp.Properties != nil { + pp.Type = ParamTypeObject + for _, property := range pp.Properties { + property.Type = ParamTypeString + } + } else if pp.Default != nil { // propagate the parsed ArrayOrString's type to the parent ParamSpec's type if pp.Default.Type != "" { // propagate the default type if specified @@ -73,9 +80,6 @@ func (pp *ParamSpec) SetDefaults(ctx context.Context) { pp.Type = ParamTypeArray } else if pp.Default.ObjectVal != nil { pp.Type = ParamTypeObject - for _, property := range pp.Properties { - property.Type = ParamTypeString - } } else { pp.Type = ParamTypeString } @@ -126,12 +130,17 @@ type ArrayOrString struct { // UnmarshalJSON implements the json.Unmarshaller interface. func (arrayOrString *ArrayOrString) UnmarshalJSON(value []byte) error { - if value[0] == '"' { + switch value[0] { + case '"': arrayOrString.Type = ParamTypeString return json.Unmarshal(value, &arrayOrString.StringVal) + case '[': + arrayOrString.Type = ParamTypeArray + return json.Unmarshal(value, &arrayOrString.ArrayVal) + default: + arrayOrString.Type = ParamTypeObject + return json.Unmarshal(value, &arrayOrString.ObjectVal) } - arrayOrString.Type = ParamTypeArray - return json.Unmarshal(value, &arrayOrString.ArrayVal) } // MarshalJSON implements the json.Marshaller interface. @@ -141,6 +150,8 @@ func (arrayOrString ArrayOrString) MarshalJSON() ([]byte, error) { return json.Marshal(arrayOrString.StringVal) case ParamTypeArray: return json.Marshal(arrayOrString.ArrayVal) + case ParamTypeObject: + return json.Marshal(arrayOrString.ObjectVal) default: return []byte{}, fmt.Errorf("impossible ArrayOrString.Type: %q", arrayOrString.Type) } diff --git a/pkg/apis/pipeline/v1beta1/param_types_test.go b/pkg/apis/pipeline/v1beta1/param_types_test.go index cb3fc1cb720..ba9c99e2420 100644 --- a/pkg/apis/pipeline/v1beta1/param_types_test.go +++ b/pkg/apis/pipeline/v1beta1/param_types_test.go @@ -86,6 +86,17 @@ func TestParamSpec_SetDefaults(t *testing.T) { ObjectVal: map[string]string{"url": "test", "path": "test"}, }, }, + }, { + name: "inferred type from properties - object", + before: &v1beta1.ParamSpec{ + Name: "parametername", + Properties: map[string]v1beta1.PropertySpec{"key1": {}}, + }, + defaultsApplied: &v1beta1.ParamSpec{ + Name: "parametername", + Type: v1beta1.ParamTypeObject, + Properties: map[string]v1beta1.PropertySpec{"key1": {}}, + }, }, { name: "fully defined ParamSpec - array", before: &v1beta1.ParamSpec{ @@ -209,6 +220,7 @@ func TestArrayOrString_UnmarshalJSON(t *testing.T) { {"{\"val\":[]}", v1beta1.ArrayOrString{Type: v1beta1.ParamTypeArray, ArrayVal: []string{}}}, {"{\"val\":[\"oneelement\"]}", v1beta1.ArrayOrString{Type: v1beta1.ParamTypeArray, ArrayVal: []string{"oneelement"}}}, {"{\"val\":[\"multiple\", \"elements\"]}", *v1beta1.NewArrayOrString("multiple", "elements")}, + {"{\"val\":{\"key1\":\"var1\", \"key2\":\"var2\"}}", *v1beta1.NewObject(map[string]string{"key1":"var1", "key2":"var2"})}, } for _, c := range cases { @@ -230,6 +242,7 @@ func TestArrayOrString_MarshalJSON(t *testing.T) { {*v1beta1.NewArrayOrString("123"), "{\"val\":\"123\"}"}, {*v1beta1.NewArrayOrString("123", "1234"), "{\"val\":[\"123\",\"1234\"]}"}, {*v1beta1.NewArrayOrString("a", "a", "a"), "{\"val\":[\"a\",\"a\",\"a\"]}"}, + {*v1beta1.NewObject(map[string]string{"key1":"var1", "key2":"var2"}), "{\"val\":{\"key1\":\"var1\",\"key2\":\"var2\"}}"}, } for _, c := range cases { diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json index 68732ff498f..b28b59c1d50 100644 --- a/pkg/apis/pipeline/v1beta1/swagger.json +++ b/pkg/apis/pipeline/v1beta1/swagger.json @@ -737,7 +737,7 @@ } }, "type": { - "description": "Type is the user-specified type of the parameter. The possible types are currently \"string\" and \"array\", and \"string\" is the default.", + "description": "Type is the user-specified type of the parameter. The possible types are currently \"string\", \"array\" and \"object\", and \"string\" is the default.", "type": "string" } } @@ -1659,6 +1659,7 @@ } }, "v1beta1.PropertySpec": { + "description": "PropertySpec defines the struct for object keys", "type": "object", "properties": { "type": { diff --git a/pkg/apis/pipeline/v1beta1/task_validation.go b/pkg/apis/pipeline/v1beta1/task_validation.go index 927ab829c57..b2a89a27dfe 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation.go +++ b/pkg/apis/pipeline/v1beta1/task_validation.go @@ -266,6 +266,16 @@ func (p ParamSpec) ValidateType() *apis.FieldError { return apis.ErrInvalidValue(p.Type, fmt.Sprintf("%s.type", p.Name)) } + if p.Type == ParamTypeObject && p.Properties == nil { + return &apis.FieldError{ + Message: "The parameter of object type misses the definition of `properties`", + Paths: []string{ + fmt.Sprintf("%s.type", p.Name), + fmt.Sprintf("%s.default.type", p.Name), + }, + } + } + // If a default value is provided, ensure its type matches param's declared type. if (p.Default != nil) && (p.Default.Type != p.Type) { return &apis.FieldError{