Skip to content

TEP-0048: default results - #9653

Open
pritidesai wants to merge 1 commit into
tektoncd:mainfrom
pritidesai:tep-0048
Open

TEP-0048: default results#9653
pritidesai wants to merge 1 commit into
tektoncd:mainfrom
pritidesai:tep-0048

Conversation

@pritidesai

@pritidesai pritidesai commented Mar 24, 2026

Copy link
Copy Markdown
Member

Changes

This commit introduces default results, allowing task authors to specify a default value for a result. If a task does not produce a value for that result during execution, the specified default will be used. This ensures that downstream tasks referencing that result can still resolve params consuming the results, preventing unnecessary failures in the pipeline.

With this change, if a task author does not define a default value and none of the steps produce the corresponding result, the entire taskRun will be marked as failed.

For more details, please refer to TEP-0048

The changes in this PR are based on #5620 authored by @vinamra28.

Co-authored-by: Vinamra Jain vinjain@redhat.com

Assisted-by: Claude Sonnet 4.6

/kind feature

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

  • Has Docs if any changes are user facing, including updates to minimum requirements e.g. Kubernetes version bumps
  • Has Tests included if any functionality added or changed
  • pre-commit Passed
  • Follows the commit message standard
  • Meets the Tekton contributor standards (including functionality, content, code)
  • Has a kind label. You can add one by adding a comment on this PR that contains /kind <type>. Valid types are bug, cleanup, design, documentation, feature, flake, misc, question, tep
  • Release notes block below has been updated with any user facing changes (API changes, bug fixes, changes requiring upgrade notices or deprecation warnings). See some examples of good release notes.
  • Release notes contains the string "action required" if the change requires additional action from users switching to the new release

Release Notes

Added an optional default field to Task result declarations. When a task fails to produce a result at runtime — because a step failed, was skipped, or simply never wrote to the result path — the declared default value is used instead.

This allows pipelines to continue executing even when a parent task doesn't produce its results. Dependent tasks consuming those results via params, WhenExpressions, or Pipeline Results will receive the default value rather than failing with a result resolution error.

 spec:
    results:
      - name: merge-strategy
         type: string
         default: "rebase"
      - name: branches
         type: array
         default:
           - main
           - v1beta1

The feature is gated behind the enable-default-results alpha feature flag. See TEP-0048 for full design details.

@tekton-robot tekton-robot added kind/feature Categorizes issue or PR as related to a new feature. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Mar 24, 2026
@tekton-robot tekton-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 24, 2026
@pritidesai
pritidesai force-pushed the tep-0048 branch 6 times, most recently from 05d242d to 7996ae5 Compare March 24, 2026 05:05
@vdemeester

Copy link
Copy Markdown
Member

/assign

@afrittoli afrittoli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you Priti for this, it would be great to have this feature!
And thanks for dealing with the matrix case too.

The only real concern I have is with the change of signature of exported functions and inconsistent use of context there, I made a suggestion which I think will simplify things (reduce changes) and fix the issue.

I suggested a couple of improvements with helper functions as well.

BTW, do you plan on implementing default results for pipelines in case of skipped tasks as well?

