diff --git a/docs/docs/20-usage/20-pipeline-syntax.md b/docs/docs/20-usage/20-pipeline-syntax.md index 6f9b1a9bf..45c96c31c 100644 --- a/docs/docs/20-usage/20-pipeline-syntax.md +++ b/docs/docs/20-usage/20-pipeline-syntax.md @@ -502,6 +502,10 @@ Woodpecker gives the ability to detach steps to run them in background until the For more details check the [service docs](./60-services.md#detachment). +### `directory` + +Using `directory`, you can set a subdirectory of your repository or an absolute path inside the Docker container in which your commands will run. + ## `services` Woodpecker can provide service containers. They can for example be used to run databases or cache containers during the execution of pipeline. diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index 343a7a748..63557f2d9 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -3,6 +3,7 @@ package compiler import ( "fmt" "path" + "path/filepath" "strings" "github.com/rs/zerolog/log" @@ -68,7 +69,7 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section } if !detached || len(container.Commands) != 0 { - workingdir = path.Join(c.base, c.path) + workingdir = c.stepWorkdir(container) } if !detached { @@ -184,3 +185,10 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section IpcMode: ipcMode, } } + +func (c *Compiler) stepWorkdir(container *yaml.Container) string { + if filepath.IsAbs(container.Directory) { + return container.Directory + } + return filepath.Join(c.base, c.path, container.Directory) +} diff --git a/pipeline/frontend/yaml/container.go b/pipeline/frontend/yaml/container.go index 247063aa8..29c07711b 100644 --- a/pipeline/frontend/yaml/container.go +++ b/pipeline/frontend/yaml/container.go @@ -37,6 +37,7 @@ type ( Tmpfs []string `yaml:"tmpfs,omitempty"` DNS types.Stringorslice `yaml:"dns,omitempty"` DNSSearch types.Stringorslice `yaml:"dns_search,omitempty"` + Directory string `yaml:"directory,omitempty"` Entrypoint types.Command `yaml:"entrypoint,omitempty"` Environment types.SliceorMap `yaml:"environment,omitempty"` ExtraHosts []string `yaml:"extra_hosts,omitempty"` diff --git a/pipeline/frontend/yaml/container_test.go b/pipeline/frontend/yaml/container_test.go index da7c67f78..239101b21 100644 --- a/pipeline/frontend/yaml/container_test.go +++ b/pipeline/frontend/yaml/container_test.go @@ -27,6 +27,7 @@ cpu_shares: 99 detach: true devices: - /dev/ttyUSB0:/dev/ttyUSB0 +directory: example/ dns: 8.8.8.8 dns_search: example.com entrypoint: /code/entrypoint.sh @@ -81,6 +82,7 @@ func TestUnmarshalContainer(t *testing.T) { CPUShares: types.StringorInt(99), Detached: true, Devices: []string{"/dev/ttyUSB0:/dev/ttyUSB0"}, + Directory: "example/", DNS: types.Stringorslice{"8.8.8.8"}, DNSSearch: types.Stringorslice{"example.com"}, Entrypoint: types.Command{"/code/entrypoint.sh"}, diff --git a/pipeline/schema/schema.json b/pipeline/schema/schema.json index a7e9d356d..947803561 100644 --- a/pipeline/schema/schema.json +++ b/pipeline/schema/schema.json @@ -215,6 +215,9 @@ "environment": { "$ref": "#/definitions/step_environment" }, + "directory": { + "$ref": "#/definitions/step_directory" + }, "secrets": { "$ref": "#/definitions/step_secrets" }, @@ -467,6 +470,10 @@ "items": { "type": "string" }, "minLength": 1 }, + "step_directory": { + "description": "Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#directory", + "type": "string" + }, "services": { "description": "Read more: https://woodpecker-ci.org/docs/usage/services", "type": "object",