Skip to content

Latest commit

 

History

History
973 lines (893 loc) · 38.8 KB

0007-conditions-beta.md

File metadata and controls

973 lines (893 loc) · 38.8 KB
title authors creation-date last-updated status
Conditions Beta
@jerop
2020-07-22
2021-06-03
implemented

TEP-0007: Conditions Beta

Original Design Doc in Google Docs, visible to members of tekton-dev@: https://docs.google.com/document/d/1kESrgmFHnirKNS4oDq3mucuB_OycBm6dSCSwRUHccZg/edit?usp=sharing

Summary

Conditions is a CRD used to specify a criteria to determine whether or not a Task executes. When other Tekton resources were migrated to beta, it remained in alpha because it was missing features needed by users.

After analyzing the feature requests and discussing with users, we have identified that the most critical gaps in Conditions are simplicity, efficiency, skipping and status. We want to address these gaps so that it can work well with the other Pipeline resources and users can count on its stability.

We will refer to Conditions as Guards because they determine if a Task executes, not if/else as would be expected from a Condition; more details on Guards vs Conditions naming can be found in this issue.

We propose:

  • For simplicity, we propose deprecating the separate Conditions CRD and using Tasks to produce the Results needed to evaluate whether a dependent Task executes.
  • For efficiency, we propose using string expressions through When Expressions to perform simple checks without spinning up new Pods; they can operate on previous Task's Results, Parameters, among other Tekton resources.
  • By deprecating Conditions CRD and using When Expressions, we can distinguish failed status from evaluating to False.

We address skipping separately in TEP-0059: Skipping Strategies.

Background

Conditions

Conditions is a custom resource that enables users to specify a criteria to determine whether or not a Task executes. Its critical component is the Check, which specifies a Step, which is a Container that evaluates a Condition. If the container runs and exits with code 0, the Condition evaluates as True, otherwise it evaluates as False.

With this design, users provide an image and Tekton runs it in a Pod to check the Condition, thus giving users flexibility to use whichever language. Conditions actually manifest themselves as TaskRuns that are handled differently from other TaskRuns. For example, when a Condition evaluates as False, the TaskRun from the Condition fails but it does not cause the whole Pipeline to fail, unlike the other TaskRuns.

Users can specify Conditions and reference them in Tasks and Pipelines as such:

apiVersion: tekton.dev/v1alpha1
kind: Condition
metadata:
  name: file-exists
spec:
  params:
    - name: 'path'
  resources:
    - name: workspace
      type: git
  check:
    image: alpine
    script: 'test -f $(resources.workspace.path)/$(params.path)'
---
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: conditional-pipeline
spec:
  resources:
    - name: source-repo
      type: git
  params:
    - name: path
      default: 'README.md'
  tasks:
    - name: first-create-file
      taskRef:
        name: create-readme-file
      resources:
        outputs:
          - name: workspace
            resource: source-repo
    - name: then-check
      conditions:
        - conditionRef: file-exists
          params:
            - name: path
              value: '$(params.path)'
          resources:
            - name: workspace
              resource: source-repo
              from: [first-create-file]
      taskRef:
        name: echo-file-exists

For further information on Conditions, read the documentation, view examples and review its uses in Tekton plumbing.

Use Cases

  • Checking if the name of a git branch matches
  • Checking if the Result of a previous Task is as expected
  • Checking if a git file has changed in the previous commits
  • Checking if an image exists in the registry
  • Checking if the name of a CI job matches

Related Work

  • Argo: Workflows support conditional execution using a when property to specify whether to run or skip a Step (example).
  • Concourse: Jobs specify the Steps to execute when the Job succeeds, fails, errors or aborts; but it has no built-in conditionals construct to determine if a Job should execute.
  • Jenkins: Uses Conditional BuildStep Plugin enables Conditions which are defined by Run Condition, which has some built-in conditions, e.g. always, never, and file exists/match.
  • Drone : Supports Pipeline Conditions for including/excluding git branches, and Step Conditions which uses the when syntax. Documentation.
  • Spinnaker: Uses string expressions, Stages only run when expressions evaluate to True.

Motivation

Tekton users have made many feature requests for Conditions that have been documented in this experience report. We have categorized the challenges that users experience when using Conditions into the specific focus areas of simplicity, efficiency and skipping which we will address in this proposal.

