Skip to content

Commit

Permalink
Introduce Params and Results into StepActions CRD
Browse files Browse the repository at this point in the history
This PR introduces `params` and `results` into the `StepAction` CRD.
It allows the `StepAction` to declare the params it needs and the
results it will produce.
The follow up PRs will contain the interaction of how a `Task` referencing
the `StepAction` resolves them.

All the tests were borrowed from `pkg/apis/pipeline/v1/...` that
overlapped with `paramSpec` and `Results`.
  • Loading branch information
chitrangpatel committed Nov 2, 2023
1 parent 8fd372f commit 44f3368
Show file tree
Hide file tree
Showing 17 changed files with 1,529 additions and 29 deletions.
142 changes: 140 additions & 2 deletions docs/pipeline-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1709,7 +1709,7 @@ If Enum is not set, no input validation is performed for the param.</p>
<h3 id="tekton.dev/v1.ParamSpecs">ParamSpecs
(<code>[]github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.ParamSpec</code> alias)</h3>
<p>
(<em>Appears on:</em><a href="#tekton.dev/v1.PipelineSpec">PipelineSpec</a>, <a href="#tekton.dev/v1.TaskSpec">TaskSpec</a>)
(<em>Appears on:</em><a href="#tekton.dev/v1.PipelineSpec">PipelineSpec</a>, <a href="#tekton.dev/v1.TaskSpec">TaskSpec</a>, <a href="#tekton.dev/v1alpha1.StepActionSpec">StepActionSpec</a>)
</p>
<div>
<p>ParamSpecs is a list of ParamSpec</p>
Expand Down Expand Up @@ -3214,7 +3214,7 @@ this field is false and so declared workspaces are required.</p>
<h3 id="tekton.dev/v1.PropertySpec">PropertySpec
</h3>
<p>
(<em>Appears on:</em><a href="#tekton.dev/v1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1.TaskResult">TaskResult</a>)
(<em>Appears on:</em><a href="#tekton.dev/v1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1.TaskResult">TaskResult</a>, <a href="#tekton.dev/v1alpha1.StepActionResult">StepActionResult</a>)
</p>
<div>
<p>PropertySpec defines the struct for object keys</p>
Expand Down Expand Up @@ -6554,6 +6554,34 @@ string
<p>If Script is not empty, the Step cannot have an Command and the Args will be passed to the Script.</p>
</td>
</tr>
<tr>
<td>
<code>Params</code><br/>
<em>
<a href="#tekton.dev/v1.ParamSpecs">
ParamSpecs
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Params is a list of input parameters required to run the stepAction.
Params must be supplied as inputs in Steps unless they declare a defaultvalue.</p>
</td>
</tr>
<tr>
<td>
<code>Results</code><br/>
<em>
<a href="#tekton.dev/v1alpha1.StepActionResult">
[]StepActionResult
</a>
</em>
</td>
<td>
<p>Results are values that this StepAction can output</p>
</td>
</tr>
</table>
</td>
</tr>
Expand Down Expand Up @@ -7037,6 +7065,18 @@ Hub resource: <a href="https://artifacthub.io/*">https://artifacthub.io/*</a>,</
</tr>
</tbody>
</table>
<h3 id="tekton.dev/v1alpha1.ResultsType">ResultsType
(<code>string</code> alias)</h3>
<p>
(<em>Appears on:</em><a href="#tekton.dev/v1alpha1.StepActionResult">StepActionResult</a>)
</p>
<div>
<p>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
RunResult is from a task result or not, which is different from
this ResultsType.</p>
</div>
<h3 id="tekton.dev/v1alpha1.RunReason">RunReason
(<code>string</code> alias)</h3>
<div>
Expand Down Expand Up @@ -7219,6 +7259,76 @@ Refer Go&rsquo;s ParseDuration documentation for expected format: <a href="https
<div>
<p>StepActionObject is implemented by StepAction</p>
</div>
<h3 id="tekton.dev/v1alpha1.StepActionResult">StepActionResult
</h3>
<p>
(<em>Appears on:</em><a href="#tekton.dev/v1alpha1.StepActionSpec">StepActionSpec</a>)
</p>
<div>
<p>StepActionResult used to describe the results of a task</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>name</code><br/>
<em>
string
</em>
</td>
<td>
<p>Name the given name</p>
</td>
</tr>
<tr>
<td>
<code>type</code><br/>
<em>
<a href="#tekton.dev/v1alpha1.ResultsType">
ResultsType
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Type is the user-specified type of the result. The possible type
is currently &ldquo;string&rdquo; and will support &ldquo;array&rdquo; in following work.</p>
</td>
</tr>
<tr>
<td>
<code>properties</code><br/>
<em>
<a href="#tekton.dev/v1.PropertySpec">
map[string]github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.PropertySpec
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Properties is the JSON Schema properties to support key-value pairs results.</p>
</td>
</tr>
<tr>
<td>
<code>description</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Description is a human-readable description of the result</p>
</td>
</tr>
</tbody>
</table>
<h3 id="tekton.dev/v1alpha1.StepActionSpec">StepActionSpec
</h3>
<p>
Expand Down Expand Up @@ -7314,6 +7424,34 @@ string
<p>If Script is not empty, the Step cannot have an Command and the Args will be passed to the Script.</p>
</td>
</tr>
<tr>
<td>
<code>Params</code><br/>
<em>
<a href="#tekton.dev/v1.ParamSpecs">
ParamSpecs
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Params is a list of input parameters required to run the stepAction.
Params must be supplied as inputs in Steps unless they declare a defaultvalue.</p>
</td>
</tr>
<tr>
<td>
<code>Results</code><br/>
<em>
<a href="#tekton.dev/v1alpha1.StepActionResult">
[]StepActionResult
</a>
</em>
</td>
<td>
<p>Results are values that this StepAction can output</p>
</td>
</tr>
</tbody>
</table>
<h3 id="tekton.dev/v1alpha1.VerificationPolicySpec">VerificationPolicySpec
Expand Down
58 changes: 58 additions & 0 deletions docs/stepactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ A `StepAction` definition supports the following fields:
- `script`
- cannot be used at the same time as using `command`.
- `env`
- [`params`](#declaring-params)
- [`results`](#declaring-results)

The non-functional example below demonstrates the use of most of the above-mentioned fields:

Expand All @@ -55,6 +57,62 @@ spec:
args: ["-lh"]
```

### Declaring Parameters

Like with `Tasks`, a `StepAction` must declare all the parameters that it used. The same rules for `Parameter` [name](./tasks.md/#parameter-name), [type](./tasks.md/#parameter-type) (including [object](./tasks.md/#object-type), [array](./tasks.md/#array-type) and [string](./tasks.md/#string-type)) apply as when declaring them in `Tasks`. A `StepAction` can also provide [default value](./tasks.md/#default-value) to a `Parameter`.

`Parameters` are passed to the `StepAction` from its corresponding `Step` referencing it.

```yaml
apiVersion: tekton.dev/v1alpha1
kind: StepAction
metadata:
name: stepaction-using-params
spec:
params:
- name: gitrepo
type: object
properties:
url:
type: string
commit:
type: string
- name: flags
type: array
- name: outputPath
type: string
default: "/workspace"
image: some-git-image
args: [
"-url=$(params.gitrepo.url)",
"-revision=$(params.gitrepo.commit)",
"-output=$(params.outputPath)",
"$(params.flags[*])",
]
```

### Declaring Results

A `StepAction` also declares the results that it will emit.

```yaml
apiVersion: tekton.dev/v1alpha1
kind: StepAction
metadata:
name: stepaction-declaring-results
spec:
results:
- name: current-date-unix-timestamp
description: The current date in unix timestamp format
- name: current-date-human-readable
description: The current date in human readable format
image: bash:latest
script: |
#!/usr/bin/env bash
date +%s | tee $(results.current-date-unix-timestamp.path)
date | tee $(results.current-date-human-readable.path)
```

## Referencing a StepAction

`StepActions` can be referenced from the `Step` using the `ref` field, as follows:
Expand Down
6 changes: 6 additions & 0 deletions hack/ignored-openapi-violations.list
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1,StepTemplate,DeprecatedTerminationMessagePath
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1,StepTemplate,DeprecatedTerminationMessagePolicy
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/resolution/v1alpha1,ResolutionRequestSpec,Parameters
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,ParamValue,ArrayVal
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,ParamValue,ObjectVal
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,ParamValue,StringVal
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,ParamValue,Type
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,StepActionSpec,Params
API rule violation: names_match,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,StepActionSpec,Results
API rule violation: list_type_missing,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,RunSpec,Workspaces
API rule violation: list_type_missing,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,VerificationPolicySpec,Authorities
API rule violation: list_type_missing,github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1,VerificationPolicySpec,Resources
Expand Down
14 changes: 7 additions & 7 deletions pkg/apis/pipeline/v1/param_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,17 @@ func (pp *ParamSpec) setDefaultsForProperties() {
}
}

// getNames returns all the names of the declared parameters
func (ps ParamSpecs) getNames() []string {
// GetNames returns all the names of the declared parameters
func (ps ParamSpecs) GetNames() []string {
var names []string
for _, p := range ps {
names = append(names, p.Name)
}
return names
}

// sortByType splits the input params into string params, array params, and object params, in that order
func (ps ParamSpecs) sortByType() (ParamSpecs, ParamSpecs, ParamSpecs) {
// SortByType splits the input params into string params, array params, and object params, in that order
func (ps ParamSpecs) SortByType() (ParamSpecs, ParamSpecs, ParamSpecs) {
var stringParams, arrayParams, objectParams ParamSpecs
for _, p := range ps {
switch p.Type {
Expand All @@ -135,10 +135,10 @@ func (ps ParamSpecs) sortByType() (ParamSpecs, ParamSpecs, ParamSpecs) {
return stringParams, arrayParams, objectParams
}

// validateNoDuplicateNames returns an error if any of the params have the same name
func (ps ParamSpecs) validateNoDuplicateNames() *apis.FieldError {
// ValidateNoDuplicateNames returns an error if any of the params have the same name
func (ps ParamSpecs) ValidateNoDuplicateNames() *apis.FieldError {
var errs *apis.FieldError
names := ps.getNames()
names := ps.GetNames()
for dup := range findDups(names) {
errs = errs.Also(apis.ErrGeneric("parameter appears more than once", "").ViaFieldKey("params", dup))
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/pipeline/v1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,9 @@ func (ps *PipelineSpec) validatePipelineParameterUsage(ctx context.Context) (err

// validatePipelineTaskParameterUsage validates that parameters referenced in the Pipeline Tasks are declared by the Pipeline
func validatePipelineTaskParameterUsage(tasks []PipelineTask, params ParamSpecs) (errs *apis.FieldError) {
allParamNames := sets.NewString(params.getNames()...)
_, arrayParams, objectParams := params.sortByType()
arrayParamNames := sets.NewString(arrayParams.getNames()...)
allParamNames := sets.NewString(params.GetNames()...)
_, arrayParams, objectParams := params.SortByType()
arrayParamNames := sets.NewString(arrayParams.GetNames()...)
objectParameterNameKeys := map[string][]string{}
for _, p := range objectParams {
for k := range p.Properties {
Expand Down Expand Up @@ -437,7 +437,7 @@ func validatePipelineTasksWorkspacesUsage(wss []PipelineWorkspaceDeclaration, pt
func ValidatePipelineParameterVariables(ctx context.Context, tasks []PipelineTask, params ParamSpecs) (errs *apis.FieldError) {
// validates all the types within a slice of ParamSpecs
errs = errs.Also(ValidateParameterTypes(ctx, params).ViaField("params"))
errs = errs.Also(params.validateNoDuplicateNames())
errs = errs.Also(params.ValidateNoDuplicateNames())
errs = errs.Also(params.validateParamEnums(ctx).ViaField("params"))
for i, task := range tasks {
errs = errs.Also(task.Params.validateDuplicateParameters().ViaField("params").ViaIndex(i))
Expand Down
24 changes: 12 additions & 12 deletions pkg/apis/pipeline/v1/task_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,16 @@ func (ts *TaskSpec) ValidateBetaFields(ctx context.Context) *apis.FieldError {
// ValidateUsageOfDeclaredParameters validates that all parameters referenced in the Task are declared by the Task.
func ValidateUsageOfDeclaredParameters(ctx context.Context, steps []Step, params ParamSpecs) *apis.FieldError {
var errs *apis.FieldError
_, _, objectParams := params.sortByType()
allParameterNames := sets.NewString(params.getNames()...)
_, _, objectParams := params.SortByType()
allParameterNames := sets.NewString(params.GetNames()...)
errs = errs.Also(validateVariables(ctx, steps, "params", allParameterNames))
errs = errs.Also(validateObjectUsage(ctx, steps, objectParams))
errs = errs.Also(validateObjectParamsHaveProperties(ctx, params))
errs = errs.Also(ValidateObjectParamsHaveProperties(ctx, params))
return errs
}

// validateObjectParamsHaveProperties returns an error if any declared object params are missing properties
func validateObjectParamsHaveProperties(ctx context.Context, params ParamSpecs) *apis.FieldError {
// ValidateObjectParamsHaveProperties returns an error if any declared object params are missing properties
func ValidateObjectParamsHaveProperties(ctx context.Context, params ParamSpecs) *apis.FieldError {
var errs *apis.FieldError
for _, p := range params {
if p.Type == ParamTypeObject && p.Properties == nil {
Expand Down Expand Up @@ -434,12 +434,12 @@ func (p ParamSpec) ValidateObjectType(ctx context.Context) *apis.FieldError {
// ValidateParameterVariables validates all variables within a slice of ParamSpecs against a slice of Steps
func ValidateParameterVariables(ctx context.Context, steps []Step, params ParamSpecs) *apis.FieldError {
var errs *apis.FieldError
errs = errs.Also(params.validateNoDuplicateNames())
errs = errs.Also(params.ValidateNoDuplicateNames())
errs = errs.Also(params.validateParamEnums(ctx).ViaField("params"))
stringParams, arrayParams, objectParams := params.sortByType()
stringParameterNames := sets.NewString(stringParams.getNames()...)
arrayParameterNames := sets.NewString(arrayParams.getNames()...)
errs = errs.Also(validateNameFormat(stringParameterNames.Insert(arrayParameterNames.List()...), objectParams))
stringParams, arrayParams, objectParams := params.SortByType()
stringParameterNames := sets.NewString(stringParams.GetNames()...)
arrayParameterNames := sets.NewString(arrayParams.GetNames()...)
errs = errs.Also(ValidateNameFormat(stringParameterNames.Insert(arrayParameterNames.List()...), objectParams))
return errs.Also(validateArrayUsage(steps, "params", arrayParameterNames))
}

Expand Down Expand Up @@ -560,8 +560,8 @@ func validateVariables(ctx context.Context, steps []Step, prefix string, vars se
return errs
}

// validateNameFormat validates that the name format of all param types follows the rules
func validateNameFormat(stringAndArrayParams sets.String, objectParams []ParamSpec) (errs *apis.FieldError) {
// ValidateNameFormat validates that the name format of all param types follows the rules
func ValidateNameFormat(stringAndArrayParams sets.String, objectParams []ParamSpec) (errs *apis.FieldError) {
// checking string or array name format
// ----
invalidStringAndArrayNames := []string{}
Expand Down
Loading

0 comments on commit 44f3368

Please sign in to comment.