Skip to content

Commit

Permalink
Adding support to enable pipelineSpec and resourceSpec
Browse files Browse the repository at this point in the history
Its now possible to embed the whole pipeline specification into Pipeline Run
using pipelineSpec, for example:

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: pipelinerun-echo-greetings
spec:
  pipelineRef:
    name: pipeline-echo-greetings

Can be specified as:

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: pipelinerun-echo-greetings
spec:
  pipelineSpec:
    tasks:
    - name: echo-good-morning
    ...
    params:
    ...

Also, resourceSpec can be embeded into PipelineRun, for example:

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: pipelinerun-echo-greetings
spec:
  resources:
    - name: git-repo
        resourceRef:
          name: my-git-repo

Can be specified as:

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
  name: pipelinerun-echo-greetings
spec:
  resources:
    - name: git-repo
      resourceSpec:
        type: git
        params:
          - name: url
            value: https://github.com/myrepo/myrepo.git
  • Loading branch information
pritidesai committed Sep 18, 2019
1 parent 454ddec commit 929a705
Show file tree
Hide file tree
Showing 19 changed files with 640 additions and 91 deletions.
130 changes: 127 additions & 3 deletions docs/pipelineruns.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ following fields:
`PipelineRun` resource object, for example a `name`.
- [`spec`][kubernetes-overview] - Specifies the configuration information for
your `PipelineRun` resource object.
- `pipelineRef` - Specifies the [`Pipeline`](pipelines.md) you want to run.
- [`pipelineRef` or `pipelineSpec`](#specifiying-a-pipeline) - Specifies the [`Pipeline`](pipelines.md) you want to run.
- Optional:

- [`resources`](#resources) - Specifies which
Expand All @@ -55,6 +55,103 @@ following fields:
[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields

### Specifying a pipeline

Since a `PipelineRun` is an invocation of a [`Pipeline`](pipelines.md), you must sepcify
what `Pipeline` to invoke.

You can do this by providing a reference to an existing `Pipeline`:

```yaml
spec:
pipelineRef:
name: myPipeline

```

Or you can embed the spec of the `Pipeline` directly in the `PipelineRun`:

```yaml
spec:
pipelineSpec:
tasks:
- name: task1
taskRef:
name: myTask
```
A sample `PipelineRun` to display greetings while embedding the spec of the `Pipeline` directly in the `PipelineRun`:

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
name: task-echo-message
spec:
inputs:
params:
- name: MESSAGE
type: string
default: "Hello World"
steps:
- name: echo
image: ubuntu
command:
- echo
args:
- "$(inputs.params.MESSAGE)"
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
name: pipelinerun-echo-greetings
spec:
pipelineSpec:
params:
- name: MORNING_GREETINGS
description: "morning greetings, default is Good Morning!"
type: string
default: "Good Morning!"
- name: NIGHT_GREETINGS
description: "Night greetings, default is Good Night!"
type: string
default: "Good Night!"
tasks:
# Task to display morning greetings
- name: echo-good-morning
taskRef:
name: task-echo-message
params:
- name: MESSAGE
value: $(params.MORNING_GREETINGS)
# Task to display night greetings
- name: echo-good-night
taskRef:
name: task-echo-message
params:
- name: MESSAGE
value: $(params.NIGHT_GREETINGS)
params:
- name: MORNING_GREETINGS
value: "Good Morning, Bob!"
- name: NIGHT_GREETINGS
value: "Good Night, Bob!"
```

Logs from a pod displaying morning greetings:

```bash
kubectl logs $(kubectl get pods -o name | grep pipelinerun-echo-greetings-echo-good-morning)
Good Morning, Bob!
```

Logs from a pod displaying morning greetings:
```bash
kubectl logs $(kubectl get pods -o name | grep pipelinerun-echo-greetings-echo-good-night)
Good Night, Bob!
```

### Resources

When running a [`Pipeline`](pipelines.md), you will need to specify the
Expand Down Expand Up @@ -85,6 +182,34 @@ spec:
name: skaffold-image-leeroy-app
```

Or you can embed the spec of the `Resource` directly in the `PipelineRun`:


```yaml
spec:
resources:
- name: source-repo
resourceSpec:
type: git
params:
- name: revision
value: v0.32.0
- name: url
value: https://github.com/GoogleContainerTools/skaffold
- name: web-image
resourceSpec:
type: image
params:
- name: url
value: gcr.io/christiewilson-catfactory/leeroy-web
- name: app-image
resourceSpec:
type: image
params:
- name: url
value: gcr.io/christiewilson-catfactory/leeroy-app
```

### Service Account

Specifies the `name` of a `ServiceAccount` resource object. Use the
Expand Down Expand Up @@ -121,7 +246,6 @@ spec:
- name: build-task
taskRef:
name: build-push
tasks:
- name: test-task
taskRef:
name: test
Expand Down Expand Up @@ -174,7 +298,7 @@ spec:
tasks:
- name: task1
taskRef:
name: myTask
name: myTask
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipeline_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
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

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// PipelineInterface is implemented by Pipeline and ClusterPipeline
type PipelineInterface interface {
PipelineMetadata() metav1.ObjectMeta
PipelineSpec() PipelineSpec
Copy() PipelineInterface
}
12 changes: 12 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ type Pipeline struct {
Status PipelineStatus `json:"status"`
}

func (p *Pipeline) PipelineMetadata() metav1.ObjectMeta {
return p.ObjectMeta
}

func (p *Pipeline) PipelineSpec() PipelineSpec {
return p.Spec
}

func (p *Pipeline) Copy() PipelineInterface {
return p.DeepCopy()
}

// PipelineTask defines a task in a Pipeline, passing inputs from both
// Params and from the output of previous tasks.
type PipelineTask struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ var _ apis.Defaultable = (*PipelineRun)(nil)
// PipelineRunSpec defines the desired state of PipelineRun
type PipelineRunSpec struct {
PipelineRef PipelineRef `json:"pipelineRef"`
// +optional
PipelineSpec *PipelineSpec `json:"pipelineSpec,omitempty"`
// Resources is a list of bindings specifying which actual instances of
// PipelineResources to use for the resources the Pipeline has declared
// it needs.
Expand Down
19 changes: 16 additions & 3 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,22 @@ func (ps *PipelineRunSpec) Validate(ctx context.Context) *apis.FieldError {
if equality.Semantic.DeepEqual(ps, &PipelineRunSpec{}) {
return apis.ErrMissingField("spec")
}
// pipeline reference should be present for pipelinerun
if ps.PipelineRef.Name == "" {
return apis.ErrMissingField("pipelinerun.spec.Pipelineref.Name")

// can't have both pipelinekRef and pipelineSpec at the same time
if ps.PipelineRef.Name != "" && ps.PipelineSpec != nil {
return apis.ErrDisallowedFields("spec.pipelineRef", "spec.pipelineSpec")
}

// Check that one of PipelineRef and PipelineSpec is present
if ps.PipelineRef.Name == "" && ps.PipelineSpec == nil {
return apis.ErrMissingField("spec.pipelineRef.name", "spec.pipelineSpec")
}

// Validate PipelineSpec if it's present
if ps.PipelineSpec != nil {
if err := ps.PipelineSpec.Validate(ctx); err != nil {
return err
}
}

// check for results
Expand Down
79 changes: 73 additions & 6 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestPipelineRun_Invalidate(t *testing.T) {
ServiceAccount: "foo",
},
},
want: apis.ErrMissingField("pipelinerun.spec.Pipelineref.Name"),
want: apis.ErrMissingField("spec.pipelineRef.name, spec.pipelineSpec"),
}, {
name: "negative pipeline timeout",
pr: v1alpha1.PipelineRun{
Expand All @@ -81,11 +81,11 @@ func TestPipelineRun_Invalidate(t *testing.T) {
},
}

for _, ts := range tests {
t.Run(ts.name, func(t *testing.T) {
err := ts.pr.Validate(context.Background())
if d := cmp.Diff(err.Error(), ts.want.Error()); d != "" {
t.Errorf("PipelineRun.Validate/%s (-want, +got) = %v", ts.name, d)
for _, ps := range tests {
t.Run(ps.name, func(t *testing.T) {
err := ps.pr.Validate(context.Background())
if d := cmp.Diff(err.Error(), ps.want.Error()); d != "" {
t.Errorf("PipelineRun.Validate/%s (-want, +got) = %v", ps.name, d)
}
})
}
Expand Down Expand Up @@ -136,3 +136,70 @@ func TestPipelineRun_Validate(t *testing.T) {
})
}
}

func TestPipelineRunSpec_Invalidate(t *testing.T) {
tests := []struct{
name string
spec v1alpha1.PipelineRunSpec
wantErr *apis.FieldError
}{{
name: "Empty pipelineSpec",
spec: v1alpha1.PipelineRunSpec{},
wantErr: apis.ErrMissingField("spec"),
}, {
name: "pipelineRef without Pipeline Name",
spec: v1alpha1.PipelineRunSpec{
PipelineRef: v1alpha1.PipelineRef{},
},
wantErr: apis.ErrMissingField("spec"),
}, {
name: "pipelineRef and pipelineSpec together",
spec: v1alpha1.PipelineRunSpec{
PipelineRef:v1alpha1.PipelineRef{
Name: "pipelinerefname",
},
PipelineSpec: &v1alpha1.PipelineSpec{
Tasks: []v1alpha1.PipelineTask{{
Name: "mytask",
TaskRef: v1alpha1.TaskRef{
Name: "mytask",
},
}}},
},
wantErr: apis.ErrDisallowedFields("spec.pipelineSpec", "spec.pipelineRef"),
}}
for _, ps := range tests {
t.Run(ps.name, func(t *testing.T) {
err := ps.spec.Validate(context.Background())
if d := cmp.Diff(ps.wantErr.Error(), err.Error()); d != "" {
t.Errorf("PipelineRunSpec.Validate/%s (-want, +got) = %v", ps.name, d)
}
})
}
}

func TestPipelineRunSpec_Validate(t *testing.T) {
tests := []struct {
name string
spec v1alpha1.PipelineRunSpec
}{{
name: "PipelineRun without pipelineRef",
spec: v1alpha1.PipelineRunSpec{
PipelineSpec:&v1alpha1.PipelineSpec{
Tasks: []v1alpha1.PipelineTask{{
Name: "mytask",
TaskRef: v1alpha1.TaskRef{
Name: "mytask",
},
}},
},
},
}}
for _, ps := range tests {
t.Run(ps.name, func(t *testing.T) {
if err := ps.spec.Validate(context.Background()); err != nil {
t.Errorf("PipelineRunSpec.Validate/%s (-want, +got) = %v", ps.name, err)
}
})
}
}
4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1alpha1/resource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ type PipelineResourceBinding struct {
// ResourceRef is a reference to the instance of the actual PipelineResource
// that should be used
ResourceRef PipelineResourceRef `json:"resourceRef,omitempty"`
// +optional
// ResourceSpec is specification of a resource that should be created and
// consumed by the task
ResourceSpec *PipelineResourceSpec `json:"resourceSpec,omitempty"`
}

// PipelineResourceResult used to export the image name and digest as json
Expand Down
Loading

0 comments on commit 929a705

Please sign in to comment.