Simplicity

Conditions actually manifest themselves as Tasks but are implemented as a separate CRD which makes them complex. Maintaining the separate Condition CRD takes extra and unnecessary effort, given that it's really a Task underneath. We prefer to reuse existing components when possible.

Efficiency

Checking Conditions is slow and expensive because it spins up new Pods to evaluate each Condition. For example, Tekton dogfooding has been heavily using Conditions to decide what to run e.g only run this branch if it contains a specific type of file. These small checks add up such that many pods are used to check Conditions and it becomes slow and expensive. Even worse, we don't have a conditional branching construct (if/else or switch), so users have to implement and execute opposite Conditions which makes it even slower and more expensive. This can also be a problem in terms of the resource limits, requests, quotas and LimitRanges.

Skipping

When a Condition fails, the guarded Task and its branch (dependent Tasks) are skipped. A Task is dependent on and in the branch of another Task as specified by ordering using runAfter or by resources using Results, Workspaces and Resources. In some use cases of Conditions, when a Condition evaluates to False, users need to skip the guarded Task only and allow dependent Tasks to execute. An example use case is when there’s a particular Task that a Pipeline wants to execute when the git branch is dev/staging/qa, but not when it’s the main/master/prod branch. Another use case is when a user wants to send out a notification whether or not a parent guarded Task was executed, as described in this issue.

Status

It is currently difficult to distinguish between a Task that was skipped due to Condition evaluating as False and a Task that failed. This is because we use exit codes in Check as described in Conditions section above and reuse ConditionSucceeded from Knative which can have the following states: True, False or Unknown. When a Task either fails or is skipped from Condition evaluating to False, we mark ConditionSucceeded as False.

Requirements

  1. Users need a way to specify logic - Guards - to determine if a Task should execute or not.
  2. Users need a way to specify whether to execute dependent Tasks when Guards of a parent Task evaluate to False.
  3. Users should be able to specify multiple Guards for a given Task.
  4. Users should be able to use Outputs from parent Tasks and static input to specify Guards.
  5. Users should be able to distinguish between a Guard failing (such as when missing resources) and a Guard evaluating to False.

Proposal

We propose:

  • For simplicity, we propose deprecating the separate Conditions CRD and using Tasks to produce the Results needed to evaluate whether a dependent Task executes.
  • For efficiency, we propose using string expressions through When Expressions to perform simple checks without spinning up new Pods; they can operate on previous Task's Results, Parameters, among other Tekton resources.
  • By deprecating Conditions CRD and using When Expressions, we can distinguish failed status from evaluating to False.

We address skipping separately in TEP-0059: Skipping Strategies.

Simplicity

As discussed in the background section, Conditions manifest themselves as Tasks. We want to keep Tekton as simple as possible by reusing existing components. So we propose phasing out the separate Conditions CRD and eventually deprecating it. In place of Conditions, we propose using Tasks produce to Results that we can use to specify Guards using When Expressions in subsequent Tasks, as described in Efficiency section below. Thus, we won’t have Conditions to migrate to beta and won’t have to maintain the separate Conditions CRD.

In the example of checking whether a file exists, the Task that would replace the Condition would be specified as such:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: file-exists
spec:
  params:
    - name: path
  workspaces:
    - name: source
  results:
    - name: exists
      description: boolean indicating whether the file exists
  steps:
  - name: check-file-exists
    image: alpine
    script: |
      if [ -f $(workspaces.source.path)/$(params.path) ]; then
        echo true | tee /tekton/results/exists
      else
        echo false | tee /tekton/results/exists
      fi

Efficiency

To improve the efficiency of guarded execution of Tasks, we need to avoid spinning up new Pods to check Guards. We can use string expressions for Guard checking, but we want to avoid adding an opinionated and complex expression language to the Tekton API to ensure Tekton can be supported by as many systems as possible.

