diff --git a/config/config-defaults.yaml b/config/config-defaults.yaml index fe62f9f2b27..0526a4a967b 100644 --- a/config/config-defaults.yaml +++ b/config/config-defaults.yaml @@ -82,3 +82,7 @@ data: # default-forbidden-env contains comma seperated environment variables that cannot be # overridden by podTemplate. default-forbidden-env: + + # default-resolver-type contains the default resolver type to be used in the cluster, + # no default-resolver-type is specified by default + default-resolver-type: diff --git a/docs/additional-configs.md b/docs/additional-configs.md index ed0644e8bb4..e4734737fab 100644 --- a/docs/additional-configs.md +++ b/docs/additional-configs.md @@ -147,7 +147,7 @@ _In the above example the environment variable `TEST_TEKTON` will not be overrid ## Customizing basic execution parameters -You can specify your own values that replace the default service account (`ServiceAccount`), timeout (`Timeout`), and Pod template (`PodTemplate`) values used by Tekton Pipelines in `TaskRun` and `PipelineRun` definitions. To do so, modify the ConfigMap `config-defaults` with your desired values. +You can specify your own values that replace the default service account (`ServiceAccount`), timeout (`Timeout`), resolver (`Resolver`), and Pod template (`PodTemplate`) values used by Tekton Pipelines in `TaskRun` and `PipelineRun` definitions. To do so, modify the ConfigMap `config-defaults` with your desired values. The example below customizes the following: @@ -156,9 +156,10 @@ The example below customizes the following: - the default `app.kubernetes.io/managed-by` label is applied to all Pods created to execute `TaskRuns`. - the default Pod template to include a node selector to select the node where the Pod will be scheduled by default. A list of supported fields is available [here](https://github.com/tektoncd/pipeline/blob/main/docs/podtemplates.md#supported-fields). For more information, see [`PodTemplate` in `TaskRuns`](./taskruns.md#specifying-a-pod-template) or [`PodTemplate` in `PipelineRuns`](./pipelineruns.md#specifying-a-pod-template). -- the default `Workspace` configuration can be set for any `Workspaces` that a Task declares but that a TaskRun does not explicitly provide +- the default `Workspace` configuration can be set for any `Workspaces` that a Task declares but that a TaskRun does not explicitly provide. - the default maximum combinations of `Parameters` in a `Matrix` that can be used to fan out a `PipelineTask`. For more information, see [`Matrix`](matrix.md). +- the default resolver type to `git`. ```yaml apiVersion: v1 @@ -175,6 +176,7 @@ data: default-task-run-workspace-binding: | emptyDir: {} default-max-matrix-combinations-count: "1024" + default-resolver-type: "git" ``` **Note:** The `_example` key in the provided [config-defaults.yaml](./../config/config-defaults.yaml) @@ -288,6 +290,7 @@ Features currently in "alpha" are: | [Trusted Resources](./trusted-resources.md) | [TEP-0091](https://github.com/tektoncd/community/blob/main/teps/0091-trusted-resources.md) | N/A | `resource-verification-mode` | | [`Provenance` field in Status](pipeline-api.md#provenance) | [issue#5550](https://github.com/tektoncd/pipeline/issues/5550) | N/A | `enable-provenance-in-status` | | [Larger Results via Sidecar Logs](#enabling-larger-results-using-sidecar-logs) | [TEP-0127](https://github.com/tektoncd/community/blob/main/teps/0127-larger-results-via-sidecar-logs.md) | [v0.43.0](https://github.com/tektoncd/pipeline/releases/tag/v0.43.0) | `results-from` | +| [Configure Default Resolver](./resolution.md#configuring-built-in-resolvers) | [TEP-0133](https://github.com/tektoncd/community/blob/main/teps/0133-configure-default-resolver.md) | N/A | | ### Beta Features diff --git a/docs/resolution.md b/docs/resolution.md index 06969b8070f..c5f85a0fb33 100644 --- a/docs/resolution.md +++ b/docs/resolution.md @@ -21,6 +21,8 @@ For new users getting started with Tekton Pipeline remote resolution, check out These resolvers are enabled by setting the appropriate feature flag in the `resolvers-feature-flags` ConfigMap in the `tekton-pipelines-resolvers` namespace. See the [section in install.md](install.md#configuring-built-in-remote-task-and-pipeline-resolution) for details. +The default resolver type can be configured by the `default-resolver-type` field in the `config-defaults` ConfigMap (`alpha` feature). See [additional-configs.md](./additional-configs.md) for details. + ## Developer Howto: Writing a Resolver From Scratch For a developer getting started with writing a new Resolver, see diff --git a/pkg/apis/config/default.go b/pkg/apis/config/default.go index d17e707dcf0..968dae25e8b 100644 --- a/pkg/apis/config/default.go +++ b/pkg/apis/config/default.go @@ -44,6 +44,8 @@ const ( DefaultCloudEventSinkValue = "" // DefaultMaxMatrixCombinationsCount is used when no max matrix combinations count is specified. DefaultMaxMatrixCombinationsCount = 256 + // DefaultResolverTypeValue is used when no default resolver type is specified + DefaultResolverTypeValue = "" defaultTimeoutMinutesKey = "default-timeout-minutes" defaultServiceAccountKey = "default-service-account" @@ -54,6 +56,7 @@ const ( defaultTaskRunWorkspaceBinding = "default-task-run-workspace-binding" defaultMaxMatrixCombinationsCountKey = "default-max-matrix-combinations-count" defaultForbiddenEnv = "default-forbidden-env" + defaultResolverTypeKey = "default-resolver-type" ) // Defaults holds the default configurations @@ -68,6 +71,7 @@ type Defaults struct { DefaultTaskRunWorkspaceBinding string DefaultMaxMatrixCombinationsCount int DefaultForbiddenEnv []string + DefaultResolverType string } // GetDefaultsConfigName returns the name of the configmap containing all @@ -97,6 +101,7 @@ func (cfg *Defaults) Equals(other *Defaults) bool { other.DefaultCloudEventsSink == cfg.DefaultCloudEventsSink && other.DefaultTaskRunWorkspaceBinding == cfg.DefaultTaskRunWorkspaceBinding && other.DefaultMaxMatrixCombinationsCount == cfg.DefaultMaxMatrixCombinationsCount && + other.DefaultResolverType == cfg.DefaultResolverType && reflect.DeepEqual(other.DefaultForbiddenEnv, cfg.DefaultForbiddenEnv) } @@ -108,6 +113,7 @@ func NewDefaultsFromMap(cfgMap map[string]string) (*Defaults, error) { DefaultManagedByLabelValue: DefaultManagedByLabelValue, DefaultCloudEventsSink: DefaultCloudEventSinkValue, DefaultMaxMatrixCombinationsCount: DefaultMaxMatrixCombinationsCount, + DefaultResolverType: DefaultResolverTypeValue, } if defaultTimeoutMin, ok := cfgMap[defaultTimeoutMinutesKey]; ok { @@ -166,6 +172,10 @@ func NewDefaultsFromMap(cfgMap map[string]string) (*Defaults, error) { tc.DefaultForbiddenEnv = tmpString.List() } + if defaultResolverType, ok := cfgMap[defaultResolverTypeKey]; ok { + tc.DefaultResolverType = defaultResolverType + } + return &tc, nil } diff --git a/pkg/apis/config/default_test.go b/pkg/apis/config/default_test.go index 59330008a7c..94377115da6 100644 --- a/pkg/apis/config/default_test.go +++ b/pkg/apis/config/default_test.go @@ -40,6 +40,7 @@ func TestNewDefaultsFromConfigMap(t *testing.T) { DefaultServiceAccount: "tekton", DefaultManagedByLabelValue: "something-else", DefaultMaxMatrixCombinationsCount: 256, + DefaultResolverType: "git", }, fileName: config.GetDefaultsConfigName(), }, diff --git a/pkg/apis/config/testdata/config-defaults.yaml b/pkg/apis/config/testdata/config-defaults.yaml index ce90e418452..d05c8e3cfc3 100644 --- a/pkg/apis/config/testdata/config-defaults.yaml +++ b/pkg/apis/config/testdata/config-defaults.yaml @@ -21,3 +21,4 @@ data: default-timeout-minutes: "50" default-service-account: "tekton" default-managed-by-label-value: "something-else" + default-resolver-type: "git" diff --git a/pkg/apis/pipeline/v1/pipeline_defaults.go b/pkg/apis/pipeline/v1/pipeline_defaults.go index 594e1761e58..1bea3f8efa9 100644 --- a/pkg/apis/pipeline/v1/pipeline_defaults.go +++ b/pkg/apis/pipeline/v1/pipeline_defaults.go @@ -19,6 +19,7 @@ package v1 import ( "context" + "github.com/tektoncd/pipeline/pkg/apis/config" "knative.dev/pkg/apis" ) @@ -31,6 +32,7 @@ func (p *Pipeline) SetDefaults(ctx context.Context) { // SetDefaults sets default values for the PipelineSpec's Params, Tasks, and Finally func (ps *PipelineSpec) SetDefaults(ctx context.Context) { + cfg := config.FromContextOrDefaults(ctx) for i := range ps.Params { ps.Params[i].SetDefaults(ctx) } @@ -40,6 +42,9 @@ func (ps *PipelineSpec) SetDefaults(ctx context.Context) { if pt.TaskRef.Kind == "" { pt.TaskRef.Kind = NamespacedTaskKind } + if pt.TaskRef.Name == "" && pt.TaskRef.Resolver == "" { + pt.TaskRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } } if pt.TaskSpec != nil { pt.TaskSpec.SetDefaults(ctx) diff --git a/pkg/apis/pipeline/v1/pipeline_defaults_test.go b/pkg/apis/pipeline/v1/pipeline_defaults_test.go index 9ff0fb0deaa..91430d4fddf 100644 --- a/pkg/apis/pipeline/v1/pipeline_defaults_test.go +++ b/pkg/apis/pipeline/v1/pipeline_defaults_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + dfttesting "github.com/tektoncd/pipeline/pkg/apis/config/testing" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "github.com/tektoncd/pipeline/test/diff" ) @@ -37,9 +38,10 @@ func TestPipeline_SetDefaults(t *testing.T) { func TestPipelineSpec_SetDefaults(t *testing.T) { cases := []struct { - desc string - ps *v1.PipelineSpec - want *v1.PipelineSpec + desc string + ps *v1.PipelineSpec + want *v1.PipelineSpec + defaults map[string]string }{{ desc: "empty pipelineSpec must not change after setting defaults", ps: &v1.PipelineSpec{}, @@ -120,6 +122,54 @@ func TestPipelineSpec_SetDefaults(t *testing.T) { }, }}, }, + }, { + desc: "pipeline task with taskRef - with default resolver", + ps: &v1.PipelineSpec{ + Tasks: []v1.PipelineTask{{ + Name: "foo", + TaskRef: &v1.TaskRef{}, + }}, + }, + want: &v1.PipelineSpec{ + Tasks: []v1.PipelineTask{{ + Name: "foo", + TaskRef: &v1.TaskRef{ + Kind: v1.NamespacedTaskKind, + ResolverRef: v1.ResolverRef{ + Resolver: "git", + }, + }, + }}, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + desc: "pipeline task with taskRef - user-provided resolver overwrites default resolver", + ps: &v1.PipelineSpec{ + Tasks: []v1.PipelineTask{{ + Name: "foo", + TaskRef: &v1.TaskRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }}, + }, + want: &v1.PipelineSpec{ + Tasks: []v1.PipelineTask{{ + Name: "foo", + TaskRef: &v1.TaskRef{ + Kind: v1.NamespacedTaskKind, + ResolverRef: v1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }}, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }, { desc: "final pipeline task with taskSpec - default param type must be " + string(v1.ParamTypeString), ps: &v1.PipelineSpec{ @@ -149,6 +199,9 @@ func TestPipelineSpec_SetDefaults(t *testing.T) { for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { ctx := context.Background() + if len(tc.defaults) > 0 { + ctx = dfttesting.SetDefaults(context.Background(), t, tc.defaults) + } tc.ps.SetDefaults(ctx) if d := cmp.Diff(tc.want, tc.ps); d != "" { t.Errorf("Mismatch of pipelineSpec after setting defaults: %s", diff.PrintWantGot(d)) diff --git a/pkg/apis/pipeline/v1/pipelinerun_defaults.go b/pkg/apis/pipeline/v1/pipelinerun_defaults.go index a78081505bd..fdfdfeed8e0 100644 --- a/pkg/apis/pipeline/v1/pipelinerun_defaults.go +++ b/pkg/apis/pipeline/v1/pipelinerun_defaults.go @@ -36,6 +36,9 @@ func (pr *PipelineRun) SetDefaults(ctx context.Context) { // SetDefaults implements apis.Defaultable func (prs *PipelineRunSpec) SetDefaults(ctx context.Context) { cfg := config.FromContextOrDefaults(ctx) + if prs.PipelineRef != nil && prs.PipelineRef.Name == "" && prs.PipelineRef.Resolver == "" { + prs.PipelineRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } if prs.Timeouts == nil || prs.Timeouts.Pipeline == nil { prs.Timeouts = &TimeoutFields{ diff --git a/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go b/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go index 2420a260462..e643562f421 100644 --- a/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go +++ b/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go @@ -332,6 +332,56 @@ func TestPipelineRunDefaulting(t *testing.T) { "default-service-account": "tekton", "default-pod-template": "nodeSelector: { 'label': 'value' }\nhostNetwork: true", }, + }, { + name: "PipelineRef uses default resolver", + in: &v1.PipelineRun{Spec: v1.PipelineRunSpec{PipelineRef: &v1.PipelineRef{}}}, + want: &v1.PipelineRun{ + Spec: v1.PipelineRunSpec{ + TaskRunTemplate: v1.PipelineTaskRunTemplate{ + ServiceAccountName: config.DefaultServiceAccountValue, + }, + Timeouts: &v1.TimeoutFields{ + Pipeline: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + PipelineRef: &v1.PipelineRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "git", + }, + }, + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + name: "PipelineRef user-provided resolver overwrites default resolver", + in: &v1.PipelineRun{ + Spec: v1.PipelineRunSpec{ + PipelineRef: &v1.PipelineRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "hub", + }, + }, + }, + }, + want: &v1.PipelineRun{ + Spec: v1.PipelineRunSpec{ + TaskRunTemplate: v1.PipelineTaskRunTemplate{ + ServiceAccountName: config.DefaultServiceAccountValue, + }, + Timeouts: &v1.TimeoutFields{ + Pipeline: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + PipelineRef: &v1.PipelineRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "hub", + }, + }, + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/apis/pipeline/v1/taskrun_defaults.go b/pkg/apis/pipeline/v1/taskrun_defaults.go index 61932f46688..9f34e6b5c73 100644 --- a/pkg/apis/pipeline/v1/taskrun_defaults.go +++ b/pkg/apis/pipeline/v1/taskrun_defaults.go @@ -50,8 +50,13 @@ func (tr *TaskRun) SetDefaults(ctx context.Context) { // SetDefaults implements apis.Defaultable func (trs *TaskRunSpec) SetDefaults(ctx context.Context) { cfg := config.FromContextOrDefaults(ctx) - if trs.TaskRef != nil && trs.TaskRef.Kind == "" { - trs.TaskRef.Kind = NamespacedTaskKind + if trs.TaskRef != nil { + if trs.TaskRef.Kind == "" { + trs.TaskRef.Kind = NamespacedTaskKind + } + if trs.TaskRef.Name == "" && trs.TaskRef.Resolver == "" { + trs.TaskRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } } if trs.Timeout == nil { diff --git a/pkg/apis/pipeline/v1/taskrun_defaults_test.go b/pkg/apis/pipeline/v1/taskrun_defaults_test.go index 107d4e60ff6..cb90af09d53 100644 --- a/pkg/apis/pipeline/v1/taskrun_defaults_test.go +++ b/pkg/apis/pipeline/v1/taskrun_defaults_test.go @@ -335,6 +335,60 @@ func TestTaskRunDefaulting(t *testing.T) { "default-service-account": "tekton", "default-pod-template": "nodeSelector: { 'label': 'value' }", }, + }, { + name: "TaskRef with default resolver", + in: &v1.TaskRun{ + Spec: v1.TaskRunSpec{ + TaskRef: &v1.TaskRef{}, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"}, + }, + Spec: v1.TaskRunSpec{ + TaskRef: &v1.TaskRef{ + Kind: "Task", + ResolverRef: v1.ResolverRef{ + Resolver: "git", + }, + }, + Timeout: &metav1.Duration{Duration: time.Hour}, + ServiceAccountName: "default", + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + name: "TaskRef user-provided resolver overwrites default resolver", + in: &v1.TaskRun{ + Spec: v1.TaskRunSpec{ + TaskRef: &v1.TaskRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"}, + }, + Spec: v1.TaskRunSpec{ + TaskRef: &v1.TaskRef{ + Kind: "Task", + ResolverRef: v1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + Timeout: &metav1.Duration{Duration: time.Hour}, + ServiceAccountName: "default", + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/apis/pipeline/v1beta1/pipeline_defaults.go b/pkg/apis/pipeline/v1beta1/pipeline_defaults.go index a7463ae53ed..716ef801554 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_defaults.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_defaults.go @@ -19,6 +19,7 @@ package v1beta1 import ( "context" + "github.com/tektoncd/pipeline/pkg/apis/config" "knative.dev/pkg/apis" ) @@ -31,6 +32,7 @@ func (p *Pipeline) SetDefaults(ctx context.Context) { // SetDefaults sets default values for the PipelineSpec's Params, Tasks, and Finally func (ps *PipelineSpec) SetDefaults(ctx context.Context) { + cfg := config.FromContextOrDefaults(ctx) for i := range ps.Params { ps.Params[i].SetDefaults(ctx) } @@ -40,6 +42,9 @@ func (ps *PipelineSpec) SetDefaults(ctx context.Context) { if pt.TaskRef.Kind == "" { pt.TaskRef.Kind = NamespacedTaskKind } + if pt.TaskRef.Name == "" && pt.TaskRef.Resolver == "" { + pt.TaskRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } } if pt.TaskSpec != nil { pt.TaskSpec.SetDefaults(ctx) diff --git a/pkg/apis/pipeline/v1beta1/pipeline_defaults_test.go b/pkg/apis/pipeline/v1beta1/pipeline_defaults_test.go index 916eacf28f7..29590d215d9 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_defaults_test.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_defaults_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + dfttesting "github.com/tektoncd/pipeline/pkg/apis/config/testing" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/test/diff" ) @@ -37,9 +38,10 @@ func TestPipeline_SetDefaults(t *testing.T) { func TestPipelineSpec_SetDefaults(t *testing.T) { cases := []struct { - desc string - ps *v1beta1.PipelineSpec - want *v1beta1.PipelineSpec + desc string + ps *v1beta1.PipelineSpec + want *v1beta1.PipelineSpec + defaults map[string]string }{{ desc: "empty pipelineSpec must not change after setting defaults", ps: &v1beta1.PipelineSpec{}, @@ -120,6 +122,54 @@ func TestPipelineSpec_SetDefaults(t *testing.T) { }, }}, }, + }, { + desc: "pipeline task with taskRef - with default resolver", + ps: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "foo", + TaskRef: &v1beta1.TaskRef{}, + }}, + }, + want: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "foo", + TaskRef: &v1beta1.TaskRef{ + Kind: v1beta1.NamespacedTaskKind, + ResolverRef: v1beta1.ResolverRef{ + Resolver: "git", + }, + }, + }}, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + desc: "pipeline task with taskRef - user-provided resolver overwrites default resolver", + ps: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "foo", + TaskRef: &v1beta1.TaskRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }}, + }, + want: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "foo", + TaskRef: &v1beta1.TaskRef{ + Kind: v1beta1.NamespacedTaskKind, + ResolverRef: v1beta1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }}, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }, { desc: "final pipeline task with taskSpec - default param type must be " + string(v1beta1.ParamTypeString), ps: &v1beta1.PipelineSpec{ @@ -149,6 +199,9 @@ func TestPipelineSpec_SetDefaults(t *testing.T) { for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { ctx := context.Background() + if len(tc.defaults) > 0 { + ctx = dfttesting.SetDefaults(context.Background(), t, tc.defaults) + } tc.ps.SetDefaults(ctx) if d := cmp.Diff(tc.want, tc.ps); d != "" { t.Errorf("Mismatch of pipelineSpec after setting defaults: %s", diff.PrintWantGot(d)) diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go index a47a0d3e556..86592824a20 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go @@ -36,6 +36,10 @@ func (pr *PipelineRun) SetDefaults(ctx context.Context) { // SetDefaults implements apis.Defaultable func (prs *PipelineRunSpec) SetDefaults(ctx context.Context) { cfg := config.FromContextOrDefaults(ctx) + if prs.PipelineRef != nil && prs.PipelineRef.Name == "" && prs.PipelineRef.Resolver == "" { + prs.PipelineRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } + if prs.Timeout == nil && prs.Timeouts == nil { prs.Timeout = &metav1.Duration{Duration: time.Duration(cfg.Defaults.DefaultTimeoutMinutes) * time.Minute} } diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go index 6290385a050..725919f1006 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go @@ -268,6 +268,48 @@ func TestPipelineRunDefaulting(t *testing.T) { "default-service-account": "tekton", "default-pod-template": "nodeSelector: { 'label': 'value' }\nhostNetwork: true", }, + }, { + name: "PipelineRef uses default resolver", + in: &v1beta1.PipelineRun{Spec: v1beta1.PipelineRunSpec{PipelineRef: &v1beta1.PipelineRef{}}}, + want: &v1beta1.PipelineRun{ + Spec: v1beta1.PipelineRunSpec{ + ServiceAccountName: config.DefaultServiceAccountValue, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + PipelineRef: &v1beta1.PipelineRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "git", + }, + }, + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + name: "PipelineRef user-provided resolver overwrites default resolver", + in: &v1beta1.PipelineRun{ + Spec: v1beta1.PipelineRunSpec{ + PipelineRef: &v1beta1.PipelineRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "hub", + }, + }, + }, + }, + want: &v1beta1.PipelineRun{ + Spec: v1beta1.PipelineRunSpec{ + ServiceAccountName: config.DefaultServiceAccountValue, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + PipelineRef: &v1beta1.PipelineRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "hub", + }, + }, + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/apis/pipeline/v1beta1/taskrun_defaults.go b/pkg/apis/pipeline/v1beta1/taskrun_defaults.go index feecece526e..61f3285decd 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_defaults.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_defaults.go @@ -50,8 +50,13 @@ func (tr *TaskRun) SetDefaults(ctx context.Context) { // SetDefaults implements apis.Defaultable func (trs *TaskRunSpec) SetDefaults(ctx context.Context) { cfg := config.FromContextOrDefaults(ctx) - if trs.TaskRef != nil && trs.TaskRef.Kind == "" { - trs.TaskRef.Kind = NamespacedTaskKind + if trs.TaskRef != nil { + if trs.TaskRef.Kind == "" { + trs.TaskRef.Kind = NamespacedTaskKind + } + if trs.TaskRef.Name == "" && trs.TaskRef.Resolver == "" { + trs.TaskRef.Resolver = ResolverName(cfg.Defaults.DefaultResolverType) + } } if trs.Timeout == nil { diff --git a/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go b/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go index e4a1f4d2528..3a127cb6d07 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go @@ -345,6 +345,60 @@ func TestTaskRunDefaulting(t *testing.T) { "default-service-account": "tekton", "default-pod-template": "nodeSelector: { 'label': 'value' }", }, + }, { + name: "TaskRef with default resolver", + in: &v1beta1.TaskRun{ + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{}, + }, + }, + want: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"}, + }, + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{ + Kind: "Task", + ResolverRef: v1beta1.ResolverRef{ + Resolver: "git", + }, + }, + Timeout: &metav1.Duration{Duration: time.Hour}, + ServiceAccountName: "default", + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, + }, { + name: "TaskRef user-provided resolver overwrites default resolver", + in: &v1beta1.TaskRun{ + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + }, + }, + want: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"}, + }, + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{ + Kind: "Task", + ResolverRef: v1beta1.ResolverRef{ + Resolver: "custom resolver", + }, + }, + Timeout: &metav1.Duration{Duration: time.Hour}, + ServiceAccountName: "default", + }, + }, + defaults: map[string]string{ + "default-resolver-type": "git", + }, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/reconciler/pipelinerun/pipelinespec/pipelinespec_test.go b/pkg/reconciler/pipelinerun/pipelinespec/pipelinespec_test.go index 2dbb4e8a220..f88073f8204 100644 --- a/pkg/reconciler/pipelinerun/pipelinespec/pipelinespec_test.go +++ b/pkg/reconciler/pipelinerun/pipelinespec/pipelinespec_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + cfgtesting "github.com/tektoncd/pipeline/pkg/apis/config/testing" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/test/diff" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -127,65 +128,116 @@ func TestGetPipelineSpec_Invalid(t *testing.T) { } func TestGetPipelineData_ResolutionSuccess(t *testing.T) { - pr := &v1beta1.PipelineRun{ - ObjectMeta: metav1.ObjectMeta{ - Name: "mypipelinerun", - }, - Spec: v1beta1.PipelineRunSpec{ - PipelineRef: &v1beta1.PipelineRef{ - ResolverRef: v1beta1.ResolverRef{ - Resolver: "foo", - Params: []v1beta1.Param{{ - Name: "bar", - Value: v1beta1.ParamValue{ - Type: v1beta1.ParamTypeString, - StringVal: "baz", + sourceMeta := &metav1.ObjectMeta{ + Name: "pipeline", + } + sourceConfigSource := &v1beta1.ConfigSource{ + URI: "abc.com", + Digest: map[string]string{"sha1": "a123"}, + EntryPoint: "foo/bar", + } + + tests := []struct { + name string + pr *v1beta1.PipelineRun + sourceMeta *metav1.ObjectMeta + sourceSpec *v1beta1.PipelineSpec + sourceConfigSource *v1beta1.ConfigSource + expectedSpec *v1beta1.PipelineSpec + defaults map[string]string + }{ + { + name: "resolve remote task with taskRef Name", + sourceMeta: sourceMeta, + sourceConfigSource: sourceConfigSource, + pr: &v1beta1.PipelineRun{ + Spec: v1beta1.PipelineRunSpec{ + PipelineRef: &v1beta1.PipelineRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "foo", }, - }}, + }, }, }, + sourceSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "pt1", + TaskRef: &v1beta1.TaskRef{ + Kind: "Task", + Name: "tref", + }, + }}, + }, + expectedSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "pt1", + TaskRef: &v1beta1.TaskRef{ + Kind: "Task", + Name: "tref", + }, + }}, + }, }, - } - sourceMeta := metav1.ObjectMeta{ - Name: "pipeline", - } - sourceSpec := v1beta1.PipelineSpec{ - Tasks: []v1beta1.PipelineTask{{ - Name: "pt1", - TaskRef: &v1beta1.TaskRef{ - Kind: "Task", - Name: "tref", + { + name: "resolve remote task with taskRef resolver - default resolver configured", + sourceMeta: sourceMeta, + sourceConfigSource: sourceConfigSource, + pr: &v1beta1.PipelineRun{ + Spec: v1beta1.PipelineRunSpec{ + PipelineRef: &v1beta1.PipelineRef{ + ResolverRef: v1beta1.ResolverRef{ + Resolver: "foo", + }, + }, + }, + }, + sourceSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "pt1", + TaskRef: &v1beta1.TaskRef{}, + }}, + }, + expectedSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "pt1", + TaskRef: &v1beta1.TaskRef{ + Kind: "Task", + ResolverRef: v1beta1.ResolverRef{ + Resolver: "foo", + }, + }, + }}, + }, + defaults: map[string]string{ + "default-resolver-type": "foo", }, - }}, - } - expectedConfigSource := &v1beta1.ConfigSource{ - URI: "abc.com", - Digest: map[string]string{ - "sha1": "a123", }, - EntryPoint: "foo/bar", } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ctx := cfgtesting.SetDefaults(context.Background(), t, tc.defaults) + getPipeline := func(ctx context.Context, n string) (v1beta1.PipelineObject, *v1beta1.ConfigSource, error) { + return &v1beta1.Pipeline{ + ObjectMeta: *tc.sourceMeta.DeepCopy(), + Spec: *tc.sourceSpec.DeepCopy(), + }, tc.sourceConfigSource.DeepCopy(), nil + } - getPipeline := func(ctx context.Context, n string) (v1beta1.PipelineObject, *v1beta1.ConfigSource, error) { - return &v1beta1.Pipeline{ - ObjectMeta: *sourceMeta.DeepCopy(), - Spec: *sourceSpec.DeepCopy(), - }, expectedConfigSource.DeepCopy(), nil - } - ctx := context.Background() - resolvedMeta, resolvedSpec, err := GetPipelineData(ctx, pr, getPipeline) - if err != nil { - t.Fatalf("Unexpected error getting mocked data: %v", err) - } - if sourceMeta.Name != resolvedMeta.Name { - t.Errorf("Expected name %q but resolved to %q", sourceMeta.Name, resolvedMeta.Name) - } - if d := cmp.Diff(sourceSpec, *resolvedSpec); d != "" { - t.Errorf(diff.PrintWantGot(d)) - } + resolvedObjectMeta, resolvedPipelineSpec, err := GetPipelineData(ctx, tc.pr, getPipeline) + if err != nil { + t.Fatalf("did not expect error getting pipeline spec but got: %s", err) + } - if d := cmp.Diff(expectedConfigSource, resolvedMeta.ConfigSource); d != "" { - t.Errorf("configsource did not match: %s", diff.PrintWantGot(d)) + if sourceMeta.Name != resolvedObjectMeta.Name { + t.Errorf("expected name %q but resolved to %q", sourceMeta.Name, resolvedObjectMeta.Name) + } + if d := cmp.Diff(tc.sourceConfigSource, resolvedObjectMeta.ConfigSource); d != "" { + t.Errorf("configSource did not match: %s", diff.PrintWantGot(d)) + } + if d := cmp.Diff(tc.expectedSpec, resolvedPipelineSpec); d != "" { + t.Errorf("pipelineSpec did not match: %s", diff.PrintWantGot(d)) + } + }) } }