diff --git a/config/300-crds/300-task.yaml b/config/300-crds/300-task.yaml index bdae311fddc..55a1f0b35a3 100644 --- a/config/300-crds/300-task.yaml +++ b/config/300-crds/300-task.yaml @@ -2985,6 +2985,11 @@ spec: items: type: string x-kubernetes-list-type: atomic + displayName: + description: |- + DisplayName is a user-facing name of the step that may be + used to populate a UI. + type: string env: description: |- List of environment variables to set in the container. @@ -6624,6 +6629,11 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + displayName: + description: |- + DisplayName is a user-facing name of the step that may be + used to populate a UI. + type: string env: description: |- List of environment variables to set in the Step. diff --git a/config/300-crds/300-taskrun.yaml b/config/300-crds/300-taskrun.yaml index 46cfe082c3b..eb4f95387f0 100644 --- a/config/300-crds/300-taskrun.yaml +++ b/config/300-crds/300-taskrun.yaml @@ -6277,6 +6277,11 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + displayName: + description: |- + DisplayName is a user-facing name of the step that may be + used to populate a UI. + type: string env: description: |- List of environment variables to set in the Step. diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md index 20e1faee3cd..dddeab8f53e 100644 --- a/docs/pipeline-api.md +++ b/docs/pipeline-api.md @@ -4389,6 +4389,19 @@ Each Step in a Task must have a unique name.

+displayName
+ +string + + + +(Optional) +

DisplayName is a user-facing name of the step that may be +used to populate a UI.

+ + + + image
string @@ -13516,6 +13529,19 @@ Each Step in a Task must have a unique name.

+displayName
+ +string + + + +(Optional) +

DisplayName is a user-facing name of the step that may be +used to populate a UI.

