diff --git a/task_test.go b/task_test.go index f991f163..31710445 100644 --- a/task_test.go +++ b/task_test.go @@ -829,7 +829,7 @@ func TestShortTaskNotation(t *testing.T) { func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) { tt := fileContentTest{ - Dir: "testdata/dotenv", + Dir: "testdata/dotenv/default", Target: "default", TrimSpace: false, Files: map[string]string{ @@ -839,26 +839,9 @@ func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) { tt.Run(t) } -func TestDotenvShouldErrorWithIncludeEnvPath(t *testing.T) { - const dir = "testdata/dotenv" - const entry = "Taskfile-errors1.yml" - - var buff bytes.Buffer - e := task.Executor{ - Dir: dir, - Entrypoint: entry, - Summary: true, - Stdout: &buff, - Stderr: &buff, - } - err := e.Setup() - assert.Error(t, err) - assert.Contains(t, err.Error(), "no such file") -} - func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) { - const dir = "testdata/dotenv" - const entry = "Taskfile-errors2.yml" + const dir = "testdata/dotenv/error_included_envs" + const entry = "Taskfile.yml" var buff bytes.Buffer e := task.Executor{ @@ -873,3 +856,15 @@ func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "move the dotenv") } + +func TestDotenvShouldAllowMissingEnv(t *testing.T) { + tt := fileContentTest{ + Dir: "testdata/dotenv/missing_env", + Target: "default", + TrimSpace: false, + Files: map[string]string{ + "include.txt": "INCLUDE1='' INCLUDE2=''\n", + }, + } + tt.Run(t) +} diff --git a/taskfile/read/taskfile.go b/taskfile/read/taskfile.go index e333feb7..e483c0cb 100644 --- a/taskfile/read/taskfile.go +++ b/taskfile/read/taskfile.go @@ -42,14 +42,18 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { if !filepath.IsAbs(dotEnvPath) { dotEnvPath = filepath.Join(dir, dotEnvPath) } - 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}) + // allow for missing env files since they may be created by a bootstrap task + if _, err := os.Stat(dotEnvPath); !os.IsNotExist(err) { + 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}) + } + } + } else { } } } diff --git a/testdata/dotenv/Taskfile-errors1.yml b/testdata/dotenv/default/Taskfile.yml similarity index 55% rename from testdata/dotenv/Taskfile-errors1.yml rename to testdata/dotenv/default/Taskfile.yml index 8551f165..f33195d1 100644 --- a/testdata/dotenv/Taskfile-errors1.yml +++ b/testdata/dotenv/default/Taskfile.yml @@ -1,8 +1,8 @@ version: '3' -dotenv: ['include1/.env', 'include1/envs/.env', 'file-does-not-exist'] +dotenv: ['../include1/.env', '../include1/envs/.env'] tasks: default: cmds: - - echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include-errors1.txt + - echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include.txt diff --git a/testdata/dotenv/Taskfile-errors2.yml b/testdata/dotenv/error_included_envs/Taskfile.yml similarity index 83% rename from testdata/dotenv/Taskfile-errors2.yml rename to testdata/dotenv/error_included_envs/Taskfile.yml index 7da25c5e..62230188 100644 --- a/testdata/dotenv/Taskfile-errors2.yml +++ b/testdata/dotenv/error_included_envs/Taskfile.yml @@ -1,7 +1,7 @@ version: '3' includes: - include1: './include1' + include1: '../include1' tasks: default: diff --git a/testdata/dotenv/Taskfile.yml b/testdata/dotenv/missing_env/Taskfile.yml similarity index 70% rename from testdata/dotenv/Taskfile.yml rename to testdata/dotenv/missing_env/Taskfile.yml index f4b775fc..865ab6dd 100644 --- a/testdata/dotenv/Taskfile.yml +++ b/testdata/dotenv/missing_env/Taskfile.yml @@ -1,6 +1,6 @@ version: '3' -dotenv: ['include1/.env', 'include1/envs/.env'] +dotenv: ['.env'] tasks: default: