1
0
mirror of https://github.com/go-task/task.git synced 2024-12-04 10:24:45 +02:00

Allow vars in dotenv paths, including environment variables

Closes #453
Closes #434
Ref #433

Co-authored-by: Andrey Nering <andrey@nering.com.br>
This commit is contained in:
Nicolas Fouché 2021-06-05 15:54:10 -03:00 committed by Andrey Nering
parent cded9af90f
commit 08265ed1d7
14 changed files with 165 additions and 28 deletions

View File

@ -78,18 +78,25 @@ setting:
KEYNAME=VALUE
```
```
# testing/.env
ENDPOINT=testing.com
```
```yaml
# Taskfile.yml
version: '3'
dotenv: ['.env']
env:
ENV: testing
dotenv: ['.env', '{{.ENV}}/.env.', '{{.HOME}}/.env']
tasks:
greet:
cmds:
- echo "Using $KEYNAME"
- echo "Using $KEYNAME and endpoint $ENDPOINT"
```
## Including other Taskfiles

View File

@ -7,6 +7,7 @@ import (
// Compiler handles compilation of a task before its execution.
// E.g. variable merger, template processing, etc.
type Compiler interface {
GetTaskfileVariables() (*taskfile.Vars, error)
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
HandleDynamicVar(v taskfile.Var, dir string) (string, error)

View File

@ -30,6 +30,10 @@ type CompilerV2 struct {
muDynamicCache sync.Mutex
}
func (c *CompilerV2) GetTaskfileVariables() (*taskfile.Vars, error) {
return &taskfile.Vars{}, nil
}
// FastGetVariables is a no-op on v2
func (c *CompilerV2) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
return c.GetVariables(t, call)

View File

@ -29,17 +29,23 @@ type CompilerV3 struct {
muDynamicCache sync.Mutex
}
func (c *CompilerV3) GetTaskfileVariables() (*taskfile.Vars, error) {
return c.getVariables(nil, nil, true)
}
func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
return c.getVariables(t, call, true)
return c.getVariables(t, &call, true)
}
func (c *CompilerV3) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
return c.getVariables(t, call, false)
return c.getVariables(t, &call, false)
}
func (c *CompilerV3) getVariables(t *taskfile.Task, call taskfile.Call, evaluateShVars bool) (*taskfile.Vars, error) {
func (c *CompilerV3) getVariables(t *taskfile.Task, call *taskfile.Call, evaluateShVars bool) (*taskfile.Vars, error) {
result := compiler.GetEnviron()
result.Set("TASK", taskfile.Var{Static: t.Task})
if t != nil {
result.Set("TASK", taskfile.Var{Static: t.Task})
}
getRangeFunc := func(dir string) func(k string, v taskfile.Var) error {
return func(k string, v taskfile.Var) error {
@ -74,6 +80,11 @@ func (c *CompilerV3) getVariables(t *taskfile.Task, call taskfile.Call, evaluate
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
return nil, err
}
if t == nil || call == nil {
return result, nil
}
if err := call.Vars.Range(rangeFunc); err != nil {
return nil, err
}

17
task.go
View File

@ -176,6 +176,23 @@ func (e *Executor) Setup() error {
}
}
if v >= 3.0 {
env, err := read.Dotenv(e.Compiler, e.Taskfile, e.Dir)
if err != nil {
return err
}
err = env.Range(func(key string, value taskfile.Var) error {
if _, ok := e.Taskfile.Env.Mapping[key]; !ok {
e.Taskfile.Env.Set(key, value)
}
return nil
})
if err != nil {
return err
}
}
if v < 2.1 && e.Taskfile.Output != "" {
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
}

View File

@ -904,6 +904,44 @@ func TestDotenvShouldAllowMissingEnv(t *testing.T) {
tt.Run(t)
}
func TestDotenvHasLocalEnvInPath(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/dotenv/local_env_in_path",
Target: "default",
TrimSpace: false,
Files: map[string]string{
"var.txt": "VAR='var_in_dot_env_1'\n",
},
}
tt.Run(t)
}
func TestDotenvHasLocalVarInPath(t *testing.T) {
tt := fileContentTest{
Dir: "testdata/dotenv/local_var_in_path",
Target: "default",
TrimSpace: false,
Files: map[string]string{
"var.txt": "VAR='var_in_dot_env_3'\n",
},
}
tt.Run(t)
}
func TestDotenvHasEnvVarInPath(t *testing.T) {
os.Setenv("ENV_VAR", "testing")
tt := fileContentTest{
Dir: "testdata/dotenv/env_var_in_path",
Target: "default",
TrimSpace: false,
Files: map[string]string{
"var.txt": "VAR='var_in_dot_env_2'\n",
},
}
tt.Run(t)
}
func TestExitImmediately(t *testing.T) {
const dir = "testdata/exit_immediately"

46
taskfile/read/dotenv.go Normal file
View File

@ -0,0 +1,46 @@
package read
import (
"os"
"path/filepath"
"github.com/joho/godotenv"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
func Dotenv(c compiler.Compiler, tf *taskfile.Taskfile, dir string) (*taskfile.Vars, error) {
vars, err := c.GetTaskfileVariables()
if err != nil {
return nil, err
}
env := &taskfile.Vars{}
tr := templater.Templater{Vars: vars, RemoveNoValue: true}
for _, dotEnvPath := range tf.Dotenv {
dotEnvPath = tr.Replace(dotEnvPath)
if !filepath.IsAbs(dotEnvPath) {
dotEnvPath = filepath.Join(dir, dotEnvPath)
}
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
continue
}
envs, err := godotenv.Read(dotEnvPath)
if err != nil {
return nil, err
}
for key, value := range envs {
if _, ok := env.Mapping[key]; !ok {
env.Set(key, taskfile.Var{Static: value})
}
}
}
return env, nil
}

View File

@ -7,7 +7,6 @@ import (
"path/filepath"
"runtime"
"github.com/joho/godotenv"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/internal/templater"
@ -37,27 +36,6 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
return nil, err
}
if v >= 3.0 {
for _, dotEnvPath := range t.Dotenv {
if !filepath.IsAbs(dotEnvPath) {
dotEnvPath = filepath.Join(dir, dotEnvPath)
}
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
continue
}
envs, err := godotenv.Read(dotEnvPath)
if err != nil {
return nil, err
}
for key, value := range envs {
if _, ok := t.Env.Mapping[key]; !ok {
t.Env.Set(key, taskfile.Var{Static: value})
}
}
}
}
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
if v >= 3.0 {
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}

View File

@ -0,0 +1 @@
VAR_IN_DOTENV=var_in_dot_env_2

View File

@ -0,0 +1,8 @@
version: "3"
dotenv: [".env.{{.ENV_VAR}}"]
tasks:
default:
cmds:
- echo "VAR='$VAR_IN_DOTENV'" > var.txt

View File

@ -0,0 +1 @@
VAR_IN_DOTENV=var_in_dot_env_1

View File

@ -0,0 +1,11 @@
version: "3"
env:
LOCAL_ENV: testing
dotenv: [".env.{{.LOCAL_ENV}}"]
tasks:
default:
cmds:
- echo "VAR='$VAR_IN_DOTENV'" > var.txt

View File

@ -0,0 +1 @@
VAR_IN_DOTENV=var_in_dot_env_3

View File

@ -0,0 +1,13 @@
version: "3"
vars:
PART_1: test
PART_2: ing
LOCAL_VAR: "{{.PART_1}}{{.PART_2}}"
dotenv: [".env.{{.LOCAL_VAR}}"]
tasks:
default:
cmds:
- echo "VAR='$VAR_IN_DOTENV'" > var.txt