mirror of
https://github.com/go-task/task.git
synced 2026-06-24 21:26:04 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
239e61e718 | ||
|
|
22549e9fd8 | ||
|
|
1f9fd24064 | ||
|
|
a7594740e3 | ||
|
|
945c72cf6c | ||
|
|
824b0c0132 | ||
|
|
51e9f2f579 | ||
|
|
e8ec33d9d0 | ||
|
|
3bbbaf12fd | ||
|
|
30ffacd879 | ||
|
|
75e9b7791c | ||
|
|
4b665ab19a | ||
|
|
08265ed1d7 | ||
|
|
58c69e36a1 |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +1,2 @@
|
|||||||
open_collective: task
|
open_collective: task
|
||||||
patreon: andreynering
|
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=USD&source=url'
|
||||||
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=BRL&source=url'
|
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v3.6.0 - 2021-07-10
|
||||||
|
|
||||||
|
- Allow using both `sources:` and `status:` in the same task
|
||||||
|
([#411](https://github.com/go-task/task/issues/411), [#427](https://github.com/go-task/task/issues/427), [#477](https://github.com/go-task/task/pull/477)).
|
||||||
|
- Small optimization and bug fix: don't compute variables if not needed for
|
||||||
|
`dotenv:` ([#517](https://github.com/go-task/task/issues/517)).
|
||||||
|
|
||||||
|
## v3.5.0 - 2021-07-04
|
||||||
|
|
||||||
|
- Add support for interpolation in `dotenv:`
|
||||||
|
([#433](https://github.com/go-task/task/discussions/433), [#434](https://github.com/go-task/task/issues/434), [#453](https://github.com/go-task/task/pull/453)).
|
||||||
|
|
||||||
## v3.4.3 - 2021-05-30
|
## v3.4.3 - 2021-05-30
|
||||||
|
|
||||||
- Add support for the `NO_COLOR` environment variable.
|
- Add support for the `NO_COLOR` environment variable.
|
||||||
|
|||||||
@@ -14,22 +14,14 @@ these options to donate:
|
|||||||
- [$2 per month](https://opencollective.com/task/contribute/backer-4034/checkout)
|
- [$2 per month](https://opencollective.com/task/contribute/backer-4034/checkout)
|
||||||
- [$5 per month](https://opencollective.com/task/contribute/supporter-8404/checkout)
|
- [$5 per month](https://opencollective.com/task/contribute/supporter-8404/checkout)
|
||||||
- [$20 per month](https://opencollective.com/task/contribute/sponsor-4035/checkout)
|
- [$20 per month](https://opencollective.com/task/contribute/sponsor-4035/checkout)
|
||||||
|
- [$50 per month](https://opencollective.com/task/contribute/sponsor-28775/checkout)
|
||||||
- [Custom value - One-time donation option supported](https://opencollective.com/task/donate)
|
- [Custom value - One-time donation option supported](https://opencollective.com/task/donate)
|
||||||
|
|
||||||
## Patreon
|
|
||||||
|
|
||||||
I'm also on [Patreon](https://www.patreon.com/andreynering) if
|
|
||||||
you prefer:
|
|
||||||
|
|
||||||
- [$5 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229277)
|
|
||||||
- [$10 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229276)
|
|
||||||
- [$15 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229275)
|
|
||||||
|
|
||||||
You can choose a custom value on any of the links above.
|
|
||||||
|
|
||||||
Patreon does not support one-time donation. As a workaround you can fire a
|
|
||||||
subscription and cancel it once the donation was succeded.
|
|
||||||
|
|
||||||
## PayPal
|
## PayPal
|
||||||
|
|
||||||
- [Any value - One-time donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=BRL&source=url)
|
- [Any value - One-time donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=USD&source=url)
|
||||||
|
|
||||||
|
## PIX (Brazil only)
|
||||||
|
|
||||||
|
If you're Brazilian, you can donate any value by
|
||||||
|
<a href="/pix.png" target="_blank">using this QR Code</a>.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="description" content="A task runner / simpler Make alternative written in Go">
|
<meta name="description" content="A task runner / simpler Make alternative written in Go">
|
||||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css">
|
||||||
<meta name="google-site-verification" content="VGAYkbdmuaciIDGkBe-eAg9yfZg0C6ostgonbGxxOa0" />
|
<meta name="google-site-verification" content="VGAYkbdmuaciIDGkBe-eAg9yfZg0C6ostgonbGxxOa0" />
|
||||||
<style>
|
<style>
|
||||||
#logo {
|
#logo {
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify-themeable/dist/js/docsify-themeable.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify-themeable/dist/js/docsify-themeable.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify-tabs"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify-tabs"></script>
|
||||||
|
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-yaml.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-yaml.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
BIN
docs/pix.png
Normal file
BIN
docs/pix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -78,18 +78,25 @@ setting:
|
|||||||
KEYNAME=VALUE
|
KEYNAME=VALUE
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# testing/.env
|
||||||
|
ENDPOINT=testing.com
|
||||||
|
```
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Taskfile.yml
|
# Taskfile.yml
|
||||||
|
|
||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
dotenv: ['.env']
|
env:
|
||||||
|
ENV: testing
|
||||||
|
|
||||||
|
dotenv: ['.env', '{{.ENV}}/.env.', '{{.HOME}}/.env']
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
greet:
|
greet:
|
||||||
cmds:
|
cmds:
|
||||||
- echo "Using $KEYNAME"
|
- echo "Using $KEYNAME and endpoint $ENDPOINT"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Including other Taskfiles
|
## Including other Taskfiles
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
// Compiler handles compilation of a task before its execution.
|
// Compiler handles compilation of a task before its execution.
|
||||||
// E.g. variable merger, template processing, etc.
|
// E.g. variable merger, template processing, etc.
|
||||||
type Compiler interface {
|
type Compiler interface {
|
||||||
|
GetTaskfileVariables() (*taskfile.Vars, error)
|
||||||
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
|
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
|
||||||
FastGetVariables(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)
|
HandleDynamicVar(v taskfile.Var, dir string) (string, error)
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ type CompilerV2 struct {
|
|||||||
muDynamicCache sync.Mutex
|
muDynamicCache sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CompilerV2) GetTaskfileVariables() (*taskfile.Vars, error) {
|
||||||
|
return &taskfile.Vars{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FastGetVariables is a no-op on v2
|
// FastGetVariables is a no-op on v2
|
||||||
func (c *CompilerV2) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
func (c *CompilerV2) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||||
return c.GetVariables(t, call)
|
return c.GetVariables(t, call)
|
||||||
@@ -105,7 +109,7 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, _ string) (string, error)
|
|||||||
Stderr: c.Logger.Stderr,
|
Stderr: c.Logger.Stderr,
|
||||||
}
|
}
|
||||||
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
||||||
return "", fmt.Errorf(`task: Command "%s" in taskvars file failed: %s`, opts.Command, err)
|
return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim a single trailing newline from the result to make most command
|
// Trim a single trailing newline from the result to make most command
|
||||||
|
|||||||
@@ -29,17 +29,23 @@ type CompilerV3 struct {
|
|||||||
muDynamicCache sync.Mutex
|
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) {
|
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) {
|
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 := 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 {
|
getRangeFunc := func(dir string) func(k string, v taskfile.Var) error {
|
||||||
return 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 {
|
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t == nil || call == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := call.Vars.Range(rangeFunc); err != nil {
|
if err := call.Vars.Range(rangeFunc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -125,7 +136,7 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var, dir string) (string, error
|
|||||||
Stderr: c.Logger.Stderr,
|
Stderr: c.Logger.Stderr,
|
||||||
}
|
}
|
||||||
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
||||||
return "", fmt.Errorf(`task: Command "%s" in taskvars file failed: %s`, opts.Command, err)
|
return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim a single trailing newline from the result to make most command
|
// Trim a single trailing newline from the result to make most command
|
||||||
|
|||||||
29
status.go
29
status.go
@@ -29,16 +29,35 @@ func (e *Executor) Status(ctx context.Context, calls ...taskfile.Call) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool, error) {
|
func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool, error) {
|
||||||
|
if len(t.Status) == 0 && len(t.Sources) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
if len(t.Status) > 0 {
|
if len(t.Status) > 0 {
|
||||||
return e.isTaskUpToDateStatus(ctx, t)
|
isUpToDate, err := e.isTaskUpToDateStatus(ctx, t)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !isUpToDate {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checker, err := e.getStatusChecker(t)
|
if len(t.Sources) > 0 {
|
||||||
if err != nil {
|
checker, err := e.getStatusChecker(t)
|
||||||
return false, err
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
isUpToDate, err := checker.IsUpToDate()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !isUpToDate {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return checker.IsUpToDate()
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) statusOnError(t *taskfile.Task) error {
|
func (e *Executor) statusOnError(t *taskfile.Task) error {
|
||||||
|
|||||||
17
task.go
17
task.go
@@ -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 != "" {
|
if v < 2.1 && e.Taskfile.Output != "" {
|
||||||
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
||||||
}
|
}
|
||||||
|
|||||||
80
task_test.go
80
task_test.go
@@ -252,12 +252,18 @@ func TestDeps(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatus(t *testing.T) {
|
func TestStatus(t *testing.T) {
|
||||||
const dir = "testdata/status"
|
const dir = "testdata/status"
|
||||||
var file = filepath.Join(dir, "foo.txt")
|
|
||||||
|
|
||||||
_ = os.Remove(file)
|
files := []string{
|
||||||
|
"foo.txt",
|
||||||
|
"bar.txt",
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
for _, f := range files {
|
||||||
t.Errorf("File should not exist: %v", err)
|
path := filepath.Join(dir, f)
|
||||||
|
_ = os.Remove(path)
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
t.Errorf("File should not exist: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
@@ -269,17 +275,33 @@ func TestStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.NoError(t, e.Setup())
|
assert.NoError(t, e.Setup())
|
||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||||
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
for _, f := range files {
|
||||||
t.Errorf("File should exist: %v", err)
|
if _, err := os.Stat(filepath.Join(dir, f)); err != nil {
|
||||||
|
t.Errorf("File should exist: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Silent = false
|
e.Silent = false
|
||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
|
||||||
|
|
||||||
if buff.String() != `task: Task "gen-foo" is up to date`+"\n" {
|
// all: not up-to-date
|
||||||
t.Errorf("Wrong output message: %s", buff.String())
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||||
}
|
assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
// status: not up-to-date
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||||
|
assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
|
||||||
|
// sources: not up-to-date
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||||
|
assert.Equal(t, "task: [gen-bar] touch bar.txt", strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
// all: up-to-date
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||||
|
assert.Equal(t, `task: Task "gen-bar" is up to date`, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrecondition(t *testing.T) {
|
func TestPrecondition(t *testing.T) {
|
||||||
@@ -904,6 +926,44 @@ func TestDotenvShouldAllowMissingEnv(t *testing.T) {
|
|||||||
tt.Run(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) {
|
func TestExitImmediately(t *testing.T) {
|
||||||
const dir = "testdata/exit_immediately"
|
const dir = "testdata/exit_immediately"
|
||||||
|
|
||||||
|
|||||||
50
taskfile/read/dotenv.go
Normal file
50
taskfile/read/dotenv.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
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) {
|
||||||
|
if len(tf.Dotenv) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
@@ -37,27 +36,6 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
|
|||||||
return nil, err
|
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 {
|
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
|
||||||
if v >= 3.0 {
|
if v >= 3.0 {
|
||||||
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
|
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
|
||||||
|
|||||||
1
testdata/dotenv/env_var_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/env_var_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VAR_IN_DOTENV=var_in_dot_env_2
|
||||||
8
testdata/dotenv/env_var_in_path/Taskfile.yml
vendored
Normal file
8
testdata/dotenv/env_var_in_path/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
dotenv: [".env.{{.ENV_VAR}}"]
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- echo "VAR='$VAR_IN_DOTENV'" > var.txt
|
||||||
1
testdata/dotenv/local_env_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/local_env_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VAR_IN_DOTENV=var_in_dot_env_1
|
||||||
11
testdata/dotenv/local_env_in_path/Taskfile.yml
vendored
Normal file
11
testdata/dotenv/local_env_in_path/Taskfile.yml
vendored
Normal 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
|
||||||
1
testdata/dotenv/local_var_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/local_var_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VAR_IN_DOTENV=var_in_dot_env_3
|
||||||
13
testdata/dotenv/local_var_in_path/Taskfile.yml
vendored
Normal file
13
testdata/dotenv/local_var_in_path/Taskfile.yml
vendored
Normal 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
|
||||||
12
testdata/status/Taskfile.yml
vendored
12
testdata/status/Taskfile.yml
vendored
@@ -4,5 +4,15 @@ tasks:
|
|||||||
gen-foo:
|
gen-foo:
|
||||||
cmds:
|
cmds:
|
||||||
- touch foo.txt
|
- touch foo.txt
|
||||||
|
sources:
|
||||||
|
- ./foo.txt
|
||||||
status:
|
status:
|
||||||
- test -f foo.txt
|
- test 1 = 0
|
||||||
|
|
||||||
|
gen-bar:
|
||||||
|
cmds:
|
||||||
|
- touch bar.txt
|
||||||
|
sources:
|
||||||
|
- ./bar.txt
|
||||||
|
status:
|
||||||
|
- test 1 = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user