Skip to content

Commit 54bda50

Browse files
committed
Introduce Value in TaskResults
This PR introduces the field `Value` in `TaskResults`. This field is necessary to capture the results produced by `StepActions` if the Task needs to resolve name conflicts. This is part of issue #7259. Following this PR, we will add support for extracting StepAction results via termination message and sidecar logs.
1 parent 63e1a26 commit 54bda50

15 files changed

+575
-18
lines changed

docs/pipeline-api.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ Used to distinguish between a single string and an array of strings.</p>
17411741
<h3 id="tekton.dev/v1.ParamValue">ParamValue
17421742
</h3>
17431743
<p>
1744-
(<em>Appears on:</em><a href="#tekton.dev/v1.Param">Param</a>, <a href="#tekton.dev/v1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1.PipelineResult">PipelineResult</a>, <a href="#tekton.dev/v1.PipelineRunResult">PipelineRunResult</a>, <a href="#tekton.dev/v1.TaskRunResult">TaskRunResult</a>)
1744+
(<em>Appears on:</em><a href="#tekton.dev/v1.Param">Param</a>, <a href="#tekton.dev/v1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1.PipelineResult">PipelineResult</a>, <a href="#tekton.dev/v1.PipelineRunResult">PipelineRunResult</a>, <a href="#tekton.dev/v1.TaskResult">TaskResult</a>, <a href="#tekton.dev/v1.TaskRunResult">TaskRunResult</a>)
17451745
</p>
17461746
<div>
17471747
<p>ResultValue is a type alias of ParamValue</p>
@@ -4931,6 +4931,20 @@ string
49314931
<p>Description is a human-readable description of the result</p>
49324932
</td>
49334933
</tr>
4934+
<tr>
4935+
<td>
4936+
<code>value</code><br/>
4937+
<em>
4938+
<a href="#tekton.dev/v1.ParamValue">
4939+
ParamValue
4940+
</a>
4941+
</em>
4942+
</td>
4943+
<td>
4944+
<em>(Optional)</em>
4945+
<p>Value the expression used to retrieve the value of the result from an underlying Step.</p>
4946+
</td>
4947+
</tr>
49344948
</tbody>
49354949
</table>
49364950
<h3 id="tekton.dev/v1.TaskRunDebug">TaskRunDebug
@@ -10232,7 +10246,7 @@ Used to distinguish between a single string and an array of strings.</p>
1023210246
<h3 id="tekton.dev/v1beta1.ParamValue">ParamValue
1023310247
</h3>
1023410248
<p>
10235-
(<em>Appears on:</em><a href="#tekton.dev/v1beta1.Param">Param</a>, <a href="#tekton.dev/v1beta1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1beta1.PipelineResult">PipelineResult</a>, <a href="#tekton.dev/v1beta1.PipelineRunResult">PipelineRunResult</a>, <a href="#tekton.dev/v1beta1.TaskRunResult">TaskRunResult</a>)
10249+
(<em>Appears on:</em><a href="#tekton.dev/v1beta1.Param">Param</a>, <a href="#tekton.dev/v1beta1.ParamSpec">ParamSpec</a>, <a href="#tekton.dev/v1beta1.PipelineResult">PipelineResult</a>, <a href="#tekton.dev/v1beta1.PipelineRunResult">PipelineRunResult</a>, <a href="#tekton.dev/v1beta1.TaskResult">TaskResult</a>, <a href="#tekton.dev/v1beta1.TaskRunResult">TaskRunResult</a>)
1023610250
</p>
1023710251
<div>
1023810252
<p>ResultValue is a type alias of ParamValue</p>
@@ -14135,6 +14149,20 @@ string
1413514149
<p>Description is a human-readable description of the result</p>
1413614150
</td>
1413714151
</tr>
14152+
<tr>
14153+
<td>
14154+
<code>value</code><br/>
14155+
<em>
14156+
<a href="#tekton.dev/v1beta1.ParamValue">
14157+
ParamValue
14158+
</a>
14159+
</em>
14160+
</td>
14161+
<td>
14162+
<em>(Optional)</em>
14163+
<p>Value the expression used to retrieve the value of the result from an underlying Step.</p>
14164+
</td>
14165+
</tr>
1413814166
</tbody>
1413914167
</table>
1414014168
<h3 id="tekton.dev/v1beta1.TaskRunConditionType">TaskRunConditionType

pkg/apis/pipeline/v1/openapi_generated.go

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/pipeline/v1/result_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ type TaskResult struct {
3232
// Description is a human-readable description of the result
3333
// +optional
3434
Description string `json:"description,omitempty"`
35+
36+
// Value the expression used to retrieve the value of the result from an underlying Step.
37+
// +optional
38+
Value *ResultValue `json:"value,omitempty"`
3539
}
3640