+ + + + image
string diff --git a/docs/stepactions.md b/docs/stepactions.md index 5801c4b04f3..32b914a4ee2 100644 --- a/docs/stepactions.md +++ b/docs/stepactions.md @@ -52,6 +52,7 @@ A `StepAction` definition supports the following fields: - [`workingDir`](#declaring-workingdir) - [`securityContext`](#declaring-securitycontext) - [`volumeMounts`](#declaring-volumemounts) + - [`description`](#declaring-description) [kubernetes-overview]: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields @@ -384,6 +385,22 @@ spec: script: ... ``` +### Declaring description + +The `description` field is an optional field that allows you to add a user-facing name to the step that may be used to populate a UI. + +```yaml +apiVersion: tekton.dev/v1 +kind: StepAction +metadata: + name: myStep +spec: + description: my step + params: ... + volumeMounts: ... + image: ... + script: ... +``` ### Referencing a StepAction diff --git a/docs/tasks.md b/docs/tasks.md index 25b5168b0d1..3820dcae262 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -20,6 +20,7 @@ weight: 201 - [Breakpoint on failure with `onError`](#breakpoint-on-failure-with-onerror) - [Redirecting step output streams with `stdoutConfig` and `stderrConfig`](#redirecting-step-output-streams-with-stdoutconfig-and-stderrconfig) - [Guarding `Step` execution using `when` expressions](#guarding-step-execution-using-when-expressions) + - [Specifying `DisplayName`](#specifying-displayname) - [Specifying `Parameters`](#specifying-parameters) - [Specifying `Workspaces`](#specifying-workspaces) - [Emitting `Results`](#emitting-results) @@ -599,6 +600,22 @@ The StepState for a skipped step looks like something similar to the below: ``` Where `terminated.exitCode` is `0` and `terminationReason` is `Skipped` to indicate the Step exited successfully and was skipped. +#### Specifying `DisplayName` + +The `displayName` field is an optional field that allows you to add a user-facing name to the step that may be used to populate a UI. + +```yaml +steps: + - name: ignore-failure-and-produce-a-result + displayName: "Ignore failure and produce a result" + onError: continue + image: busybox + script: | + echo -n 123 | tee $(results.result1.path) + exit 1 + echo -n 456 | tee $(results.result2.path) +``` + ### Specifying `Parameters` You can specify parameters, such as compilation flags or artifact names, that you want to supply to the `Task` at execution time. diff --git a/examples/v1/pipelineruns/beta/pipelinerun-with-matrix-and-taskrunspecs-param-substitution.yaml b/examples/v1/pipelineruns/beta/pipelinerun-with-matrix-and-taskrunspecs-param-substitution.yaml index d51d40fbbd8..f998d234511 100644 --- a/examples/v1/pipelineruns/beta/pipelinerun-with-matrix-and-taskrunspecs-param-substitution.yaml +++ b/examples/v1/pipelineruns/beta/pipelinerun-with-matrix-and-taskrunspecs-param-substitution.yaml @@ -27,6 +27,7 @@ spec: - name: node-type steps: - name: build-and-push + displayName: "Build and push" image: ubuntu script: | echo "building on $(params.node-type)" diff --git a/examples/v1/pipelineruns/beta/pipelinerun-with-matrix.yaml b/examples/v1/pipelineruns/beta/pipelinerun-with-matrix.yaml index 1f4f2b338d9..9e4916b8777 100644 --- a/examples/v1/pipelineruns/beta/pipelinerun-with-matrix.yaml +++ b/examples/v1/pipelineruns/beta/pipelinerun-with-matrix.yaml @@ -11,6 +11,7 @@ spec: - name: browser steps: - name: echo + displayName: "echo platform and browser" image: mirror.gcr.io/alpine script: | echo "$(params.platform) and $(params.browser)" diff --git a/examples/v1/pipelineruns/pipeline-with-displayname.yaml b/examples/v1/pipelineruns/pipeline-with-displayname.yaml index 28bba882ec7..74040110f91 100644 --- a/examples/v1/pipelineruns/pipeline-with-displayname.yaml +++ b/examples/v1/pipelineruns/pipeline-with-displayname.yaml @@ -18,6 +18,7 @@ spec: description: The sum of the two provided integers steps: - name: sum + displayName: Do the sum image: mirror.gcr.io/bash script: | #!/usr/bin/env bash diff --git a/examples/v1/pipelineruns/pipelinerun-with-pipelinespec-and-taskspec.yaml b/examples/v1/pipelineruns/pipelinerun-with-pipelinespec-and-taskspec.yaml index 45431740245..cb213b0f3ee 100644 --- a/examples/v1/pipelineruns/pipelinerun-with-pipelinespec-and-taskspec.yaml +++ b/examples/v1/pipelineruns/pipelinerun-with-pipelinespec-and-taskspec.yaml @@ -12,6 +12,7 @@ spec: app: "example" steps: - name: echo + displayName: "echo step" image: mirror.gcr.io/ubuntu script: | #!/usr/bin/env bash diff --git a/pkg/apis/pipeline/v1/container_types.go b/pkg/apis/pipeline/v1/container_types.go index 3e20e34982d..45d6c5dec5f 100644 --- a/pkg/apis/pipeline/v1/container_types.go +++ b/pkg/apis/pipeline/v1/container_types.go @@ -25,6 +25,10 @@ type Step struct { // Name of the Step specified as a DNS_LABEL. // Each Step in a Task must have a unique name. Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + // DisplayName is a user-facing name of the step that may be + // used to populate a UI. + // +optional + DisplayName string `json:"displayName,omitempty"` // Docker image name. // More info: https://kubernetes.io/docs/concepts/containers/images // +optional diff --git a/pkg/apis/pipeline/v1/openapi_generated.go b/pkg/apis/pipeline/v1/openapi_generated.go index 1b9bb396c39..37a66c84946 100644 --- a/pkg/apis/pipeline/v1/openapi_generated.go +++ b/pkg/apis/pipeline/v1/openapi_generated.go @@ -2874,6 +2874,13 @@ func schema_pkg_apis_pipeline_v1_Step(ref common.ReferenceCallback) common.OpenA Format: "", }, }, + "displayName": { + SchemaProps: spec.SchemaProps{ + Description: "DisplayName is a user-facing name of the step that may be used to populate a UI.", + Type: []string{"string"}, + Format: "", + }, + }, "image": { SchemaProps: spec.SchemaProps{ Description: "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images", diff --git a/pkg/apis/pipeline/v1/pipeline_types_test.go b/pkg/apis/pipeline/v1/pipeline_types_test.go index f9e00a0213d..07dac3adb8b 100644 --- a/pkg/apis/pipeline/v1/pipeline_types_test.go +++ b/pkg/apis/pipeline/v1/pipeline_types_test.go @@ -1163,6 +1163,19 @@ func TestPipelineTask_ValidateEmbeddedOrType(t *testing.T) { }, }, }, + }, { + name: "just steps with DisplayName", + pt: PipelineTask{ + TaskSpec: &EmbeddedTask{ + TaskSpec: TaskSpec{ + Steps: []Step{{ + Name: "foo", + DisplayName: "step DisplayName", + Image: "bar", + }}, + }, + }, + }, }, { name: "apiVersion and steps", pt: PipelineTask{ diff --git a/pkg/apis/pipeline/v1/swagger.json b/pkg/apis/pipeline/v1/swagger.json index 537df3ba0a0..2dd13f3a2ad 100644 --- a/pkg/apis/pipeline/v1/swagger.json +++ b/pkg/apis/pipeline/v1/swagger.json @@ -1497,6 +1497,10 @@ "default": {}, "$ref": "#/definitions/v1.ResourceRequirements" }, + "displayName": { + "description": "DisplayName is a user-facing name of the step that may be used to populate a UI.", + "type": "string" + }, "env": { "description": "List of environment variables to set in the Step. Cannot be updated.", "type": "array", diff --git a/pkg/apis/pipeline/v1/task_validation_test.go b/pkg/apis/pipeline/v1/task_validation_test.go index 1a4e1655927..8d95b0ea0a0 100644 --- a/pkg/apis/pipeline/v1/task_validation_test.go +++ b/pkg/apis/pipeline/v1/task_validation_test.go @@ -70,6 +70,28 @@ func TestTaskValidate(t *testing.T) { }) } } +func TestTaskValidateStepWithDisplayName(t *testing.T) { + t.Run("valid task with step display name", func(t *testing.T) { + ctx := t.Context() + task := &v1.Task{ + ObjectMeta: metav1.ObjectMeta{Name: "task"}, + Spec: v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "my-step", + DisplayName: "My Step", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + echo hello`, + }}, + }, + } + err := task.Validate(ctx) + if err != nil { + t.Errorf("Task.Validate() returned error for valid Task: %v", err) + } + }) +} func TestTaskSpecValidatePropagatedParamsAndWorkspaces(t *testing.T) { type fields struct { @@ -371,6 +393,19 @@ func TestTaskSpecValidate(t *testing.T) { MountPath: "some/path", }}, }, + }, { + name: "valid step with displayName", + fields: fields{ + Steps: []v1.Step{{ + Image: "my-image", + DisplayName: "Step with DisplayName", + Args: []string{"arg"}, + }}, + Results: []v1.TaskResult{{ + Name: "MY-RESULT", + Description: "my great result", + }}, + }, }, { name: "valid result", fields: fields{ diff --git a/pkg/apis/pipeline/v1beta1/container_conversion.go b/pkg/apis/pipeline/v1beta1/container_conversion.go index 5b61377bcc8..2939b6bbf45 100644 --- a/pkg/apis/pipeline/v1beta1/container_conversion.go +++ b/pkg/apis/pipeline/v1beta1/container_conversion.go @@ -38,6 +38,7 @@ func (r *Ref) convertFrom(ctx context.Context, source v1.Ref) { func (s Step) convertTo(ctx context.Context, sink *v1.Step) { sink.Name = s.Name + sink.DisplayName = s.DisplayName sink.Image = s.Image sink.Command = s.Command sink.Args = s.Args @@ -81,6 +82,7 @@ func (s Step) convertTo(ctx context.Context, sink *v1.Step) { func (s *Step) convertFrom(ctx context.Context, source v1.Step) { s.Name = source.Name + s.DisplayName = source.DisplayName s.Image = source.Image s.Command = source.Command s.Args = source.Args diff --git a/pkg/apis/pipeline/v1beta1/container_types.go b/pkg/apis/pipeline/v1beta1/container_types.go index 8338789300c..2510c95caf4 100644 --- a/pkg/apis/pipeline/v1beta1/container_types.go +++ b/pkg/apis/pipeline/v1beta1/container_types.go @@ -27,6 +27,10 @@ type Step struct { // Name of the Step specified as a DNS_LABEL. // Each Step in a Task must have a unique name. Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + // DisplayName is a user-facing name of the step that may be + // used to populate a UI. + // +optional + DisplayName string `json:"displayName,omitempty"` // Image reference name to run for this Step. // More info: https://kubernetes.io/docs/concepts/containers/images // +optional diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go index 82327d285b7..92b32cb19ea 100644 --- a/pkg/apis/pipeline/v1beta1/openapi_generated.go +++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go @@ -3637,6 +3637,13 @@ func schema_pkg_apis_pipeline_v1beta1_Step(ref common.ReferenceCallback) common. Format: "", }, }, + "displayName": { + SchemaProps: spec.SchemaProps{ + Description: "DisplayName is a user-facing name of the step that may be used to populate a UI.", + Type: []string{"string"}, + Format: "", + }, + }, "image": { SchemaProps: spec.SchemaProps{ Description: "Image reference name to run for this Step. More info: https://kubernetes.io/docs/concepts/containers/images", diff --git a/pkg/apis/pipeline/v1beta1/pipeline_types_test.go b/pkg/apis/pipeline/v1beta1/pipeline_types_test.go index bf7d19b72ea..483a2a5f713 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_types_test.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_types_test.go @@ -1119,6 +1119,19 @@ func TestPipelineTask_ValidateEmbeddedOrType(t *testing.T) { }, }, }, + }, { + name: "just steps with DisplayName", + pt: PipelineTask{ + TaskSpec: &EmbeddedTask{ + TaskSpec: TaskSpec{ + Steps: []Step{{ + Name: "foo", + DisplayName: "step DisplayName", + Image: "bar", + }}, + }, + }, + }, }, { name: "apiVersion and steps", pt: PipelineTask{ diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json index 629cc02417f..087f55fcd58 100644 --- a/pkg/apis/pipeline/v1beta1/swagger.json +++ b/pkg/apis/pipeline/v1beta1/swagger.json @@ -2045,6 +2045,10 @@ }, "x-kubernetes-list-type": "atomic" }, + "displayName": { + "description": "DisplayName is a user-facing name of the step that may be used to populate a UI.", + "type": "string" + }, "env": { "description": "List of environment variables to set in the container. Cannot be updated.", "type": "array", diff --git a/pkg/apis/pipeline/v1beta1/task_conversion_test.go b/pkg/apis/pipeline/v1beta1/task_conversion_test.go index ce7a02df823..ec6a8114e60 100644 --- a/pkg/apis/pipeline/v1beta1/task_conversion_test.go +++ b/pkg/apis/pipeline/v1beta1/task_conversion_test.go @@ -52,6 +52,7 @@ spec: description: test steps: - image: foo + - displayName: "step-display-name" params: - name: param-1 type: string diff --git a/pkg/apis/pipeline/v1beta1/task_validation_test.go b/pkg/apis/pipeline/v1beta1/task_validation_test.go index 504ed091600..2bdeb0431cf 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/task_validation_test.go @@ -423,6 +423,19 @@ func TestTaskSpecValidate(t *testing.T) { MountPath: "some/path", }}, }, + }, { + name: "valid step with displayName", + fields: fields{ + Steps: []v1beta1.Step{{ + Image: "my-image", + DisplayName: "Step with DisplayName", + Args: []string{"arg"}, + }}, + Results: []v1beta1.TaskResult{{ + Name: "MY-RESULT", + Description: "my great result", + }}, + }, }, { name: "valid result", fields: fields{ @@ -2787,3 +2800,25 @@ func TestTaskSpecValidate_StepWhen_Error(t *testing.T) { }) } } +func TestTaskValidateStepWithDisplayName(t *testing.T) { + t.Run("valid task with step display name", func(t *testing.T) { + ctx := t.Context() + task := &v1beta1.Task{ + ObjectMeta: metav1.ObjectMeta{Name: "task"}, + Spec: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{ + Name: "my-step", + DisplayName: "My Step", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + echo hello`, + }}, + }, + } + err := task.Validate(ctx) + if err != nil { + t.Errorf("Task.Validate() returned error for valid Task: %v", err) + } + }) +}