diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go index 3f55b20243a..232fcbbe03f 100644 --- a/pkg/apis/pipeline/v1beta1/openapi_generated.go +++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go @@ -3999,6 +3999,13 @@ func schema_pkg_apis_pipeline_v1beta1_TaskResult(ref common.ReferenceCallback) c Format: "", }, }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type is the user-specified type of the result. The possible type is currently \"string\" and will support \"array\" in following work.", + Type: []string{"string"}, + Format: "", + }, + }, "description": { SchemaProps: spec.SchemaProps{ Description: "Description is a human-readable description of the result", @@ -4294,6 +4301,13 @@ func schema_pkg_apis_pipeline_v1beta1_TaskRunResult(ref common.ReferenceCallback Format: "", }, }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type is the user-specified type of the result. The possible type is currently \"string\" and will support \"array\" in following work.", + Type: []string{"string"}, + Format: "", + }, + }, "value": { SchemaProps: spec.SchemaProps{ Description: "Value the given value of the result", diff --git a/pkg/apis/pipeline/v1beta1/resource_types.go b/pkg/apis/pipeline/v1beta1/resource_types.go index 5b07109e857..0eda026817a 100644 --- a/pkg/apis/pipeline/v1beta1/resource_types.go +++ b/pkg/apis/pipeline/v1beta1/resource_types.go @@ -138,6 +138,8 @@ type PipelineResourceResult struct { } // ResultType used to find out whether a PipelineResourceResult is from a task result or not +// Note that ResultsType is another type which is used to define the data type +// (e.g. string, array, etc) we used for Results type ResultType int // UnmarshalJSON unmarshals either an int or a string into a ResultType. String diff --git a/pkg/apis/pipeline/v1beta1/result_defaults.go b/pkg/apis/pipeline/v1beta1/result_defaults.go new file mode 100644 index 00000000000..28cdc21cfa3 --- /dev/null +++ b/pkg/apis/pipeline/v1beta1/result_defaults.go @@ -0,0 +1,24 @@ +/* +Copyright 2022 The Tekton 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 v1beta1 + +import "context" + +// SetDefaults set the default type for TaskResult +func (tr *TaskResult) SetDefaults(ctx context.Context) { + if tr != nil && tr.Type == "" { + // ResultsTypeString is the default value + tr.Type = ResultsTypeString + } +} diff --git a/pkg/apis/pipeline/v1beta1/result_types.go b/pkg/apis/pipeline/v1beta1/result_types.go new file mode 100644 index 00000000000..2848d45949f --- /dev/null +++ b/pkg/apis/pipeline/v1beta1/result_types.go @@ -0,0 +1,60 @@ +/* +Copyright 2022 The Tekton 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 v1beta1 + +// TaskResult used to describe the results of a task +type TaskResult struct { + // Name the given name + Name string `json:"name"` + + // Type is the user-specified type of the result. The possible type + // is currently "string" and will support "array" in following work. + // +optional + Type ResultsType `json:"type,omitempty"` + + // Description is a human-readable description of the result + // +optional + Description string `json:"description"` +} + +// TaskRunResult used to describe the results of a task +type TaskRunResult struct { + // Name the given name + Name string `json:"name"` + + // Type is the user-specified type of the result. The possible type + // is currently "string" and will support "array" in following work. + // +optional + Type ResultsType `json:"type,omitempty"` + + // Value the given value of the result + Value string `json:"value"` +} + +// ResultsType indicates the type of a result; +// Used to distinguish between a single string and an array of strings. +// Note that there is ResultType used to find out whether a +// PipelineResourceResult is from a task result or not, which is different from +// this ResultsType. +// TODO(#4723): add "array" and "object" support +// TODO(#4723): align ResultsType and ParamType in ArrayOrString +type ResultsType string + +// Valid ResultsType: +const ( + ResultsTypeString ResultsType = "string" +) + +// AllResultsTypes can be used for ResultsTypes validation. +var AllResultsTypes = []ResultsType{ResultsTypeString} diff --git a/pkg/apis/pipeline/v1beta1/result_validation.go b/pkg/apis/pipeline/v1beta1/result_validation.go new file mode 100644 index 00000000000..4c64b780d16 --- /dev/null +++ b/pkg/apis/pipeline/v1beta1/result_validation.go @@ -0,0 +1,40 @@ +/* +Copyright 2022 The Tekton 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 v1beta1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// Validate implements apis.Validatable +func (tr TaskResult) Validate(_ context.Context) *apis.FieldError { + if !resultNameFormatRegex.MatchString(tr.Name) { + return apis.ErrInvalidKeyName(tr.Name, "name", fmt.Sprintf("Name must consist of alphanumeric characters, '-', '_', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my-name', or 'my_name', regex used for validation is '%s')", ResultNameFormat)) + } + // Validate the result type + validType := false + for _, allowedType := range AllResultsTypes { + if tr.Type == allowedType { + validType = true + } + } + if !validType { + return apis.ErrInvalidValue(tr.Type, "type", fmt.Sprintf("type must be string")) + } + + return nil +} diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json index 92af2a98c73..794007f7b02 100644 --- a/pkg/apis/pipeline/v1beta1/swagger.json +++ b/pkg/apis/pipeline/v1beta1/swagger.json @@ -2262,6 +2262,10 @@ "description": "Name the given name", "type": "string", "default": "" + }, + "type": { + "description": "Type is the user-specified type of the result. The possible type is currently \"string\" and will support \"array\" in following work.", + "type": "string" } } }, @@ -2406,6 +2410,10 @@ "type": "string", "default": "" }, + "type": { + "description": "Type is the user-specified type of the result. The possible type is currently \"string\" and will support \"array\" in following work.", + "type": "string" + }, "value": { "description": "Value the given value of the result", "type": "string", diff --git a/pkg/apis/pipeline/v1beta1/task_defaults.go b/pkg/apis/pipeline/v1beta1/task_defaults.go index 8703a41ad60..74eecf139dd 100644 --- a/pkg/apis/pipeline/v1beta1/task_defaults.go +++ b/pkg/apis/pipeline/v1beta1/task_defaults.go @@ -34,6 +34,9 @@ func (ts *TaskSpec) SetDefaults(ctx context.Context) { for i := range ts.Params { ts.Params[i].SetDefaults(ctx) } + for i := range ts.Results { + ts.Results[i].SetDefaults(ctx) + } } // applyImplicitParams propagates implicit params from the parent context diff --git a/pkg/apis/pipeline/v1beta1/task_types.go b/pkg/apis/pipeline/v1beta1/task_types.go index f7067b3a7a9..7a218754193 100644 --- a/pkg/apis/pipeline/v1beta1/task_types.go +++ b/pkg/apis/pipeline/v1beta1/task_types.go @@ -126,16 +126,6 @@ type TaskSpec struct { Results []TaskResult `json:"results,omitempty"` } -// TaskResult used to describe the results of a task -type TaskResult struct { - // Name the given name - Name string `json:"name"` - - // Description is a human-readable description of the result - // +optional - Description string `json:"description"` -} - // Step embeds the Container type, which allows it to include fields not // provided by Container. type Step struct { diff --git a/pkg/apis/pipeline/v1beta1/task_validation.go b/pkg/apis/pipeline/v1beta1/task_validation.go index e6baaed04eb..2a9435fd0b6 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation.go +++ b/pkg/apis/pipeline/v1beta1/task_validation.go @@ -77,14 +77,6 @@ func validateResults(ctx context.Context, results []TaskResult) (errs *apis.Fiel return errs } -// Validate implements apis.Validatable -func (tr TaskResult) Validate(_ context.Context) *apis.FieldError { - if !resultNameFormatRegex.MatchString(tr.Name) { - return apis.ErrInvalidKeyName(tr.Name, "name", fmt.Sprintf("Name must consist of alphanumeric characters, '-', '_', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my-name', or 'my_name', regex used for validation is '%s')", ResultNameFormat)) - } - return nil -} - // a mount path which conflicts with any other declared workspaces, with the explicitly // declared volume mounts, or with the stepTemplate. The names must also be unique. func validateDeclaredWorkspaces(workspaces []WorkspaceDeclaration, steps []Step, stepTemplate *corev1.Container) (errs *apis.FieldError) { diff --git a/pkg/apis/pipeline/v1beta1/task_validation_test.go b/pkg/apis/pipeline/v1beta1/task_validation_test.go index c860b927ded..6cb3391e71b 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/task_validation_test.go @@ -294,6 +294,21 @@ func TestTaskSpecValidate(t *testing.T) { Description: "my great result", }}, }, + }, { + name: "valid result type", + fields: fields{ + Steps: []v1beta1.Step{{ + Container: corev1.Container{ + Image: "my-image", + Args: []string{"arg"}, + }, + }}, + Results: []v1beta1.TaskResult{{ + Name: "MY-RESULT", + Type: "string", + Description: "my great result", + }}, + }, }, { name: "valid task name context", fields: fields{ @@ -956,6 +971,21 @@ func TestTaskSpecValidateError(t *testing.T) { Paths: []string{"results[0].name"}, Details: "Name must consist of alphanumeric characters, '-', '_', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my-name', or 'my_name', regex used for validation is '^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$')", }, + }, { + name: "result type not validate", + fields: fields{ + Steps: validSteps, + Results: []v1beta1.TaskResult{{ + Name: "MY-RESULT", + Type: "wrong", + Description: "my great result", + }}, + }, + expectedError: apis.FieldError{ + Message: `invalid value: wrong`, + Paths: []string{"results[0].type"}, + Details: "type must be string", + }, }, { name: "context not validate", fields: fields{ diff --git a/pkg/apis/pipeline/v1beta1/taskrun_types.go b/pkg/apis/pipeline/v1beta1/taskrun_types.go index abccc5df7a8..1b7937f46e8 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_types.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_types.go @@ -235,15 +235,6 @@ type TaskRunStatusFields struct { TaskSpec *TaskSpec `json:"taskSpec,omitempty"` } -// TaskRunResult used to describe the results of a task -type TaskRunResult struct { - // Name the given name - Name string `json:"name"` - - // Value the given value of the result - Value string `json:"value"` -} - // TaskRunStepOverride is used to override the values of a Step in the corresponding Task. type TaskRunStepOverride struct { // The name of the Step to override.