diff --git a/Gopkg.lock b/Gopkg.lock index a8e7111b83f..5788a63544a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1356,10 +1356,8 @@ "github.com/google/go-containerregistry/pkg/v1", "github.com/google/go-containerregistry/pkg/v1/empty", "github.com/google/go-containerregistry/pkg/v1/layout", - "github.com/google/go-containerregistry/pkg/v1/partial", "github.com/google/go-containerregistry/pkg/v1/random", "github.com/google/go-containerregistry/pkg/v1/remote", - "github.com/google/go-containerregistry/pkg/v1/types", "github.com/hashicorp/go-multierror", "github.com/hashicorp/golang-lru", "github.com/jenkins-x/go-scm/scm", diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_types.go b/pkg/apis/pipeline/v1alpha1/taskrun_types.go index 1a676a7cbaf..06515436d36 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_types.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_types.go @@ -48,9 +48,11 @@ type TaskRunSpec struct { // Refer Go's ParseDuration documentation for expected format: https://golang.org/pkg/time/#ParseDuration // +optional Timeout *metav1.Duration `json:"timeout,omitempty"` - // PodTemplate holds pod specific configuration PodTemplate PodTemplate `json:"podTemplate,omitempty"` + // Env, if specified will provide variables to all task steps. + // +optional + Env []corev1.EnvVar `json:"env,omitempty"` } // TaskRunSpecStatus defines the taskrun spec status the user can provide diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 2d57103828e..44fede027a0 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -1717,6 +1717,13 @@ func (in *TaskRunSpec) DeepCopyInto(out *TaskRunSpec) { **out = **in } in.PodTemplate.DeepCopyInto(&out.PodTemplate) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/pkg/pod/pod.go b/pkg/pod/pod.go index 75b84259111..5cd9a7f6271 100644 --- a/pkg/pod/pod.go +++ b/pkg/pod/pod.go @@ -144,10 +144,12 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha } // Add implicit env vars. - // They're prepended to the list, so that if the user specified any - // themselves their value takes precedence. + // Append to an empty list to ensure we don't alter implicitEnvVars. + // Precedence: step.Env > taskRun.Spec.Env > implicitEnvVars for i, s := range stepContainers { - env := append(implicitEnvVars, s.Env...) + env := append([]corev1.EnvVar{}, implicitEnvVars...) + env = append(env, taskRun.Spec.Env...) + env = append(env, s.Env...) stepContainers[i].Env = env } diff --git a/pkg/pod/pod_test.go b/pkg/pod/pod_test.go index a4d3b3f8191..37379ffd819 100644 --- a/pkg/pod/pod_test.go +++ b/pkg/pod/pod_test.go @@ -573,7 +573,55 @@ script-heredoc-randomly-generated-6nl7g }}, Volumes: append(implicitVolumes, scriptsVolume, toolsVolume, downwardVolume), }, - }} { + }, { + desc: "env is set", + ts: v1alpha1.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "step-with-env", + Image: "image", + Command: []string{"cmd"}, // avoid entrypoint lookup. + }}}, + }, + trs: v1alpha1.TaskRunSpec{ + Env: []corev1.EnvVar{ + {Name: "FOO", Value: "bar"}, + }, + }, + want: &corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + InitContainers: []corev1.Container{placeToolsInit}, + Containers: []corev1.Container{{ + Name: "step-step-with-env", + Image: "image", + Command: []string{"/tekton/tools/entrypoint"}, + Args: []string{ + "-wait_file", + "/tekton/downward/ready", + "-wait_file_content", + "-post_file", + "/tekton/tools/0", + "-entrypoint", + "cmd", + "--", + }, + // Append to an empty slice to avoid manipulating + // implicitEnvVars, but keep user variables last to ensure + // precedence. + Env: append(append([]corev1.EnvVar{}, implicitEnvVars...), corev1.EnvVar{Name: "FOO", Value: "bar"}), + VolumeMounts: append([]corev1.VolumeMount{toolsMount, downwardMount}, implicitVolumeMounts...), + WorkingDir: workspaceDir, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("0"), + corev1.ResourceMemory: resource.MustParse("0"), + corev1.ResourceEphemeralStorage: resource.MustParse("0"), + }, + }, + }}, + Volumes: append(implicitVolumes, toolsVolume, downwardVolume), + }, + }, + } { t.Run(c.desc, func(t *testing.T) { names.TestingSeed() kubeclient := fakek8s.NewSimpleClientset(