Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Implementation of conditionals #1093

Merged
merged 3 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/conditions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Conditions

This document defines `Conditions` and their capabilities.

*NOTE*: This feature is currently a WIP being tracked in [#1137](https://github.com/tektoncd/pipeline/issues/1137)
Copy link
Collaborator

Choose a reason for hiding this comment

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

🎉


---

- [Syntax](#syntax)
- [Check](#check)
- [Examples](#examples)

## Syntax

To define a configuration file for a `Condition` resource, you can specify the
following fields:

- Required:
- [`apiVersion`][kubernetes-overview] - Specifies the API version, for example
`tekton.dev/v1alpha1`.
- [`kind`][kubernetes-overview] - Specify the `Condition` resource object.
- [`metadata`][kubernetes-overview] - Specifies data to uniquely identify the
`Condition` resource object, for example a `name`.
- [`spec`][kubernetes-overview] - Specifies the configuration information for
your `Condition` resource object. In order for a `Condition` to do anything,
the spec must include:
- [`check`](#check) - Specifies a container that you want to run for evaluating the condition

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields

### Check

The `check` field is required. You define a single check to define the body of a `Condition`. The
check must specify a container image that adheres to the [container contract](./container-contract.md). The container image
runs till completion. The container must exit successfully i.e. with an exit code 0 for the
condition evaluation to be successful. All other exit codes are considered to be a condition check
failure.

## Examples

For complete examples, see
[the examples folder](https://github.com/tektoncd/pipeline/tree/master/examples).

---

Except as otherwise noted, the content of this page is licensed under the
[Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/),
and code samples are licensed under the
[Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0).
24 changes: 24 additions & 0 deletions docs/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ following fields:
- [`retries`](#retries) - Used when the task is wanted to be executed if
it fails. Could a network error or a missing dependency. It does not
apply to cancellations.
- [`conditions`](#conditions) - Used when a task is to be executed only if the specified
conditons are evaluated to be true.

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
Expand Down Expand Up @@ -285,6 +287,28 @@ In this example, the task "build-the-image" will be executed and if the first
run fails a second one would triggered. But, if that fails no more would
triggered: a max of two executions.


#### conditions

Sometimes you will need to run tasks only when some conditions are true. The `conditions` field
allows you to list a series of references to [`Conditions`](./conditions.md) that are run before the task
is run. If all of the conditions evaluate to true, the task is run. If any of the conditions are false,
the Task is not run. Its status.ConditionSucceeded is set to False with the reason set to `ConditionCheckFailed`.
However, unlike regular task failures, condition failures do not automatically fail the entire pipeline
run -- other tasks that are not dependent on the task (via `from` or `runAfter`) are still run.

```yaml
tasks:
- name: conditional-task
taskRef:
name: build-push
conditions:
- conditionRef: my-condition
```

In this example, `my-condition` refers to a [Condition](#conditions) custom resource. The `build-push`
task will only be executed if the condition evaluates to true.

## Ordering

The [Pipeline Tasks](#pipeline-tasks) in a `Pipeline` can be connected and run
Expand Down
68 changes: 68 additions & 0 deletions examples/pipelineruns/conditional-pipelinerun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
apiVersion: tekton.dev/v1alpha1
kind: Condition
metadata:
name: always-true
spec:
check:
image: alpine
command: ["/bin/sh"]
args: ['-c', 'exit 0']
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: pipeline-git
spec:
type: git
params:
- name: revision
value: master
- name: url
value: https://github.com/tektoncd/pipeline
---
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
name: list-files
spec:
inputs:
resources:
- name: workspace
type: git
steps:
- name: run-ls
image: ubuntu
command: ["/bin/bash"]
args: ['-c', 'ls -al ${inputs.resources.workspace.path}']
---
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: list-files-pipeline
spec:
resources:
- name: source-repo
type: git
tasks:
- name: list-files-1
taskRef:
name: list-files
conditions:
- conditionRef: "always-true"
dibyom marked this conversation as resolved.
Show resolved Hide resolved
resources:
inputs:
- name: workspace
resource: source-repo
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
name: demo-condtional-pr
spec:
pipelineRef:
name: list-files-pipeline
serviceAccount: 'default'
resources:
- name: source-repo
resourceRef:
name: pipeline-git
25 changes: 19 additions & 6 deletions pkg/apis/pipeline/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,25 @@ limitations under the License.

package pipeline

// GroupName is the Kubernetes resource group name for Pipeline types.
const (
GroupName = "tekton.dev"
TaskLabelKey = "/task"
TaskRunLabelKey = "/taskRun"
PipelineLabelKey = "/pipeline"
PipelineRunLabelKey = "/pipelineRun"
// GroupName is the Kubernetes resource group name for Pipeline types.
GroupName = "tekton.dev"

// TaskLabelKey is used as the label identifier for a task
TaskLabelKey = "/task"

// TaskRunLabelKey is used as the label identifier for a TaskRun
TaskRunLabelKey = "/taskRun"

// PipelineLabelKey is used as the label identifier for a Pipeline
PipelineLabelKey = "/pipeline"

// PipelineRunLabelKey is used as the label identifier for a PipelineRun
PipelineRunLabelKey = "/pipelineRun"

// PipelineRunLabelKey is used as the label identifier for a PipelineTask
PipelineTaskLabelKey = "/pipelineTask"

// ConditionCheck is used as the label identifier for a ConditionCheck
Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks for adding these!!

ConditionCheckKey = "/conditionCheck"
)
10 changes: 10 additions & 0 deletions pkg/apis/pipeline/v1alpha1/condition_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,13 @@ func NewConditionCheck(tr *TaskRun) *ConditionCheck {
cc := ConditionCheck(*tr)
return &cc
}

// IsDone returns true if the ConditionCheck's status indicates that it is done.
func (cc *ConditionCheck) IsDone() bool {
return !cc.Status.GetCondition(apis.ConditionSucceeded).IsUnknown()
}

// IsSuccessful returns true if the ConditionCheck's status indicates that it is done.
func (cc *ConditionCheck) IsSuccessful() bool {
return cc.Status.GetCondition(apis.ConditionSucceeded).IsTrue()
}
55 changes: 55 additions & 0 deletions pkg/apis/pipeline/v1alpha1/condition_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
Copyright 2019 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1_test

import (
"testing"

corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/apis"

"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
tb "github.com/tektoncd/pipeline/test/builder"
)

func TestConditionCheck_IsDone(t *testing.T) {
tr := tb.TaskRun("", "", tb.TaskRunStatus(tb.StatusCondition(
apis.Condition{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
},
)))

cc := v1alpha1.ConditionCheck(*tr)
if !cc.IsDone() {
t.Fatal("Expected conditionCheck status to be done")
}
}

func TestConditionCheck_IsSuccessful(t *testing.T) {
tr := tb.TaskRun("", "", tb.TaskRunStatus(tb.StatusCondition(
apis.Condition{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionTrue,
},
)))

cc := v1alpha1.ConditionCheck(*tr)
if !cc.IsSuccessful() {
t.Fatal("Expected conditionCheck status to be done")
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice :D

3 changes: 3 additions & 0 deletions pkg/reconciler/v1alpha1/pipelinerun/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

pipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client"
clustertaskinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/clustertask"
conditioninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/condition"
pipelineinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/pipeline"
resourceinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/pipelineresource"
pipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/pipelinerun"
Expand Down Expand Up @@ -54,6 +55,7 @@ func NewController(
pipelineRunInformer := pipelineruninformer.Get(ctx)
pipelineInformer := pipelineinformer.Get(ctx)
resourceInformer := resourceinformer.Get(ctx)
conditionInformer := conditioninformer.Get(ctx)
timeoutHandler := reconciler.NewTimeoutHandler(ctx.Done(), logger)

opt := reconciler.Options{
Expand All @@ -72,6 +74,7 @@ func NewController(
clusterTaskLister: clusterTaskInformer.Lister(),
taskRunLister: taskRunInformer.Lister(),
resourceLister: resourceInformer.Lister(),
conditionLister: conditionInformer.Lister(),
timeoutHandler: timeoutHandler,
}
impl := controller.NewImpl(c, c.Logger, pipelineRunControllerName)
Expand Down