From f7e5829dcf276cb2872f0ebcb633014095c86be8 Mon Sep 17 00:00:00 2001 From: Chitrang Patel Date: Wed, 6 Dec 2023 11:22:10 -0500 Subject: [PATCH] TEP-0142: Introduce WorkingDir in StepActions This PR introduces `workingDir` into `StepActions`. This allows the `StepAction` to set the `workingDir` and work relative to it. --- docs/pipeline-api.md | 30 ++++++++++++++++ docs/stepactions.md | 36 +++++++++++++++++++ pkg/apis/pipeline/v1/task_validation.go | 6 ++++ pkg/apis/pipeline/v1/task_validation_test.go | 15 ++++++-- .../pipeline/v1alpha1/openapi_generated.go | 7 ++++ .../pipeline/v1alpha1/stepaction_types.go | 6 ++++ pkg/apis/pipeline/v1alpha1/swagger.json | 4 +++ pkg/apis/pipeline/v1beta1/task_validation.go | 6 ++++ .../pipeline/v1beta1/task_validation_test.go | 15 ++++++-- pkg/reconciler/taskrun/resources/taskspec.go | 1 + .../taskrun/resources/taskspec_test.go | 24 ++++++------- pkg/reconciler/taskrun/taskrun_test.go | 2 -- 12 files changed, 132 insertions(+), 20 deletions(-) diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md index 2acc4130672..ecb9247b69d 100644 --- a/docs/pipeline-api.md +++ b/docs/pipeline-api.md @@ -6720,6 +6720,21 @@ string +workingDir
+ +string + + + +(Optional) +

Step’s working directory. +If not specified, the container runtime’s default will be used, which +might be configured in the container image. +Cannot be updated.

+ + + + params
@@ -7541,6 +7556,21 @@ string +workingDir
+ +string + + + +(Optional) +

Step’s working directory. +If not specified, the container runtime’s default will be used, which +might be configured in the container image. +Cannot be updated.

