Skip to content

Commit

Permalink
pipelinetask metadata
Browse files Browse the repository at this point in the history
Adding metadata to TaskSpec in PipelineTask to allow specifying metadata.
This metadata will be propogated to taskRun and then to the pods.

```
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: pipelinerun-with-taskspec-to-echo-greetings
spec:
  pipelineSpec:
    tasks:
      - name: echo-greetings
        taskSpec:
          metadata:
            labels: [ …]
          steps:
...
```

Metadata is already supported as part of Tasks and Pipelines while
respective CRDs are created. But was not possible to specify with
embedded resources.
  • Loading branch information
pritidesai committed Jul 1, 2020
1 parent 44f22a0 commit b42df6a
Show file tree
Hide file tree
Showing 12 changed files with 369 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ spec:
tasks:
- name: echo-good-morning
taskSpec:
metadata:
labels:
app: "example"
steps:
- name: echo
image: ubuntu
Expand Down
15 changes: 14 additions & 1 deletion internal/builder/v1beta1/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,20 @@ func PipelineRunResult(name, value string) PipelineRunStatusOp {
// PipelineTaskSpec sets the TaskSpec on a PipelineTask.
func PipelineTaskSpec(spec *v1beta1.TaskSpec) PipelineTaskOp {
return func(pt *v1beta1.PipelineTask) {
pt.TaskSpec = spec
if pt.TaskSpec == nil {
pt.TaskSpec = &v1beta1.EmbeddedTask{}
}
pt.TaskSpec.TaskSpec = spec
}
}

// PipelineTaskMetadata sets the Metadata on a PipelineTask.
func PipelineTaskMetadata(metadata metav1.ObjectMeta) PipelineTaskOp {
return func(pt *v1beta1.PipelineTask) {
if pt.TaskSpec == nil {
pt.TaskSpec = &v1beta1.EmbeddedTask{}
}
pt.TaskSpec.Metadata = metadata
}
}

Expand Down
69 changes: 62 additions & 7 deletions internal/builder/v1beta1/pipeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,14 @@ func TestPipeline(t *testing.T) {
Timeout: &metav1.Duration{Duration: 5 * time.Second},
}, {
Name: "foo",
TaskSpec: &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{Container: corev1.Container{
Name: "step",
Image: "myimage",
}}},
},
}},
TaskSpec: &v1beta1.EmbeddedTask{
TaskSpec: &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{Container: corev1.Container{
Name: "step",
Image: "myimage",
}}},
},
}}},
Workspaces: []v1beta1.PipelineWorkspaceDeclaration{{
Name: "workspace1",
}},
Expand Down Expand Up @@ -393,3 +394,57 @@ func TestPipelineRunWithPipelineSpec(t *testing.T) {
t.Fatalf("PipelineRun diff -want, +got: %s", diff)
}
}

func TestPipelineRunWithTaskSpec_TaskMetadata(t *testing.T) {
pipelineRun := tb.PipelineRun("pear", tb.PipelineRunNamespace("foo"),
tb.PipelineRunSpec("", tb.PipelineRunPipelineSpec(
tb.PipelineTask("a-task", "",
tb.PipelineTaskMetadata(metav1.ObjectMeta{
Name: "a-task-name",
Labels: map[string]string{"label": "labelvalue"},
Annotations: map[string]string{"annotation": "annotationvalue"}},
),
tb.PipelineTaskSpec(&v1beta1.TaskSpec{
Steps: []v1beta1.Step{{Container: corev1.Container{
Name: "step",
Image: "myimage",
}}},
},
))),
tb.PipelineRunServiceAccountName("sa"),
))

expectedPipelineRun := &v1beta1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{
Name: "pear",
Namespace: "foo",
},
Spec: v1beta1.PipelineRunSpec{
PipelineRef: nil,
PipelineSpec: &v1beta1.PipelineSpec{
Tasks: []v1beta1.PipelineTask{{
Name: "a-task",
TaskSpec: &v1beta1.EmbeddedTask{
Metadata: metav1.ObjectMeta{
Name: "a-task-name",
Labels: map[string]string{"label": "labelvalue"},
Annotations: map[string]string{"annotation": "annotationvalue"},
},
TaskSpec: &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{Container: corev1.Container{
Name: "step",
Image: "myimage",
}}},
},
},
}},
},
ServiceAccountName: "sa",
Timeout: &metav1.Duration{Duration: 1 * time.Hour},
},
}

if diff := cmp.Diff(expectedPipelineRun, pipelineRun); diff != "" {
t.Fatalf("PipelineRun diff -want, +got: %s", diff)
}
}
8 changes: 5 additions & 3 deletions pkg/apis/pipeline/v1alpha1/pipeline_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"context"
"fmt"

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