3741
// TaskRunResult used to describe the results of a task

pkg/apis/pipeline/v1/result_validation.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ package v1
1616
import (
1717
"context"
1818
"fmt"
19+
"regexp"
1920

21+
"github.com/tektoncd/pipeline/pkg/apis/config"
22+
"k8s.io/apimachinery/pkg/util/validation"
2023
"knative.dev/pkg/apis"
2124
)
2225

@@ -28,20 +31,16 @@ func (tr TaskResult) Validate(ctx context.Context) (errs *apis.FieldError) {
2831

2932
switch {
3033
case tr.Type == ResultsTypeObject:
31-
errs := validateObjectResult(tr)
32-
return errs
34+
errs = errs.Also(validateObjectResult(tr))
3335
case tr.Type == ResultsTypeArray:
34-
return nil
3536
// Resources created before the result. Type was introduced may not have Type set
3637
// and should be considered valid
3738
case tr.Type == "":
38-
return nil
3939
// By default, the result type is string
4040
case tr.Type != ResultsTypeString:
41-
return apis.ErrInvalidValue(tr.Type, "type", "type must be string")
41+
errs = errs.Also(apis.ErrInvalidValue(tr.Type, "type", "type must be string"))
4242
}
43-
44-
return nil
43+
return errs.Also(tr.validateValue(ctx))
4544
}
4645

4746
// validateObjectResult validates the object result and check if the Properties is missing
@@ -66,3 +65,60 @@ func validateObjectResult(tr TaskResult) (errs *apis.FieldError) {
6665
}
6766
return nil
6867
}
68+
69+
// validateValue validates the value of the TaskResult.
70+
// It requires that enable-step-actions is true, the value is of type string
71+
// and format $(steps.<stepName>.results.<resultName>)
72+
func (tr TaskResult) validateValue(ctx context.Context) (errs *apis.FieldError) {
73+
if tr.Value == nil {
74+
return nil
75+
}
76+
if !config.FromContextOrDefaults(ctx).FeatureFlags.EnableStepActions {
77+
return apis.ErrGeneric("feature flag %s should be set to true to fetch Results from Steps using StepActions.", config.EnableStepActions)
78+
}
79+
if tr.Value.Type != ParamTypeString {
80+
return &apis.FieldError{
81+
Message: fmt.Sprintf(
82+
"Invalid Type. Wanted string but got: \"%v\"", tr.Value.Type),
83+
Paths: []string{
84+
fmt.Sprintf("%s.type", tr.Name),
85+
},
86+
}
87+
}
88+
if tr.Value.StringVal != "" {
89+
stepName, resultName, err := ExtractStepResultName(tr.Value.StringVal)
90+
if err != nil {
91+
return &apis.FieldError{
92+
Message: fmt.Sprintf("%v", err),
93+
Paths: []string{fmt.Sprintf("%s.value", tr.Name)},
94+
}
95+
}
96+
if e := validation.IsDNS1123Label(stepName); len(e) > 0 {
97+
errs = errs.Also(&apis.FieldError{
98+
Message: fmt.Sprintf("invalid extracted step name %q", stepName),
99+
Paths: []string{fmt.Sprintf("%s.value", tr.Name)},
100+
Details: "stepName in $(steps.<stepName>.results.<resultName>) must be a valid DNS Label, For more info refer to https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
101+
})
102+
}
103+
if !resultNameFormatRegex.MatchString(resultName) {
104+
errs = errs.Also(&apis.FieldError{
105+
Message: fmt.Sprintf("invalid extracted result name %q", resultName),
106+
Paths: []string{fmt.Sprintf("%s.value", tr.Name)},
107+
Details: fmt.Sprintf("resultName in $(steps.<stepName>.results.<resultName>) 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),
108+
})
109+
}
110+
}
111+
return errs
112+
}
113+
114+
// ExtractStepResultName extracts the step name and result name from a string matching
115+
// formtat $(steps.<stepName>.results.<resultName>).
116+
// If a match is not found, an error is retured.
117+
func ExtractStepResultName(value string) (string, string, error) {
118+
re := regexp.MustCompile(`\$\(steps\.(.*?)\.results\.(.*?)\)`)
119+
rs := re.FindStringSubmatch(value)
120+
if len(rs) != 3 {
121+
return "", "", fmt.Errorf("Could not extract step name and result name. Expected value to look like $(steps.<stepName>.results.<resultName>) but got \"%v\"", value)
122+
}
123+
return rs[1], rs[2], nil
124+
}

0 commit comments

Comments
 (0)