+ + + + params
diff --git a/docs/stepactions.md b/docs/stepactions.md index 3295f34f479..2f45b3fa0c6 100644 --- a/docs/stepactions.md +++ b/docs/stepactions.md @@ -13,6 +13,7 @@ weight: 201 - [Passing Params to StepAction](#passing-params-to-stepaction) - [Emitting Results](#emitting-results) - [Fetching Emitted Results from StepActions](#fetching-emitted-results-from-stepactions) + - [Declaring WorkingDir](#declaring-workingdir) - [Declaring SecurityContext](#declaring-securitycontext) - [Declaring VolumeMounts](#declaring-volumemounts) - [Referencing a StepAction](#referencing-a-stepaction) @@ -51,6 +52,7 @@ A `StepAction` definition supports the following fields: - `env` - [`params`](#declaring-parameters) - [`results`](#emitting-results) + - [`workingDir`](#declaring-workingdir) - [`securityContext`](#declaring-securitycontext) - [`volumeMounts`](#declaring-volumemounts) @@ -234,6 +236,40 @@ spec: name: kaniko-step-action ``` +### Declaring WorkingDir + +You can declare `workingDir` in a `StepAction`: + +```yaml +apiVersion: tekton.dev/v1alpha1 +kind: StepAction +metadata: + name: example-stepaction-name +spec: + image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:latest + workingDir: /workspace + script: | + # clone the repo + ... +``` + +The `Task` using the `StepAction` has more context about how the `Steps` have been orchestrated. As such, the `Task` should be able to update the `workingDir` of the `StepAction` so that the `StepAction` is executed from the correct location. +The `StepAction` can parametrize the `workingDir` and work relative to it. This way, the `Task` does not really need control over the workingDir, it just needs to pass the path as a parameter. + +```yaml +apiVersion: tekton.dev/v1alpha1 +kind: StepAction +metadata: + name: example-stepaction-name +spec: + image: ubuntu + params: + - name: source + description: "The path to the source code." + workingDir: $(params.source) +``` + + ### Declaring SecurityContext You can declare `securityContext` in a `StepAction`: diff --git a/pkg/apis/pipeline/v1/task_validation.go b/pkg/apis/pipeline/v1/task_validation.go index 86c277ca968..c98819cf592 100644 --- a/pkg/apis/pipeline/v1/task_validation.go +++ b/pkg/apis/pipeline/v1/task_validation.go @@ -352,6 +352,12 @@ func validateStep(ctx context.Context, s Step, names sets.String) (errs *apis.Fi Paths: []string{"script"}, }) } + if s.WorkingDir != "" { + errs = errs.Also(&apis.FieldError{ + Message: "working dir cannot be used with Ref", + Paths: []string{"workingDir"}, + }) + } if s.Env != nil { errs = errs.Also(&apis.FieldError{ Message: "env cannot be used with Ref", diff --git a/pkg/apis/pipeline/v1/task_validation_test.go b/pkg/apis/pipeline/v1/task_validation_test.go index 6f38a2d38b0..60ce1bc12fd 100644 --- a/pkg/apis/pipeline/v1/task_validation_test.go +++ b/pkg/apis/pipeline/v1/task_validation_test.go @@ -528,8 +528,7 @@ func TestTaskSpecStepActionReferenceValidate(t *testing.T) { }{{ name: "valid stepaction ref", Steps: []v1.Step{{ - Name: "mystep", - WorkingDir: "/foo", + Name: "mystep", Ref: &v1.Ref{ Name: "stepAction", }, @@ -1536,6 +1535,18 @@ func TestTaskSpecValidateErrorWithStepActionRef(t *testing.T) { Message: "script cannot be used with Ref", Paths: []string{"steps[0].script"}, }, + }, { + name: "Cannot use workingDir with Ref", + Steps: []v1.Step{{ + Ref: &v1.Ref{ + Name: "stepAction", + }, + WorkingDir: "/workspace", + }}, + expectedError: apis.FieldError{ + Message: "working dir cannot be used with Ref", + Paths: []string{"steps[0].workingDir"}, + }, }, { name: "Cannot use env with Ref", Steps: []v1.Step{{ diff --git a/pkg/apis/pipeline/v1alpha1/openapi_generated.go b/pkg/apis/pipeline/v1alpha1/openapi_generated.go index 3426a815b7f..99ad0a618f6 100644 --- a/pkg/apis/pipeline/v1alpha1/openapi_generated.go +++ b/pkg/apis/pipeline/v1alpha1/openapi_generated.go @@ -829,6 +829,13 @@ func schema_pkg_apis_pipeline_v1alpha1_StepActionSpec(ref common.ReferenceCallba Format: "", }, }, + "workingDir": { + SchemaProps: spec.SchemaProps{ + Description: "Step's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.", + Type: []string{"string"}, + Format: "", + }, + }, "params": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ diff --git a/pkg/apis/pipeline/v1alpha1/stepaction_types.go b/pkg/apis/pipeline/v1alpha1/stepaction_types.go index 4209f1de4ca..faee28dc2e5 100644 --- a/pkg/apis/pipeline/v1alpha1/stepaction_types.go +++ b/pkg/apis/pipeline/v1alpha1/stepaction_types.go @@ -112,6 +112,12 @@ type StepActionSpec struct { // If Script is not empty, the Step cannot have an Command and the Args will be passed to the Script. // +optional Script string `json:"script,omitempty"` + // Step's working directory. + // If not specified, the container runtime's default will be used, which + // might be configured in the container image. + // Cannot be updated. + // +optional + WorkingDir string `json:"workingDir,omitempty" protobuf:"bytes,5,opt,name=workingDir"` // Params is a list of input parameters required to run the stepAction. // Params must be supplied as inputs in Steps unless they declare a defaultvalue. // +optional diff --git a/pkg/apis/pipeline/v1alpha1/swagger.json b/pkg/apis/pipeline/v1alpha1/swagger.json index 4423cb8c3cb..8aeabcc9c43 100644 --- a/pkg/apis/pipeline/v1alpha1/swagger.json +++ b/pkg/apis/pipeline/v1alpha1/swagger.json @@ -457,6 +457,10 @@ "x-kubernetes-list-type": "atomic", "x-kubernetes-patch-merge-key": "mountPath", "x-kubernetes-patch-strategy": "merge" + }, + "workingDir": { + "description": "Step's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.", + "type": "string" } } }, diff --git a/pkg/apis/pipeline/v1beta1/task_validation.go b/pkg/apis/pipeline/v1beta1/task_validation.go index b87039a600e..574812867bc 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation.go +++ b/pkg/apis/pipeline/v1beta1/task_validation.go @@ -341,6 +341,12 @@ func validateStep(ctx context.Context, s Step, names sets.String) (errs *apis.Fi Paths: []string{"script"}, }) } + if s.WorkingDir != "" { + errs = errs.Also(&apis.FieldError{ + Message: "working dir cannot be used with Ref", + Paths: []string{"workingDir"}, + }) + } if s.Env != nil { errs = errs.Also(&apis.FieldError{ Message: "env cannot be used with Ref", diff --git a/pkg/apis/pipeline/v1beta1/task_validation_test.go b/pkg/apis/pipeline/v1beta1/task_validation_test.go index 1b60c14f6ca..117cccf0dbc 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/task_validation_test.go @@ -532,8 +532,7 @@ func TestTaskSpecStepActionReferenceValidate(t *testing.T) { }{{ name: "valid stepaction ref", Steps: []v1beta1.Step{{ - Name: "mystep", - WorkingDir: "/foo", + Name: "mystep", Ref: &v1beta1.Ref{ Name: "stepAction", }, @@ -1549,6 +1548,18 @@ func TestTaskSpecValidateErrorWithStepActionRef(t *testing.T) { Message: "script cannot be used with Ref", Paths: []string{"steps[0].script"}, }, + }, { + name: "Cannot use workingDir with Ref", + Steps: []v1beta1.Step{{ + Ref: &v1beta1.Ref{ + Name: "stepAction", + }, + WorkingDir: "/workspace", + }}, + expectedError: apis.FieldError{ + Message: "working dir cannot be used with Ref", + Paths: []string{"steps[0].workingDir"}, + }, }, { name: "Cannot use env with Ref", Steps: []v1beta1.Step{{ diff --git a/pkg/reconciler/taskrun/resources/taskspec.go b/pkg/reconciler/taskrun/resources/taskspec.go index 255dc399c58..9b9e14174d5 100644 --- a/pkg/reconciler/taskrun/resources/taskspec.go +++ b/pkg/reconciler/taskrun/resources/taskspec.go @@ -125,6 +125,7 @@ func GetStepActionsData(ctx context.Context, taskSpec v1.TaskSpec, taskRun *v1.T if stepActionSpec.Script != "" { s.Script = stepActionSpec.Script } + s.WorkingDir = stepActionSpec.WorkingDir if stepActionSpec.Env != nil { s.Env = stepActionSpec.Env } diff --git a/pkg/reconciler/taskrun/resources/taskspec_test.go b/pkg/reconciler/taskrun/resources/taskspec_test.go index 1a3479a47ad..7e1d90b69c4 100644 --- a/pkg/reconciler/taskrun/resources/taskspec_test.go +++ b/pkg/reconciler/taskrun/resources/taskspec_test.go @@ -321,8 +321,7 @@ func TestGetStepActionsData(t *testing.T) { Ref: &v1.Ref{ Name: "stepAction", }, - WorkingDir: "/bar", - Timeout: &metav1.Duration{Duration: time.Hour}, + Timeout: &metav1.Duration{Duration: time.Hour}, }}, }, }, @@ -343,11 +342,10 @@ func TestGetStepActionsData(t *testing.T) { }, }, want: []v1.Step{{ - Image: "myimage", - Command: []string{"ls"}, - Args: []string{"-lh"}, - WorkingDir: "/bar", - Timeout: &metav1.Duration{Duration: time.Hour}, + Image: "myimage", + Command: []string{"ls"}, + Args: []string{"-lh"}, + Timeout: &metav1.Duration{Duration: time.Hour}, VolumeMounts: []corev1.VolumeMount{{ Name: "$(params.foo)", MountPath: "/path", @@ -469,8 +467,7 @@ func TestGetStepActionsData(t *testing.T) { Ref: &v1.Ref{ Name: "stepAction", }, - WorkingDir: "/bar", - Timeout: &metav1.Duration{Duration: time.Hour}, + Timeout: &metav1.Duration{Duration: time.Hour}, }, { Image: "foo", Command: []string{"ls"}, @@ -490,11 +487,10 @@ func TestGetStepActionsData(t *testing.T) { }, }, want: []v1.Step{{ - Image: "myimage", - Command: []string{"ls"}, - Args: []string{"-lh"}, - WorkingDir: "/bar", - Timeout: &metav1.Duration{Duration: time.Hour}, + Image: "myimage", + Command: []string{"ls"}, + Args: []string{"-lh"}, + Timeout: &metav1.Duration{Duration: time.Hour}, }, { Image: "foo", Command: []string{"ls"}, diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go index 5148ac1b9d6..dcd38ad1ff6 100644 --- a/pkg/reconciler/taskrun/taskrun_test.go +++ b/pkg/reconciler/taskrun/taskrun_test.go @@ -2942,7 +2942,6 @@ spec: - ref: name: stepAction name: step1 - workingDir: /foo - ref: name: stepAction2 name: step2 @@ -2993,7 +2992,6 @@ spec: Image: "myImage", Command: []string{"ls"}, Name: "step1", - WorkingDir: "/foo", SecurityContext: &corev1.SecurityContext{Privileged: &securityContextPrivileged}, }, { Image: "myImage",