Comment thread docs/tasks.md
Comment thread pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go Outdated
Comment on lines +272 to +276
for _, taskResult := range resolvedTask.TaskSpec.Results {
if taskResult.Name == reference.Result && taskResult.Default != nil {
return *taskResult.Default, nil
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop is used in a few places, perhaps it's worth factoring it up to a private function, e.g.

// taskResultDefault returns the default value for resultName from the TaskSpec,
// or nil if none is declared.func taskResultDefault(spec *v1.TaskSpec, resultName string) *v1.ResultValue {
    for _, r := range spec.Results {
        if r.Name == resultName {
            return r.Default // nil if not set
        }
    }
    return nil
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is resolved now 🤔

Comment thread pkg/reconciler/pipelinerun/resources/resultrefresolution.go
Comment on lines +239 to +246
if referencedPipelineTask.PipelineTask.IsMatrixed() {
// For a matrixed task that didn't run, wrap the default into array format.
var arrayVal v1.ParamValue
if taskResult.Default.Type == v1.ParamTypeArray {
arrayVal = *taskResult.Default
} else {
arrayVal = v1.ParamValue{Type: v1.ParamTypeArray, ArrayVal: []string{taskResult.Default.StringVal}}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use here the helper matrixedDefaultValue from my other comment and fix the behaviour for object params - again, it's probably blocked by validation, but safer to handle here as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using the matrixDefaultValue now from your other comment

Comment thread docs/tasks.md Outdated
@pritidesai
pritidesai force-pushed the tep-0048 branch 7 times, most recently from 279dffb to beafe5a Compare March 31, 2026 00:18
@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 13, 2026

@waveywaves waveywaves left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding to afrittoli's review with two additional observations:

  1. v1beta1 conversion gap: result_conversion.go does not convert the new Default field between v1 and v1beta1. A v1 Task with a default result, converted to v1beta1 and back, will silently lose the default. The v1beta1 TaskResult struct needs the Default field added, or the conversion must explicitly handle it.

  2. Missing 'produced overrides default' test: All test cases in TestApplyTaskResultsToPipelineResults_DefaultResults verify default-when-missing scenarios. The most critical invariant (actual produced result takes precedence over default) appears untested. Adding one test case where a task produces a result AND has a default would prove this works correctly.

Also needs rebase.

@pritidesai

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 20, 2026
@tekton-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please ask for approval from pritidesai after the PR has been reviewed.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 25, 2026
@vdemeester

Copy link
Copy Markdown
Member

@pritidesai it needs a rebase 🙏🏼

@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 18, 2026
@pritidesai

pritidesai commented Jun 19, 2026

Copy link
Copy Markdown
Member Author
  1. v1beta1 conversion gap: result_conversion.go does not convert the new Default field between v1 and v1beta1. A v1 Task with a default result, converted to v1beta1 and back, will silently lose the default. The v1beta1 TaskResult struct needs the Default field added, or the conversion must explicitly handle it.

Hi @waveywaves, v1beta1 TaskResult struct has the default filed defined:

https://github.com/tektoncd/pipeline/pull/9653/changes#diff-e76276785b79837e5a02d5e687fe27d2bb427c389cbdc348627561a1cb3d2a2f

along with the conversion:

https://github.com/tektoncd/pipeline/pull/9653/changes#diff-dbda3cea3080a20c617fc15ae003f5e460e6f6dad37b224fc5a670b224c791a8

Is there anything specific I might have missed?

@pritidesai

Copy link
Copy Markdown
Member Author
  1. Missing 'produced overrides default' test: All test cases in TestApplyTaskResultsToPipelineResults_DefaultResults verify default-when-missing scenarios. The most critical invariant (actual produced result takes precedence over default) appears untested. Adding one test case where a task produces a result AND has a default would prove this works correctly.

There is a test case which validates use of an actual result even with default defined:

https://github.com/tektoncd/pipeline/pull/9653/changes#diff-44c74890ca26c70492312151417116129a59f80678b4bacb4ffdf7a03a8628feR4844

Does this work or should we add some more tests?

@pritidesai

Copy link
Copy Markdown
Member Author

@afrittoli @vdemeester @waveywaves thank you for your input. I have addressed the feedback, and the PR is now ready for review 🙏

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for default Task results (TEP-0048) behind the enable-default-results alpha feature flag, allowing pipelines to resolve missing task results using declared defaults (including when tasks are skipped). It also introduces validation to fail TaskRuns that don’t emit non-defaulted declared results.

Changes:

  • Introduce default on Task result declarations (v1 + v1beta1) with API/schema/codegen/CRD updates and validation gated by enable-default-results.
  • Populate/use default result values across TaskRun reconciliation and PipelineRun result reference resolution (including skipped tasks and matrix cases).
  • Add docs + examples and extend unit/e2e plumbing to exercise alpha examples with the feature enabled.

Reviewed changes

Copilot reviewed 34 out of 38 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/e2e-tests.sh Adds env var + configmap patching to toggle enable-default-results for alpha example runs.
pkg/reconciler/taskrun/validate_taskrun.go Adds validation to ensure declared non-default results are produced (flag-gated).
pkg/reconciler/taskrun/validate_taskrun_test.go Unit tests for the new “missing non-default results” validation behavior.
pkg/reconciler/taskrun/taskrun.go Pre-populates default results during prepare and invokes results-produced validation during reconcile.
pkg/reconciler/taskrun/taskrun_test.go Controller test verifying default result pre-population behavior.
pkg/reconciler/pipelinerun/resources/resultrefresolution.go Uses declared defaults when resolving missing referenced results (incl. skipped tasks + matrix).
pkg/reconciler/pipelinerun/resources/resultrefresolution_test.go Adds tests covering result-ref resolution using default values.
pkg/reconciler/pipelinerun/resources/pipelinerunstate.go Stores EnableDefaultResults in facts; adds helper to extract task result defaults from resolved tasks.
pkg/reconciler/pipelinerun/resources/pipelinerunstate_test.go Tests GetTaskResultDefaults; updates GetChildReferences call signature.
pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go Threads enableDefaultResults through result-ref checks; resolves TaskSpec even when TaskRun absent.
pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go Adds finally-skip behavior tests when defaults exist + flag enabled.
pkg/reconciler/pipelinerun/resources/apply.go Enables PipelineRun result population from declared task result defaults (flag-gated).
pkg/reconciler/pipelinerun/resources/apply_test.go Updates callers for new signature and adds coverage for default-based pipeline results.
pkg/reconciler/pipelinerun/pipelinerun.go Wires feature flag into facts; passes defaults+ctx into pipeline results application and result-ref checks.
pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go DeepCopy support for new TaskResult.Default.
pkg/apis/pipeline/v1beta1/task_conversion_test.go Conversion test ensuring default round-trips between v1beta1 and v1.
pkg/apis/pipeline/v1beta1/swagger.json Swagger schema includes default for v1beta1 task results.
pkg/apis/pipeline/v1beta1/result_validation.go Adds validation for default (type + properties) and requires feature flag enabled.
pkg/apis/pipeline/v1beta1/result_types.go Adds Default field to v1beta1 TaskResult.
pkg/apis/pipeline/v1beta1/result_conversion.go Converts Default between v1beta1 and v1.
pkg/apis/pipeline/v1beta1/openapi_generated.go OpenAPI includes default for v1beta1 TaskResult.
pkg/apis/pipeline/v1/zz_generated.deepcopy.go DeepCopy support for new TaskResult.Default.
pkg/apis/pipeline/v1/swagger.json Swagger schema includes default for v1 task results.
pkg/apis/pipeline/v1/result_validation.go Adds validation for default (type + properties) and requires feature flag enabled.
pkg/apis/pipeline/v1/result_validation_test.go Unit tests for default validation (flag gating, type checks, object keys).
pkg/apis/pipeline/v1/result_types.go Adds Default field to v1 TaskResult.
pkg/apis/pipeline/v1/openapi_generated.go OpenAPI includes default for v1 TaskResult.
pkg/apis/config/feature_flags.go Introduces enable-default-results feature flag (alpha) and parses it into config.
examples/v1/taskruns/alpha/default-results.yaml New alpha TaskRun example demonstrating defaults for string/array/object results.
examples/v1/pipelineruns/beta/pipelinerun-with-matrix-context-variables.yaml Adjusts example logic to match expected matrix results behavior.
examples/v1/pipelineruns/alpha/pipelinerun-with-default-results.yaml New alpha PipelineRun example using defaults across tasks + finally (incl. skipped task).
examples/v1/pipelineruns/alpha/pipelinerun-emitting-default-results.yaml New alpha PipelineRun example showing pipeline results populated via task defaults.
docs/tasks.md Documents default result values and feature-flag gating under the Results section.
docs/pipeline-api.md API reference docs updated to include default on Task results (v1 + v1beta1).
config/config-feature-flags.yaml Adds enable-default-results entry to feature-flags ConfigMap template.
config/300-crds/300-taskrun.yaml CRD schema updates to include the new feature flag field and result default field.
config/300-crds/300-task.yaml CRD schema updates to include Task result default.
config/300-crds/300-pipelinerun.yaml CRD schema updates to include the new feature flag field.
Files not reviewed (4)
  • pkg/apis/pipeline/v1/openapi_generated.go: Generated file
  • pkg/apis/pipeline/v1/zz_generated.deepcopy.go: Generated file
  • pkg/apis/pipeline/v1beta1/openapi_generated.go: Generated file
  • pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/reconciler/taskrun/validate_taskrun.go
Comment thread pkg/apis/pipeline/v1/result_validation.go
Comment thread pkg/apis/pipeline/v1beta1/result_validation.go
Comment thread docs/tasks.md
Comment thread pkg/reconciler/pipelinerun/resources/pipelinerunstate_test.go
Comment thread pkg/reconciler/pipelinerun/resources/resultrefresolution_test.go
@pritidesai
pritidesai force-pushed the tep-0048 branch 2 times, most recently from a94df1e to b8836a6 Compare June 30, 2026 22:12
@pritidesai

Copy link
Copy Markdown
Member Author

@vdemeester I’ve addressed all of Copilot’s review comments. Are there any additional changes you think we should consider?

@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 9, 2026
This commit introduces default results, allowing task authors to specify a
default value for a result. If a task does not produce a value for that
result during execution, the specified default will be used. This ensures that
downstream tasks referencing that result can still resolve params consuming
the results, preventing unncessary failures in the pipeline.

With this change, if a task author does not define a default value and none of
the steps produce the corresponding result, the entire taskRun will be marked
as failed.

For more details, please refer to TEP-0048

Co-authored-by: Vinamra Jain <vinjain@redhat.com>

Assisted-by: Claude 4.6 Sonnet

Signed-off-by: Priti Desai <pdesai@us.ibm.com>
@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants