diff --git a/CHANGELOG.md b/CHANGELOG.md index 83a2aeb2c0..f332efc4df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,12 @@ - On Windows, Task can now be installed using [Scoop](https://scoop.sh/) ([#152](https://github.com/go-task/task/pull/152)); - Fixes issue with file/directory globing - ([#153](https://github.com/go-task/task/issues/153)). + ([#153](https://github.com/go-task/task/issues/153)); +- Add ability to globally set environment variables + ( + [#138](https://github.com/go-task/task/pull/138), + [#159](https://github.com/go-task/task/pull/159) + ). ## v2.2.1 - 2018-12-09 diff --git a/docs/installation.md b/docs/installation.md index d7c65cd1ed..94adf560ac 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -72,7 +72,7 @@ Both methods requires having the [Go][go] environment properly setup locally. ## Install script We also have a [install script][installscript], which is very useful on -scanarios like CIs. Many thanks to [godownloader][godownloader] for allowing +scenarios like CIs. Many thanks to [godownloader][godownloader] for allowing easily generating this script. ```bash diff --git a/docs/usage.md b/docs/usage.md index 7f37e53443..88ea1e807b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -31,23 +31,41 @@ interpreter. So you can write sh/bash commands and it will work even on Windows, where `sh` or `bash` are usually not available. Just remember any executable called must be available by the OS or in PATH. -If you ommit a task name, "default" will be assumed. +If you omit a task name, "default" will be assumed. ## Environment -You can specify environment variables that are added when running a command: +You can use `env` to set custom environment variables for a specific task: ```yaml version: '2' tasks: - build: + greet: cmds: - - echo $hallo + - echo $GREETING env: - hallo: welt + GREETING: Hey, there! ``` +Additionally, you can set globally environment variables, that'll be available +to all tasks: + +```yaml +version: '2' + +env: + GREETING: Hey, there! + +tasks: + greet: + cmds: + - echo $GREETING +``` + +> NOTE: `env` supports expansion and and retrieving output from a shell command +> just like variables, as you can see on the [Variables](#variables) section. + ## Operating System specific tasks If you add a `Taskfile_{{GOOS}}.yml` you can override or amend your Taskfile @@ -455,7 +473,7 @@ Task also adds the following functions: - `catLines`: Replaces Unix (\n) and Windows (\r\n) styled newlines with a space. - `toSlash`: Does nothing on Unix, but on Windows converts a string from `\` path format to `/`. -- `fromSlash`: Oposite of `toSlash`. Does nothing on Unix, but on Windows +- `fromSlash`: Opposite of `toSlash`. Does nothing on Unix, but on Windows converts a string from `\` path format to `/`. - `exeExt`: Returns the right executable extension for the current OS (`".exe"` for Windows, `""` for others). @@ -488,7 +506,7 @@ tasks: ## Help Running `task --list` (or `task -l`) lists all tasks with a description. -The following taskfile: +The following Taskfile: ```yaml version: '2' @@ -575,7 +593,7 @@ tasks: * Or globally with `--silent` or `-s` flag -If you want to suppress stdout instead, just redirect a command to `/dev/null`: +If you want to suppress STDOUT instead, just redirect a command to `/dev/null`: ```yaml version: '2' diff --git a/internal/taskfile/merge.go b/internal/taskfile/merge.go index b2b32ef948..e862fe7aa7 100644 --- a/internal/taskfile/merge.go +++ b/internal/taskfile/merge.go @@ -35,6 +35,13 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error { t1.Vars[k] = v } + if t1.Env == nil { + t1.Env = make(Vars) + } + for k, v := range t2.Vars { + t1.Env[k] = v + } + if t1.Tasks == nil { t1.Tasks = make(Tasks) } diff --git a/internal/taskfile/taskfile.go b/internal/taskfile/taskfile.go index 58311aabc8..b3869fbd0e 100644 --- a/internal/taskfile/taskfile.go +++ b/internal/taskfile/taskfile.go @@ -7,6 +7,7 @@ type Taskfile struct { Output string Includes map[string]string Vars Vars + Env Vars Tasks Tasks } @@ -23,6 +24,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { Output string Includes map[string]string Vars Vars + Env Vars Tasks Tasks } if err := unmarshal(&taskfile); err != nil { @@ -33,6 +35,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { tf.Output = taskfile.Output tf.Includes = taskfile.Includes tf.Vars = taskfile.Vars + tf.Env = taskfile.Env tf.Tasks = taskfile.Tasks if tf.Expansions <= 0 { tf.Expansions = 2 diff --git a/task.go b/task.go index d9d90a902a..9de7d88c01 100644 --- a/task.go +++ b/task.go @@ -268,9 +268,9 @@ func getEnviron(t *taskfile.Task) []string { return nil } - envs := os.Environ() + environ := os.Environ() for k, v := range t.Env.ToStringMap() { - envs = append(envs, fmt.Sprintf("%s=%s", k, v)) + environ = append(environ, fmt.Sprintf("%s=%s", k, v)) } - return envs + return environ } diff --git a/task_test.go b/task_test.go index e4dbd766f6..02f7b0ff86 100644 --- a/task_test.go +++ b/task_test.go @@ -61,7 +61,8 @@ func TestEnv(t *testing.T) { Target: "default", TrimSpace: false, Files: map[string]string{ - "env.txt": "GOOS='linux' GOARCH='amd64' CGO_ENABLED='0'\n", + "local.txt": "GOOS='linux' GOARCH='amd64' CGO_ENABLED='0'\n", + "global.txt": "FOO='foo' BAR='overriden' BAZ='baz'\n", }, } tt.Run(t) diff --git a/testdata/env/.gitignore b/testdata/env/.gitignore index 7a7d633f14..2211df63dd 100644 --- a/testdata/env/.gitignore +++ b/testdata/env/.gitignore @@ -1 +1 @@ -env.txt +*.txt diff --git a/testdata/env/Taskfile.yml b/testdata/env/Taskfile.yml index 9aab4252d6..d5a7419db2 100644 --- a/testdata/env/Taskfile.yml +++ b/testdata/env/Taskfile.yml @@ -1,10 +1,33 @@ -default: - vars: - AMD64: amd64 - env: - GOOS: linux - GOARCH: "{{.AMD64}}" - CGO_ENABLED: - sh: echo '0' - cmds: - - echo "GOOS='$GOOS' GOARCH='$GOARCH' CGO_ENABLED='$CGO_ENABLED'" > env.txt +version: '2' + +vars: + BAZ: + sh: echo baz + +env: + FOO: foo + BAR: bar + BAZ: "{{.BAZ}}" + +tasks: + default: + cmds: + - task: local + - task: global + + local: + vars: + AMD64: amd64 + env: + GOOS: linux + GOARCH: "{{.AMD64}}" + CGO_ENABLED: + sh: echo '0' + cmds: + - echo "GOOS='$GOOS' GOARCH='$GOARCH' CGO_ENABLED='$CGO_ENABLED'" > local.txt + + global: + env: + BAR: overriden + cmds: + - echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" > global.txt diff --git a/variables.go b/variables.go index bdbf52e51c..8e3600732b 100644 --- a/variables.go +++ b/variables.go @@ -30,7 +30,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { Status: r.ReplaceSlice(origTask.Status), Dir: r.Replace(origTask.Dir), Vars: nil, - Env: r.ReplaceVars(origTask.Env), + Env: nil, Silent: origTask.Silent, Method: r.Replace(origTask.Method), Prefix: r.Replace(origTask.Prefix), @@ -46,6 +46,14 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { if new.Prefix == "" { new.Prefix = new.Task } + + new.Env = make(taskfile.Vars, len(e.Taskfile.Env)+len(origTask.Env)) + for k, v := range r.ReplaceVars(e.Taskfile.Env) { + new.Env[k] = v + } + for k, v := range r.ReplaceVars(origTask.Env) { + new.Env[k] = v + } for k, v := range new.Env { static, err := e.Compiler.HandleDynamicVar(v) if err != nil {