"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"knative.dev/pkg/apis"
)
Expand Down Expand Up @@ -61,8 +63,8 @@ func (source *PipelineTask) ConvertTo(ctx context.Context, sink *v1beta1.Pipelin
sink.Name = source.Name
sink.TaskRef = source.TaskRef
if source.TaskSpec != nil {
sink.TaskSpec = &v1beta1.TaskSpec{}
if err := source.TaskSpec.ConvertTo(ctx, sink.TaskSpec); err != nil {
sink.TaskSpec = &v1beta1.EmbeddedTask{v1.ObjectMeta{}, &v1beta1.TaskSpec{}}
if err := source.TaskSpec.ConvertTo(ctx, sink.TaskSpec.TaskSpec); err != nil {
return err
}
}
Expand Down Expand Up @@ -112,7 +114,7 @@ func (sink *PipelineTask) ConvertFrom(ctx context.Context, source v1beta1.Pipeli
sink.TaskRef = source.TaskRef
if source.TaskSpec != nil {
sink.TaskSpec = &TaskSpec{}
if err := sink.TaskSpec.ConvertFrom(ctx, source.TaskSpec); err != nil {
if err := sink.TaskSpec.ConvertFrom(ctx, source.TaskSpec.TaskSpec); err != nil {
return err
}
}
Expand Down
50 changes: 32 additions & 18 deletions pkg/apis/pipeline/v1beta1/pipeline_defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"context"
"testing"

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

"github.com/tektoncd/pipeline/test/diff"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -85,41 +87,53 @@ func TestPipelineSpec_SetDefaults(t *testing.T) {
desc: "pipeline task with taskSpec - default param type must be " + string(v1beta1.ParamTypeString),
ps: &v1beta1.PipelineSpec{
Tasks: []v1beta1.PipelineTask{{
Name: "foo", TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
}},
Name: "foo", TaskSpec: &v1beta1.EmbeddedTask{
Metadata: v1.ObjectMeta{},
TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
}},
},
},
}},
},
want: &v1beta1.PipelineSpec{
Tasks: []v1beta1.PipelineTask{{
Name: "foo", TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
Type: v1beta1.ParamTypeString,
}},
Name: "foo", TaskSpec: &v1beta1.EmbeddedTask{
Metadata: v1.ObjectMeta{},
TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
Type: v1beta1.ParamTypeString,
}},
},
},
}},
},
}, {
desc: "final pipeline task with taskSpec - default param type must be " + string(v1beta1.ParamTypeString),
ps: &v1beta1.PipelineSpec{
Finally: []v1beta1.PipelineTask{{
Name: "foo", TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
}},
Name: "foo", TaskSpec: &v1beta1.EmbeddedTask{
Metadata: v1.ObjectMeta{},
TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
}},
},
},
}},
},
want: &v1beta1.PipelineSpec{
Finally: []v1beta1.PipelineTask{{
Name: "foo", TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
Type: v1beta1.ParamTypeString,
}},
Name: "foo", TaskSpec: &v1beta1.EmbeddedTask{
Metadata: v1.ObjectMeta{},
TaskSpec: &v1beta1.TaskSpec{
Params: []v1beta1.ParamSpec{{
Name: "string-param",
Type: v1beta1.ParamTypeString,
}},
},
},
}},
},
Expand Down
26 changes: 25 additions & 1 deletion pkg/apis/pipeline/v1beta1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ limitations under the License.
package v1beta1

import (
"github.com/tektoncd/pipeline/pkg/apis/validate"
"github.com/tektoncd/pipeline/pkg/reconciler/pipeline/dag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
)

// +genclient
Expand Down Expand Up @@ -90,6 +92,15 @@ type PipelineResult struct {
Value string `json:"value"`
}

type EmbeddedTask struct {
// +optional
Metadata metav1.ObjectMeta `json:"metadata,omitempty"`

// TaskSpec is a specification of a task
// +optional
*TaskSpec `json:",inline,omitempty"`
}

// PipelineTask defines a task in a Pipeline, passing inputs from both
// Params and from the output of previous tasks.
type PipelineTask struct {
Expand All @@ -104,7 +115,7 @@ type PipelineTask struct {

// TaskSpec is a specification of a task
// +optional
TaskSpec *TaskSpec `json:"taskSpec,omitempty"`
TaskSpec *EmbeddedTask `json:"taskSpec,inline,omitempty"`

// Conditions is a list of conditions that need to be true for the task to run
// +optional
Expand Down Expand Up @@ -139,6 +150,19 @@ type PipelineTask struct {
Timeout *metav1.Duration `json:"timeout,omitempty"`
}

func (pt *PipelineTask) TaskSpecMetadata() metav1.ObjectMeta {
return pt.TaskSpec.Metadata
}

func (pt *PipelineTask) ValidateTaskSpecMetadata() *apis.FieldError {
if pt.TaskSpec != nil {
if err := validate.ObjectMetadata(pt.TaskSpec.Metadata.GetObjectMeta()); err != nil {
return err.ViaField("[tasks|finally].taskSpec.metadata")
}
}
return nil
}

func (pt PipelineTask) HashKey() string {
return pt.Name
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/pipeline/v1beta1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ func validatePipelineTaskName(ctx context.Context, prefix string, i int, t Pipel
if err := t.TaskSpec.Validate(ctx); err != nil {
return err
}
if err := t.ValidateTaskSpecMetadata(); err != nil {
return err
}
}
if t.TaskRef != nil && t.TaskRef.Name != "" {
// Task names are appended to the container name, which must exist and
Expand Down
Loading

0 comments on commit b42df6a

Please sign in to comment.