From 6e0af0b0580624281ae95450af5ef76e98ebe72f Mon Sep 17 00:00:00 2001 From: Marc Cataford Date: Mon, 12 Aug 2024 00:34:17 -0400 Subject: [PATCH] feat: add working-directory and job-level default workdir to workflow --- internal/workflow/models.go | 31 ++++++++++++- internal/workflow/models_test.go | 80 ++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 internal/workflow/models_test.go diff --git a/internal/workflow/models.go b/internal/workflow/models.go index 04d0db4..00950eb 100644 --- a/internal/workflow/models.go +++ b/internal/workflow/models.go @@ -9,7 +9,12 @@ type Job struct { Steps []Step `yaml:"steps"` Needs []string `yaml:"needs"` // Job name; this isn't guaranteed to be unique. - Name string `yaml:"name"` + Name string `yaml:"name"` + Defaults struct { + Run struct { + WorkingDirectory string `yaml:"working-directory"` + } `yaml:"run"` + } `yaml:"defaults"` } func (j Job) Validate() []error { @@ -31,7 +36,8 @@ func (j Job) Validate() []error { } type Step struct { - Run string `yaml:"run"` + Run string `yaml:"run"` + WorkingDirectory string `yaml:"working-directory"` } func (s Step) Validate() []error { @@ -49,6 +55,27 @@ type Workflow struct { Jobs map[string]Job `yaml:"jobs"` } +// Returns the given workflow's job+step working directory inside the container +// that runs the job. +// +// Values considered, in order: +// - Step working-directory; +// - Job default run working-directory +func (w Workflow) GetWorkingDirectory(jobName string, stepIndex int) string { + jobDefinition := w.Jobs[jobName] + stepDefinition := jobDefinition.Steps[stepIndex] + + if stepDefinition.WorkingDirectory != "" { + return stepDefinition.WorkingDirectory + } + + if jobDefinition.Defaults.Run.WorkingDirectory != "" { + return jobDefinition.Defaults.Run.WorkingDirectory + } + + return "." +} + func (w Workflow) Validate() []error { validationErrors := []error{} diff --git a/internal/workflow/models_test.go b/internal/workflow/models_test.go new file mode 100644 index 0000000..8a541be --- /dev/null +++ b/internal/workflow/models_test.go @@ -0,0 +1,80 @@ +package workflow + +import ( + "testing" +) + +func TestWorkingDirectoryDefaultsToCurrentDirectory(t *testing.T) { + sample := ` +jobs: + jobA: + runs-on: default + steps: + - run: echo "test" + ` + + workflow, _ := FromYamlBytes([]byte(sample)) + workDir := workflow.GetWorkingDirectory("jobA", 0) + if workDir != "." { + t.Errorf("Expected current directory as working directory, got %s", workDir) + } +} + +func TestWorkingDirectoryUsesStepDefault(t *testing.T) { + sample := ` +jobs: + jobA: + runs-on: default + steps: + - run: echo "test" + working-directory: ./test + ` + + workflow, _ := FromYamlBytes([]byte(sample)) + workDir := workflow.GetWorkingDirectory("jobA", 0) + if workDir != "./test" { + t.Errorf("Expected current directory as ./test working directory, got %s", workDir) + } +} + +func TestWorkingDirectoryUsesJobDefaultsIfNoStepDefault(t *testing.T) { + sample := ` + +jobs: + jobA: + runs-on: default + defaults: + run: + working-directory: ./test-job + steps: + - run: echo "test" + ` + + workflow, _ := FromYamlBytes([]byte(sample)) + workDir := workflow.GetWorkingDirectory("jobA", 0) + if workDir != "./test-job" { + t.Errorf("Expected current directory as ./test working directory, got %s", workDir) + } +} + +func TestWorkingDirectoryFromStepOverridesJobDefault(t *testing.T) { + sample := ` + +jobs: + jobA: + runs-on: default + defaults: + run: + working-directory: ./test-job + steps: + - run: echo "test" + working-directory: ./test-step + ` + + workflow, _ := FromYamlBytes([]byte(sample)) + workDir := workflow.GetWorkingDirectory("jobA", 0) + if workDir != "./test-step" { + t.Errorf("Expected current directory as ./test working directory, got %s", workDir) + } + +}