We propose using a simple expression syntax When Expressions (similar to Kubernetes' Match Expressions) to evaluate Guards efficiently. The components of When Expressions are Input, Operator and Values:

  • Input is the input for the Guard checking which can be static inputs or outputs from parent Tasks, such as Parameters or Results.
  • Values is an array of string values. The Values array must be non-empty. It can contain static values or variables (such as Parameters).
  • Operator represents an Input's relationship to a set of Values. Operators we will use in Guards are In and NotIn.

When we have more than one Guard, the guarded Task will be executed when all the Guards evaluate to True. Note that when a Guard uses a resource from another Task, such as a Result, it introduces an implicit resource dependency that makes the guarded Task dependent on the resource-producing Task.

Here's how a user can specify a Guard that executes on that Result:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: file-exists
spec:
  params:
    - name: path
  workspaces:
    - name: source
  results:
    - name: exists
      description: boolean indicating whether the file exists
  steps:
  - name: check-file-exists
    image: alpine
    script: |
      if [ -f $(workspaces.source.path)/$(params.path) ]; then
        echo true | tee /tekton/results/exists
      else
        echo false | tee /tekton/results/exists
      fi
---
api: tekton.dev/v1beta1
kind: Pipeline
metadata:
    name: generate-file
spec:
  workspaces:
    - name: source-repo
  params:
    - name: path
      default: 'README.md'
  tasks:
    - name: create-file
      taskRef:
        name: create-readme-file
      workspaces:
        - name: source
          workspace: source-repo
    - name: file-exists
      taskRef:
        name: file-exists
      workspaces:
        - name: source
          workspace: source-repo
    - name: echo-file-exists
      when:
        - input: '$(tasks.file-exists.results.exists)'
          operator: In
          values: ['true']
      taskRef:
        name: echo-file-exists

Other examples of Guards using When Expressions are:

input: $(params.branch)
operator: In
values: [‘main’]
---
input: $(params.branch)
operator: NotIn
values: [‘main’]
---
input: ‘false’
operator: In
values: [‘’]

We can explore adding more Operators later if needed, such as IsTrue, IsFalse, IsEmpty and IsNotEmpty. Kubernetes' Match Expressions uses a comma separator as an AND operator but it won't be supported in Tekton's When Expressions (can be revisted later).

Status

Add Skipped Tasks section to the PipelineRunStatus that contains a list of SkippedTasks that contains a Name field which has the PipelineTaskName and a When Expressions field which has a list of the resolved WhenExpressions. Thus, users can know why a particular Task was skipped. In addition, TaskRuns from guarded Tasks that execute because their WhenExpressions evaluate to true would have the resolved WhenExpressions included in the TaskRun status.

In this example, the WhenExpressions in skip-this-task evaluate to False while the WhenExpressions in run-this-task evaluate to True:

Status:
  Completion Time:  2020-08-27T15:07:34Z
  Conditions:
    Last Transition Time:  2020-08-27T15:07:34Z
    Message:               Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1
    Reason:                Completed
    Status:                True
    Type:                  Succeeded
  Pipeline Spec:
    Params:
      Name: param
      Type: string
      Default: foo
    Tasks:
      Name:  skip-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Night!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          bar
        Input:     $(params.param)
        Operator:  notin
        Values:
          $(params.param)
      Name:  run-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Morning!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          $(params.param)
  Skipped Tasks:
    Name: skip-this-task
    When Expressions:
      Input:     foo
      Operator:  in
      Values:
        bar
      Input:     foo
      Operator:  notin
      Values:
        foo
  Start Time:   2020-08-27T15:07:30Z
  Task Runs:
    pipelinerun-to-skip-task-run-this-task-r2djj:
      Pipeline Task Name:  run-this-task
      Status:
        Completion Time:  2020-08-27T15:07:34Z
        Conditions:
          Last Transition Time:  2020-08-27T15:07:34Z
          Message:               All Steps have completed executing
          Reason:                Succeeded
          Status:                True
          Type:                  Succeeded
        Pod Name:                pipelinerun-to-skip-task-run-this-task-r2djj-pod
        Start Time:              2020-08-27T15:07:30Z
        Steps:
          Container:  step-echo
          Image ID:   docker-pullable://ubuntu@sha256:6f2fb2f9fb5582f8b5
          Name:       echo
          Terminated:
            Container ID:  docker://df348b8f64165fd15e3301095510
            Exit Code:     0
            Finished At:   2020-08-27T15:07:33Z
            Reason:        Completed
            Started At:    2020-08-27T15:07:33Z
        Task Spec:
          Steps:
            Image:  ubuntu
            Name:   echo
            Resources:
            Script:  echo "Good Morning!"
      When Expressions:
          Input:     foo
          Operator:  in
          Values:
            foo
Events:
  Type    Reason     Age    From         Message
  ----    ------     ----   ----         -------
  Normal  Started    2m29s  PipelineRun  
  Normal  Running    2m29s  PipelineRun  Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 1
  Normal  Succeeded  2m25s  PipelineRun  Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1

Examples

These are examples of how the Conditions in Tekton dogfooding and their usage would be translated and used in the new design:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: check-git-files-changed
  namespace: tektonci
  annotations:
    description: |
      Succeeds if any of the files changed in the last N commits from the
      revision defined in the git resource matches the regular expression
spec:
  params:
    - name: gitCloneDepth
      description: Number of commits + 1
    - name: regex
      description: Regular expression to match files changed
  resources:
    - name: source
      type: git
  results:
    - name: changed
      description: Boolean that indicates whether a file changed
  steps:
    - name: check-git-files-changed
      image: alpine/git
      script: |
        #!/bin/sh
        set -ex
        BACK="HEAD~$(( $(params.gitCloneDepth) - 1 ))"
        cd $(resources.source.path)
        if [ -z git diff-tree --no-commit-id --name-only -r HEAD $BACK | grep -E '$(params.regex)' ]; then
          echo false | tee /tekton/results/changed
        else
          echo true | tee /tekton/results/changed
        fi
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: tekton-noop-check
  namespace: tektonci
spec:
  params:
    - name: passorfail
      description: Should the CI Job 'pass' or 'fail'
    - name: message
      description: Message to be logged in the CI Job
    - name: gitCloneDepth
      description: Number of commits in the change + 1
    - name: fileFilterRegex
      description: Names regex to be matched in the list of modified files
    - name: checkName
      description: The name of the GitHub check that this pipeline is used for
    - name: gitHubCommand
      description: The command that was used to trigger testing
  resources:
    - name: source
      type: git
  tasks:
    - name: check-git-files-changed
      params:
        - name: gitCloneDepth
          value: $(params.gitCloneDepth)
        - name: regex
          value: $(params.fileFilterRegex)
      resources:
        - name: source
          resource: source
      taskRef:
        - name: check-git-files-changed
    - name: check-name-matches
      params:
        - name: gitHubCommand
          value: $(params.gitHubCommand)
        - name: checkName
          value: $(params.checkName)
      resources:
        - name: source
          resource: source
      taskRef:
        - name: check-git-files-changed
    - name: ci-job
      when:
      - input: "$(tasks.check-git-files-changed.results.changed)"
        key: In
        values: ["true"]
      - input: "$(params.githubCommand)"
        key: In
        values: ["", "/test $(params.checkName)"]
      taskRef:
        name: tekton-noop
      params:
        - name: message
          value: $(params.message)
        - name: passorfail
          value: $(params.passorfail)
      resources:
        inputs:
          - name: source
            resource: source

Risks and Mitigations

The When Expressions providing In and NotIn Operators may not cover some edge use cases of Guards, however the design will be flexible to support other Operators. Moreover, this design allows for exploring using CEL through CustomTasks.

Test Plan

  • Provide unit tests and e2e tests for When Expressions with varied Inputs and Values.
  • Provide unit tests and e2e tests for whenSkipped with varied Task branches.

Alternatives

Simplicity

Tasks that produce Skip Result

As discussed in the background section, Conditions manifest themselves as Tasks. We can phase out the separate Conditions CRD and eventually deprecate it. In place of Conditions, we can use Tasks produce a Result called Skip with string values True or False -- to indicate whether the Task it’s guarding will be executed or not. When a user provides another value, the Task will evaluate it as an error. Thus, we won’t have Conditions to migrate to beta and won’t have to maintain the separate Conditions CRD. Moreover, the features supported by Tasks become readily available to be used for guarded execution of Tasks. Using Results allows us to distinguish between when a Task fails and when the Task used as a Guard evaluates to False.

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: file-exists
spec:
  parameters:
    - name: path
  resources:
    - name: workspace
      type: git
  results:
    - name: skip
      description: boolean indicating whether guarded Task should be skipped
  steps:
  - name: check-file-exists
    image: alpine
    script: |
      if [ -f $(resources.workspace.path)/$(params.path) ]; then
        echo true | tee /tekton/results/skip
      else
        echo false | tee /tekton/results/skip
      fi
---
api: tekton.dev/v1beta1
kind: Pipeline
metadata:
    name: generate-file
spec:
  workspaces:
    - name: source-repo
  params:
    - name: path
      default: 'README.md'
  tasks:
    - name: create-file
      taskRef:
        name: create-readme-file
      workspaces:
        - name: source
          workspace: source-repo
    - name: echo-file-exists
      when:
        - name: check-file-exists
          taskRef:
            - name: file-exists
          workspaces:
            - name: source
              workspace: source-repo
      taskRef:
        name: echo-file-exists

Initially, while still supporting Conditions, we can use Tasks used as Guards. Users can use either the Conditions list or Guards list, but not both of them. Over time, we will phase out the Conditions and support Guards only.

Efficiency

CelRun Custom Task

If guarded execution of Tasks is implemented using Tasks that produce Skip Result, we can then extend it to use CustomTasks to build and experiment with using string expressions for simple Guards. In Triggers, we use Common Expression Language for filtering using a CEL interceptor. We can provide a CelRun CustomTask, so that we experiment with CEL without putting it into the Tekton API. After experimentation with CelRun CustomTask for a while, we will revisit whether we want to add it to the Tekton API.

An example using a CelRun can be specified as shown below:

api: tekton.dev/v1beta1
kind: Pipeline
metadata:
    name: generate-file
spec:
  workspaces:
    - name: source-repo
  params:
    - name: path
      default: 'README.md'
    - name: branch
      default: 'main'
  tasks:
    - name: create-file
      taskRef:
        name: create-readme-file
      workspaces:
        - name: source
          workspace: source-repo
    - name: echo-file-exists
      when:
        - name: check-file-exists
          taskRef:
            - name: file-exists
          workspaces:
            - name: source
              workspace: source-repo
        - name: branch-is-main
          taskSpec:
            apiVersion: custom.dev/v1beta1
            kind: CelRun
            spec:
                eval: '$(params.branch)' == ‘main’
      taskRef:
        name: echo-file-exists

When the Pipeline executes, it’ll create a CelRun object, and we’ll provide a controller to interpret and execute the CelRun. We can also experiment with using other languages, like bash, scriptmode, jsonpath. If we pursue this later, we'll write a separate TEP.

Expression Language Interceptor

In Triggers, we use CEL for filtering to avoid spinning up a new pod. Similarly, we can choose a particular expression language - Common Expression Language - and use it to evaluate simple Guards efficiently in the controller.

api: tekton.dev/v1beta1
kind: Pipeline
metadata:
    name: generate-file
spec:
  workspaces:
    - name: source-repo
  params:
    - name: path
      default: 'README.md'
    - name: branch
      default: 'main'
  tasks:
    - name: create-file
      taskRef:
        name: create-readme-file
      workspaces:
        - name: source
          workspace: source-repo
    - name: echo-file-exists
      when:
        - name: check-file-exists
          taskRef:
            - name: file-exists
          workspaces:
            - name: source
              workspace: source-repo
        - name: branch-is-main
          eval: '$(params.branch)' == ‘main’
      taskRef:
        name: echo-file-exists

To make it flexible, similarly to Triggers which uses language interceptors that's pluggable, we can provide a CEL interceptor out of the box and, if needed, users can add or bring their own interceptors to use other languages.

Status

Minimal Skipped

Add Skipped Tasks section to the PipelineRunStatus that contains a list of SkippedTasks that contains a Name field which has the PipelineTaskName. The WhenExpressions that made the Task skipped can be found in the PipelineSpec, the Parameter variables used can be found in the PipelineSpec and the Results used from previous Tasks can be found in the relevant TaskRun. It may be more work for users to reverse-engineer to identify why a Task was skipped, but gives us the benefit of significantly reducing the PipelineRunStatus compared to what we currently have with Conditions.

In this example, the WhenExpressions in skip-this-task evaluate to False while the WhenExpressions in run-this-task evaluate to True:

Status:
  Completion Time:  2020-08-27T15:07:34Z
  Conditions:
    Last Transition Time:  2020-08-27T15:07:34Z
    Message:               Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1
    Reason:                Completed
    Status:                True
    Type:                  Succeeded
  Pipeline Spec:
    Params:
      Name: param
      Type: string
      Default: foo
    Tasks:
      Name:  skip-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Night!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          bar
        Input:     $(params.param)
        Operator:  notin
        Values:
          $(params.param)
      Name:  run-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Morning!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          $(params.param)
  Skipped Tasks:
    Name: skip-this-task
  Start Time:   2020-08-27T15:07:30Z
  Task Runs:
    pipelinerun-to-skip-task-run-this-task-r2djj:
      Pipeline Task Name:  run-this-task
      Status:
        Completion Time:  2020-08-27T15:07:34Z
        Conditions:
          Last Transition Time:  2020-08-27T15:07:34Z
          Message:               All Steps have completed executing
          Reason:                Succeeded
          Status:                True
          Type:                  Succeeded
        Pod Name:                pipelinerun-to-skip-task-run-this-task-r2djj-pod
        Start Time:              2020-08-27T15:07:30Z
        Steps:
          Container:  step-echo
          Image ID:   docker-pullable://ubuntu@sha256:6f2fb2f9fb5582f8b5
          Name:       echo
          Terminated:
            Container ID:  docker://df348b8f64165fd15e3301095510
            Exit Code:     0
            Finished At:   2020-08-27T15:07:33Z
            Reason:        Completed
            Started At:    2020-08-27T15:07:33Z
        Task Spec:
          Steps:
            Image:  ubuntu
            Name:   echo
            Resources:
            Script:  echo "Good Morning!"
Events:
  Type    Reason     Age    From         Message
  ----    ------     ----   ----         -------
  Normal  Started    2m29s  PipelineRun  
  Normal  Running    2m29s  PipelineRun  Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 1
  Normal  Succeeded  2m25s  PipelineRun  Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1

ConditionSucceeded

For skipped Tasks, create a TaskRun object with ConditionType ConditionSucceeded with status ConditionTrue and reason Skipped because it has successfully skipped the Task based on the WhenExpressions. The message would have further detail that the Task was skipped because WhenExpressions were evaluated to False. However, it might be confusing that we create a TaskRun object to record status for a Task that was skipped and it also creates a larger PipelineRunStatus than using Skipped Tasks section.

Status:
  Completion Time:  2020-08-27T15:07:34Z
  Conditions:
    Last Transition Time:  2020-08-27T15:07:34Z
    Message:               Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1
    Reason:                Completed
    Status:                True
    Type:                  Succeeded
  Pipeline Spec:
    Params:
      Name: param
      Type: string
      Default: foo
    Tasks:
      Name:  skip-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Night!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          bar
        Input:     $(params.param)
        Operator:  notin
        Values:
          $(params.param)
      Name:  run-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Morning!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          $(params.param)
  Start Time:   2020-08-27T15:07:30Z
  Task Runs:
    pipelinerun-to-skip-task-run-this-task-r2djj:
      Pipeline Task Name:  run-this-task
      Status:
        Completion Time:  2020-08-27T15:07:34Z
        Conditions:
          Last Transition Time:  2020-08-27T15:07:34Z
          Message:               All Steps have completed executing
          Reason:                Succeeded
          Status:                True
          Type:                  Succeeded
        Pod Name:                pipelinerun-to-skip-task-run-this-task-r2djj-pod
        Start Time:              2020-08-27T15:07:30Z
        Steps:
          Container:  step-echo
          Image ID:   docker-pullable://ubuntu@sha256:6f2fb2f9fb5582f8b5
          Name:       echo
          Terminated:
            Container ID:  docker://df348b8f64165fd15e3301095510
            Exit Code:     0
            Finished At:   2020-08-27T15:07:33Z
            Reason:        Completed
            Started At:    2020-08-27T15:07:33Z
        Task Spec:
          Steps:
            Image:  ubuntu
            Name:   echo
            Resources:
            Script:  echo "Good Morning!"
      When Expressions:
          Input:     foo
          Operator:  in
          Values:
            foo
    pipelinerun-to-skip-task-skip-this-task-r2djj:
      Pipeline Task Name:  skip-this-task
      Status:
        Conditions:
          Message:               WhenExpressions for pipeline task skip-this-task evaluated to false and was skipped 
          Reason:                Skipped
          Status:                True
          Type:                  Succeeded
      When Expressions:
        Input:     foo
        Operator:  in
        Values:
          bar
        Input:     foo
        Operator:  notin
        Values:
          foo
Events:
  Type    Reason     Age    From         Message
  ----    ------     ----   ----         -------
  Normal  Started    2m29s  PipelineRun  
  Normal  Running    2m29s  PipelineRun  Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 1
  Normal  Succeeded  2m25s  PipelineRun  Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1

ConditionSkipped

Add a new ConditionType called ConditionSkipped. For skipped Tasks, create a TaskRun object with ConditionType ConditionSkipped with status ConditionTrue and reason WhenExpressionsEvaluatedToFalse. However, it might be confusing that we create a TaskRun object to record status for a Task that was skipped and it also creates a larger PipelineRunStatus than using Skipped Tasks section.

Status:
  Completion Time:  2020-08-27T15:07:34Z
  Conditions:
    Last Transition Time:  2020-08-27T15:07:34Z
    Message:               Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1
    Reason:                Completed
    Status:                True
    Type:                  Succeeded
  Pipeline Spec:
    Params:
      Name: param
      Type: string
      Default: foo
    Tasks:
      Name:  skip-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Night!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          bar
        Input:     $(params.param)
        Operator:  notin
        Values:
          $(params.param)
      Name:  run-this-task
      Task Spec:
        Metadata:
        Steps:
          Image:  ubuntu
          Name:   echo
          Resources:
          Script:  echo "Good Morning!"
      When:
        Input:     $(params.param)
        Operator:  in
        Values:
          $(params.param)
  Start Time:   2020-08-27T15:07:30Z
  Task Runs:
    pipelinerun-to-skip-task-run-this-task-r2djj:
      Pipeline Task Name:  run-this-task
      Status:
        Completion Time:  2020-08-27T15:07:34Z
        Conditions:
          Last Transition Time:  2020-08-27T15:07:34Z
          Message:               All Steps have completed executing
          Reason:                Succeeded
          Status:                True
          Type:                  Succeeded
        Pod Name:                pipelinerun-to-skip-task-run-this-task-r2djj-pod
        Start Time:              2020-08-27T15:07:30Z
        Steps:
          Container:  step-echo
          Image ID:   docker-pullable://ubuntu@sha256:6f2fb2f9fb5582f8b5
          Name:       echo
          Terminated:
            Container ID:  docker://df348b8f64165fd15e3301095510
            Exit Code:     0
            Finished At:   2020-08-27T15:07:33Z
            Reason:        Completed
            Started At:    2020-08-27T15:07:33Z
        Task Spec:
          Steps:
            Image:  ubuntu
            Name:   echo
            Resources:
            Script:  echo "Good Morning!"
      When Expressions:
          Input:     foo
          Operator:  in
          Values:
            foo
    pipelinerun-to-skip-task-skip-this-task-r2djj:
      Pipeline Task Name:  skip-this-task
      Status:
        Conditions:
          Message:               WhenExpressions for pipeline task skip-this-task evaluated to false and was skipped 
          Reason:                WhenExpressionsEvaluatedToFalse
          Status:                True
          Type:                  Skipped
      When Expressions:
        Input:     foo
        Operator:  in
        Values:
          bar
        Input:     foo
        Operator:  notin
        Values:
          foo
Events:
  Type    Reason     Age    From         Message
  ----    ------     ----   ----         -------
  Normal  Started    2m29s  PipelineRun  
  Normal  Running    2m29s  PipelineRun  Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 1
  Normal  Succeeded  2m25s  PipelineRun  Tasks Completed: 1 (Failed: 0, Cancelled 0), Skipped: 1

Upgrade & Migration Strategy

  • We will implement the design while still supporting the Conditions CRD.
  • We will gather user feedback and use it to inform phasing out Conditions CRD.
  • In addition, we will add common examples in the Catalog to help users migrate easily.