Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: experiment taskfile envs take precedence over os envs #1633

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions internal/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ import (
"fmt"
"os"

"github.com/go-task/task/v3/internal/experiments"
"github.com/go-task/task/v3/taskfile/ast"
)

func Get(t *ast.Task) []string {
if t.Env == nil {
return nil
}

environ := os.Environ()
for k, v := range t.Env.ToCacheMap() {
if !isTypeAllowed(v) {
continue
}

if _, alreadySet := os.LookupEnv(k); alreadySet {
continue
if !experiments.EnvPrecedence.Enabled {
if _, alreadySet := os.LookupEnv(k); alreadySet {
continue
}
}
environ = append(environ, fmt.Sprintf("%s=%v", k, v))
}
Expand Down
3 changes: 3 additions & 0 deletions internal/experiments/experiments.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var (
RemoteTaskfiles Experiment
AnyVariables Experiment
MapVariables Experiment
EnvPrecedence Experiment
)

func init() {
Expand All @@ -37,6 +38,7 @@ func init() {
RemoteTaskfiles = New("REMOTE_TASKFILES")
AnyVariables = New("ANY_VARIABLES", "1", "2")
MapVariables = New("MAP_VARIABLES", "1", "2")
EnvPrecedence = New("ENV_PRECEDENCE")
}

func New(xName string, enabledValues ...string) Experiment {
Expand Down Expand Up @@ -104,5 +106,6 @@ func List(l *logger.Logger) error {
printExperiment(w, l, GentleForce)
printExperiment(w, l, RemoteTaskfiles)
printExperiment(w, l, MapVariables)
printExperiment(w, l, EnvPrecedence)
return w.Flush()
}
17 changes: 15 additions & 2 deletions task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/go-task/task/v3"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/experiments"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/taskfile/ast"
)
Expand Down Expand Up @@ -60,7 +61,6 @@ func (fct fileContentTest) Run(t *testing.T) {
for f := range fct.Files {
_ = os.Remove(filepathext.SmartJoin(fct.Dir, f))
}

e := &task.Executor{
Dir: fct.Dir,
TempDir: task.TempDir{
Expand All @@ -71,9 +71,9 @@ func (fct fileContentTest) Run(t *testing.T) {
Stdout: io.Discard,
Stderr: io.Discard,
}

require.NoError(t, e.Setup(), "e.Setup()")
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: fct.Target}), "e.Run(target)")

for name, expectContent := range fct.Files {
t.Run(fct.name(name), func(t *testing.T) {
path := filepathext.SmartJoin(e.Dir, name)
Expand Down Expand Up @@ -108,6 +108,7 @@ func TestEmptyTaskfile(t *testing.T) {
}

func TestEnv(t *testing.T) {
t.Setenv("QUX", "from_os")
tt := fileContentTest{
Dir: "testdata/env",
Target: "default",
Expand All @@ -116,9 +117,21 @@ func TestEnv(t *testing.T) {
"local.txt": "GOOS='linux' GOARCH='amd64' CGO_ENABLED='0'\n",
"global.txt": "FOO='foo' BAR='overriden' BAZ='baz'\n",
"multiple_type.txt": "FOO='1' BAR='true' BAZ='1.1'\n",
"not-overriden.txt": "QUX='from_os'\n",
},
}
tt.Run(t)
t.Setenv("TASK_X_ENV_PRECEDENCE", "1")
experiments.EnvPrecedence = experiments.New("ENV_PRECEDENCE")
ttt := fileContentTest{
Dir: "testdata/env",
Target: "overriden",
TrimSpace: false,
Files: map[string]string{
"overriden.txt": "QUX='from_taskfile'\n",
},
}
ttt.Run(t)
}

func TestVars(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions testdata/env/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ env:
FOO: foo
BAR: bar
BAZ: "{{.BAZ}}"
QUX: from_taskfile

tasks:
default:
cmds:
- task: local
- task: global
- task: not-overriden
- task: multiple_type

local:
Expand All @@ -40,3 +42,11 @@ tasks:
BAZ: 1.1
cmds:
- echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" > multiple_type.txt

not-overriden:
cmds:
- echo "QUX='$QUX'" > not-overriden.txt

overriden:
cmds:
- echo "QUX='$QUX'" > overriden.txt
70 changes: 70 additions & 0 deletions website/docs/experiments/env_precedence.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
draft: false # Hide in production
slug: '/experiments/env-precedence'
---

# Env Precedence (#1038)

:::caution

All experimental features are subject to breaking changes and/or removal _at any
time_. We strongly recommend that you do not use these features in a production
environment. They are intended for testing and feedback only.

:::

:::warning

This experiment breaks the following functionality:

- environment variable will take precedence over OS environment variables

:::

:::info

To enable this experiment, set the environment variable: `TASK_X_ENV_PRECEDENCE=1`.
Check out [our guide to enabling experiments ][enabling-experiments] for more
information.

:::

Before this experiment, the OS variable took precedence over the task environment variable. This experiment changes the precedence to make the task environment variable take precedence over the OS variable.

Consider the following example:

```yml
version: '3'

tasks:
default:
env:
KEY: 'other'
cmds:
- echo "$KEY"
```
Running `KEY=some task` before this experiment, the output would be `some`, but after this experiment, the output would be `other`.

If you still want to get the OS variable, you can use the template function env like follow : `{{env "OS_VAR"}}`.

```yml
version: '3'

tasks:
default:
env:
KEY: 'other'
cmds:
- echo "$KEY"
- echo {{env "KEY"}}
```
Running `KEY=some task`, the output would be `other` and `some`.

Like other variables/envs, you can also fall back to a given value using the default template function:
```yml
MY_ENV: '{{.MY_ENV | default "fallback"}}'
```

{/* prettier-ignore-start */}
[enabling-experiments]: ./experiments.mdx#enabling-experiments
{/* prettier-ignore-end */}
Loading