mirror of
https://github.com/go-task/task.git
synced 2026-06-27 14:44:19 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cad318b70 | ||
|
|
8c6002cae6 | ||
|
|
0355bbaf3b | ||
|
|
2ba083a650 | ||
|
|
c79ea5a257 | ||
|
|
44706f4957 | ||
|
|
a1b3bb03ed | ||
|
|
76caa16909 | ||
|
|
160b788198 | ||
|
|
eada62f62c | ||
|
|
bd9419e6db | ||
|
|
bdd9de3001 | ||
|
|
200ba4ed04 | ||
|
|
1e8939dd58 | ||
|
|
f45dd11e53 | ||
|
|
1a0cc1d64d | ||
|
|
421cb522d9 | ||
|
|
1b18b041d6 | ||
|
|
8788703ac6 | ||
|
|
b6c25e3ad9 | ||
|
|
73eaa68cd1 | ||
|
|
beb927f7b4 | ||
|
|
cdc969cd4e | ||
|
|
2a67499f12 | ||
|
|
6a3cc79daa | ||
|
|
97d4a947ee | ||
|
|
e0e47ad9a0 | ||
|
|
b08eac58e9 | ||
|
|
c2148a359d | ||
|
|
c172185a24 | ||
|
|
1140a5c4ae | ||
|
|
3cc378c960 | ||
|
|
9b3a961303 | ||
|
|
d048555149 | ||
|
|
7533858a52 | ||
|
|
c4e10ef0aa | ||
|
|
c20842e7cd |
@@ -17,6 +17,9 @@ build:
|
|||||||
goarch: 386
|
goarch: 386
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
|
flags:
|
||||||
|
- -trimpath
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w # Don't set main.version.
|
- -s -w # Don't set main.version.
|
||||||
|
|
||||||
|
|||||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,5 +1,25 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v3.15.2 - 2022-09-08
|
||||||
|
|
||||||
|
- Fix error when using variable in `env:` introduced in the previous release
|
||||||
|
([#858](https://github.com/go-task/task/issues/858), [#866](https://github.com/go-task/task/pull/866)).
|
||||||
|
- Fix handling of `CLI_ARGS` (`--`) in Bash completion
|
||||||
|
([#863](https://github.com/go-task/task/pull/863)).
|
||||||
|
- On zsh completion, add ability to replace `--list-all` with `--list` as
|
||||||
|
already possible on the Bash completion
|
||||||
|
([#861](https://github.com/go-task/task/pull/861)).
|
||||||
|
|
||||||
|
## v3.15.0 - 2022-09-03
|
||||||
|
|
||||||
|
- Add new special variables `ROOT_DIR` and `TASKFILE_DIR`. This was a highly
|
||||||
|
requested feature
|
||||||
|
([#215](https://github.com/go-task/task/issues/215), [#857](https://github.com/go-task/task/pull/857), [Documentation](https://taskfile.dev/api/#special-variables)).
|
||||||
|
- Follow symlinks on `sources`
|
||||||
|
([#826](https://github.com/go-task/task/issues/826), [#831](https://github.com/go-task/task/pull/831)).
|
||||||
|
- Improvements and fixes to Bash completion
|
||||||
|
([#835](https://github.com/go-task/task/pull/835), [#844](https://github.com/go-task/task/pull/844)).
|
||||||
|
|
||||||
## v3.14.1 - 2022-08-03
|
## v3.14.1 - 2022-08-03
|
||||||
|
|
||||||
- Always resolve relative include paths relative to the including Taskfile
|
- Always resolve relative include paths relative to the including Taskfile
|
||||||
|
|||||||
13
Taskfile.yml
13
Taskfile.yml
@@ -80,6 +80,19 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- goreleaser --snapshot --rm-dist
|
- goreleaser --snapshot --rm-dist
|
||||||
|
|
||||||
|
docs:changelog:
|
||||||
|
desc: Copy CHANGELOG.md to the documentation website
|
||||||
|
vars:
|
||||||
|
FILE: docs/docs/changelog.md
|
||||||
|
cmds:
|
||||||
|
- rm {{.FILE}}
|
||||||
|
- 'echo "---" >> {{.FILE}}'
|
||||||
|
- 'echo "slug: /changelog/" >> {{.FILE}}'
|
||||||
|
- 'echo "sidebar_position: 6" >> {{.FILE}}'
|
||||||
|
- 'echo "---" >> {{.FILE}}'
|
||||||
|
- 'echo "" >> {{.FILE}}'
|
||||||
|
- 'cat CHANGELOG.md >> {{.FILE}}'
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
cmds:
|
cmds:
|
||||||
- echo '{{.GO_PACKAGES}}'
|
- echo '{{.GO_PACKAGES}}'
|
||||||
|
|||||||
@@ -1,26 +1,55 @@
|
|||||||
#!/bin/bash
|
# vim: set tabstop=2 shiftwidth=2 expandtab:
|
||||||
|
|
||||||
GO_TASK_PROGNAME=task
|
_GO_TASK_COMPLETION_LIST_OPTION='--list-all'
|
||||||
|
|
||||||
_go_task_completion()
|
function _task()
|
||||||
{
|
{
|
||||||
local cur
|
local cur prev words cword
|
||||||
_get_comp_words_by_ref -n : cur
|
_init_completion -n : || return
|
||||||
|
|
||||||
case "$cur" in
|
# Check for `--` within command-line and quit or strip suffix.
|
||||||
--*)
|
local i
|
||||||
local options
|
for i in "${!words[@]}"; do
|
||||||
options="$(_parse_help task)"
|
if [ "${words[$i]}" == "--" ]; then
|
||||||
mapfile -t COMPREPLY < <(compgen -W "$options" -- "$cur")
|
# Do not complete words following `--` passed to CLI_ARGS.
|
||||||
|
[ $cword -gt $i ] && return
|
||||||
|
# Remove the words following `--` to not put --list in CLI_ARGS.
|
||||||
|
words=( "${words[@]:0:$i}" )
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Handle special arguments of options.
|
||||||
|
case "$prev" in
|
||||||
|
-d|--dir)
|
||||||
|
_filedir -d
|
||||||
|
return $?
|
||||||
;;
|
;;
|
||||||
*)
|
-t|--taskfile)
|
||||||
local tasks
|
_filedir yaml || return $?
|
||||||
tasks="$($GO_TASK_PROGNAME --list-all 2> /dev/null | awk 'NR>1 { sub(/:$/,"",$2); print $2 }')"
|
_filedir yml
|
||||||
mapfile -t COMPREPLY < <(compgen -W "$tasks" -- "$cur")
|
return $?
|
||||||
|
;;
|
||||||
|
-o|--output)
|
||||||
|
COMPREPLY=( $( compgen -W "interleaved group prefixed" -- $cur ) )
|
||||||
|
return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Handle normal options.
|
||||||
|
case "$cur" in
|
||||||
|
-*)
|
||||||
|
COMPREPLY=( $( compgen -W "$(_parse_help $1)" -- $cur ) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Prepare task name completions.
|
||||||
|
local tasks=( $( "${words[@]}" --silent $_GO_TASK_COMPLETION_LIST_OPTION 2> /dev/null ) )
|
||||||
|
COMPREPLY=( $( compgen -W "${tasks[*]}" -- "$cur" ) )
|
||||||
|
|
||||||
|
# Post-process because task names might contain colons.
|
||||||
__ltrim_colon_completions "$cur"
|
__ltrim_colon_completions "$cur"
|
||||||
}
|
}
|
||||||
|
|
||||||
complete -F _go_task_completion $GO_TASK_PROGNAME
|
complete -F _task task
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
local context state state_descr line
|
local context state state_descr line
|
||||||
typeset -A opt_args
|
typeset -A opt_args
|
||||||
|
|
||||||
|
_GO_TASK_COMPLETION_LIST_OPTION="${GO_TASK_COMPLETION_LIST_OPTION:---list-all}"
|
||||||
|
|
||||||
# Listing commands from Taskfile.yml
|
# Listing commands from Taskfile.yml
|
||||||
function __task_list() {
|
function __task_list() {
|
||||||
local -a scripts cmd
|
local -a scripts cmd
|
||||||
@@ -27,7 +29,7 @@ function __task_list() {
|
|||||||
(( enabled )) || return 0
|
(( enabled )) || return 0
|
||||||
|
|
||||||
scripts=()
|
scripts=()
|
||||||
for item in "${(@)${(f)$("${cmd[@]}" --list-all)}[2,-1]#\* }"; do
|
for item in "${(@)${(f)$("${cmd[@]}" $_GO_TASK_COMPLETION_LIST_OPTION)}[2,-1]#\* }"; do
|
||||||
task="${item%%:[[:space:]]*}"
|
task="${item%%:[[:space:]]*}"
|
||||||
desc="${item##[^[:space:]]##[[:space:]]##}"
|
desc="${item##[^[:space:]]##[[:space:]]##}"
|
||||||
scripts+=( "${task//:/\\:}:$desc" )
|
scripts+=( "${task//:/\\:}:$desc" )
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ tasks:
|
|||||||
start:
|
start:
|
||||||
desc: Start website
|
desc: Start website
|
||||||
vars:
|
vars:
|
||||||
|
HOST: '{{default "localhost" .HOST}}'
|
||||||
PORT: '{{default "3001" .PORT}}'
|
PORT: '{{default "3001" .PORT}}'
|
||||||
cmds:
|
cmds:
|
||||||
- npx docusaurus start --no-open --port={{.PORT}}
|
- npx docusaurus start --no-open --host={{.HOST}} --port={{.PORT}}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
desc: Build website
|
desc: Build website
|
||||||
|
|||||||
@@ -44,6 +44,19 @@ variable
|
|||||||
| | `--version` | `bool` | `false` | Show Task version. |
|
| | `--version` | `bool` | `false` | Show Task version. |
|
||||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
|
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
|
||||||
|
|
||||||
|
## Special Variables
|
||||||
|
|
||||||
|
There are some special variables that is available on the templating system:
|
||||||
|
|
||||||
|
| Var | Description |
|
||||||
|
| - | - |
|
||||||
|
| `CLI_ARGS` | Contain all extra arguments passed after `--` when calling Task through the CLI. |
|
||||||
|
| `TASK` | The name of the current task. |
|
||||||
|
| `ROOT_DIR` | The absolute path of the root Taskfile. |
|
||||||
|
| `TASKFILE_DIR` | The absolute path of the included Taskfile. |
|
||||||
|
| `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. |
|
||||||
|
| `TIMESTAMP` | The date object of the greatest timestamp of the files listes in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |
|
||||||
|
|
||||||
## ENV
|
## ENV
|
||||||
|
|
||||||
Some environment variables can be overriden to adjust Task behavior.
|
Some environment variables can be overriden to adjust Task behavior.
|
||||||
|
|||||||
@@ -5,6 +5,34 @@ sidebar_position: 6
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v3.15.2 - 2022-09-08
|
||||||
|
|
||||||
|
- Fix error when using variable in `env:` introduced in the previous release
|
||||||
|
([#858](https://github.com/go-task/task/issues/858), [#866](https://github.com/go-task/task/pull/866)).
|
||||||
|
- Fix handling of `CLI_ARGS` (`--`) in Bash completion
|
||||||
|
([#863](https://github.com/go-task/task/pull/863)).
|
||||||
|
- On zsh completion, add ability to replace `--list-all` with `--list` as
|
||||||
|
already possible on the Bash completion
|
||||||
|
([#861](https://github.com/go-task/task/pull/861)).
|
||||||
|
|
||||||
|
## v3.15.0 - 2022-09-03
|
||||||
|
|
||||||
|
- Add new special variables `ROOT_DIR` and `TASKFILE_DIR`. This was a highly
|
||||||
|
requested feature
|
||||||
|
([#215](https://github.com/go-task/task/issues/215), [#857](https://github.com/go-task/task/pull/857), [Documentation](https://taskfile.dev/api/#special-variables)).
|
||||||
|
- Follow symlinks on `sources`
|
||||||
|
([#826](https://github.com/go-task/task/issues/826), [#831](https://github.com/go-task/task/pull/831)).
|
||||||
|
- Improvements and fixes to Bash completion
|
||||||
|
([#835](https://github.com/go-task/task/pull/835), [#844](https://github.com/go-task/task/pull/844)).
|
||||||
|
|
||||||
|
## v3.14.1 - 2022-08-03
|
||||||
|
|
||||||
|
- Always resolve relative include paths relative to the including Taskfile
|
||||||
|
([#822](https://github.com/go-task/task/issues/822), [#823](https://github.com/go-task/task/pull/823)).
|
||||||
|
- Fix ZSH and PowerShell completions to consider all tasks instead of just the
|
||||||
|
public ones (those with descriptions)
|
||||||
|
([#803](https://github.com/go-task/task/pull/803)).
|
||||||
|
|
||||||
## v3.14.0 - 2022-07-08
|
## v3.14.0 - 2022-07-08
|
||||||
|
|
||||||
- Add ability to override the `.task` directory location with the
|
- Add ability to override the `.task` directory location with the
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ guide to check the full schema documentation and Task features.
|
|||||||
`$PATH` and you're done! Or you can also install using [Homebrew][homebrew],
|
`$PATH` and you're done! Or you can also install using [Homebrew][homebrew],
|
||||||
[Snapcraft][snapcraft], or [Scoop][scoop] if you want.
|
[Snapcraft][snapcraft], or [Scoop][scoop] if you want.
|
||||||
- Available on CIs: by adding [this simple command](installation.md#install-script)
|
- Available on CIs: by adding [this simple command](installation.md#install-script)
|
||||||
to install on your CI script and you're done to use Task as part of your CI pipeline;
|
to install on your CI script and you're ready to use Task as part of your CI pipeline;
|
||||||
- Truly cross-platform: while most build tools only work well on Linux or macOS,
|
- Truly cross-platform: while most build tools only work well on Linux or macOS,
|
||||||
Task also supports Windows thanks to [this shell interpreter for Go][sh].
|
Task also supports Windows thanks to [this shell interpreter for Go][sh].
|
||||||
- Great for code generation: you can easily [prevent a task from running](/usage#prevent-unnecessary-work)
|
- Great for code generation: you can easily [prevent a task from running](/usage#prevent-unnecessary-work)
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ the `test-release` task of the Taskfile.
|
|||||||
artifacts automatically when a new Git tag is pushed to master
|
artifacts automatically when a new Git tag is pushed to master
|
||||||
(raw executables and DEB and RPM packages).
|
(raw executables and DEB and RPM packages).
|
||||||
|
|
||||||
|
Since v3.15.0, raw executables can also be reproduced and verified locally by
|
||||||
|
checking out a specific tag and calling `goreleaser build`, using the Go version
|
||||||
|
defined in the above GitHub Actions.
|
||||||
|
|
||||||
# Homebrew
|
# Homebrew
|
||||||
|
|
||||||
To release a new version on the [Homebrew tap][homebrewtap] edit the
|
To release a new version on the [Homebrew tap][homebrewtap] edit the
|
||||||
@@ -31,9 +35,9 @@ the [Snapcraft dashboard][snapcraftdashboard].
|
|||||||
|
|
||||||
# Scoop
|
# Scoop
|
||||||
|
|
||||||
Scoop is a community owned installation method. Scoop owners usually take care
|
Scoop is a command-line package manager for the Windows operating system.
|
||||||
of updating versions there by editing
|
Scoop package manifests are maintained by the community.
|
||||||
[this file](https://github.com/lukesampson/scoop-extras/blob/master/bucket/task.json).
|
Scoop owners usually take care of updating versions there by editing [this file](https://github.com/lukesampson/scoop-extras/blob/master/bucket/task.json).
|
||||||
If you think its Task version is outdated, open an issue to let us know.
|
If you think its Task version is outdated, open an issue to let us know.
|
||||||
|
|
||||||
# Nix
|
# Nix
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&family=Roboto:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--ifm-font-family-base: Roboto, system-ui, -apple-system, Segoe UI, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
||||||
|
--ifm-font-family-monospace: 'Roboto Mono', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||||
|
|
||||||
--ifm-color-primary: #43ABA2 ;
|
--ifm-color-primary: #43ABA2 ;
|
||||||
--ifm-color-primary-dark: #3AB2A6;
|
--ifm-color-primary-dark: #3AB2A6;
|
||||||
--ifm-color-primary-darker: #32B8AB;
|
--ifm-color-primary-darker: #32B8AB;
|
||||||
@@ -11,13 +16,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
--ifm-color-primary: #43ABA2 ;
|
|
||||||
--ifm-color-primary-dark: #3AB2A6;
|
|
||||||
--ifm-color-primary-darker: #32B8AB;
|
|
||||||
--ifm-color-primary-darkest: #29BEB0;
|
|
||||||
--ifm-color-primary-light: #4CA59D;
|
|
||||||
--ifm-color-primary-lighter: #559F98;
|
|
||||||
--ifm-color-primary-lightest: #5D9993;
|
|
||||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
docs/static/img/favicon.ico
vendored
BIN
docs/static/img/favicon.ico
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 170 KiB |
@@ -17,7 +17,7 @@ type taskNotFoundError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err *taskNotFoundError) Error() string {
|
func (err *taskNotFoundError) Error() string {
|
||||||
return fmt.Sprintf(`task: Task "%s" not found`, err.taskName)
|
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskRunError struct {
|
type TaskRunError struct {
|
||||||
@@ -26,7 +26,7 @@ type TaskRunError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err *TaskRunError) Error() string {
|
func (err *TaskRunError) Error() string {
|
||||||
return fmt.Sprintf(`task: Failed to run task "%s": %v`, err.taskName, err.err)
|
return fmt.Sprintf(`task: Failed to run task %q: %v`, err.taskName, err.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *TaskRunError) ExitCode() int {
|
func (err *TaskRunError) ExitCode() int {
|
||||||
@@ -46,7 +46,7 @@ type MaximumTaskCallExceededError struct {
|
|||||||
|
|
||||||
func (e *MaximumTaskCallExceededError) Error() string {
|
func (e *MaximumTaskCallExceededError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`task: maximum task call exceeded (%d) for task "%s": probably an cyclic dep or infinite loop`,
|
`task: maximum task call exceeded (%d) for task %q: probably an cyclic dep or infinite loop`,
|
||||||
MaximumTaskCall,
|
MaximumTaskCall,
|
||||||
e.task,
|
e.task,
|
||||||
)
|
)
|
||||||
|
|||||||
7
init.go
7
init.go
@@ -4,7 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultTaskfile = `# https://taskfile.dev
|
const defaultTaskfile = `# https://taskfile.dev
|
||||||
@@ -23,13 +24,13 @@ tasks:
|
|||||||
|
|
||||||
// InitTaskfile Taskfile creates a new Taskfile
|
// InitTaskfile Taskfile creates a new Taskfile
|
||||||
func InitTaskfile(w io.Writer, dir string) error {
|
func InitTaskfile(w io.Writer, dir string) error {
|
||||||
f := filepath.Join(dir, "Taskfile.yaml")
|
f := filepathext.SmartJoin(dir, "Taskfile.yaml")
|
||||||
|
|
||||||
if _, err := os.Stat(f); err == nil {
|
if _, err := os.Stat(f); err == nil {
|
||||||
return ErrTaskfileAlreadyExists
|
return ErrTaskfileAlreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(f, []byte(defaultTaskfile), 0644); err != nil {
|
if err := os.WriteFile(f, []byte(defaultTaskfile), 0o644); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "Taskfile.yaml created in the current directory\n")
|
fmt.Fprintf(w, "Taskfile.yaml created in the current directory\n")
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/compiler"
|
"github.com/go-task/task/v3/internal/compiler"
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/logger"
|
"github.com/go-task/task/v3/internal/logger"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
@@ -44,7 +44,13 @@ func (c *CompilerV3) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*ta
|
|||||||
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()
|
||||||
if t != nil {
|
if t != nil {
|
||||||
result.Set("TASK", taskfile.Var{Static: t.Task})
|
specialVars, err := c.getSpecialVars(t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range specialVars {
|
||||||
|
result.Set(k, taskfile.Var{Static: v})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRangeFunc := func(dir string) func(k string, v taskfile.Var) error {
|
getRangeFunc := func(dir string) func(k string, v taskfile.Var) error {
|
||||||
@@ -83,9 +89,7 @@ func (c *CompilerV3) getVariables(t *taskfile.Task, call *taskfile.Call, evaluat
|
|||||||
if err := tr.Err(); err != nil {
|
if err := tr.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !filepath.IsAbs(dir) {
|
dir = filepathext.SmartJoin(c.Dir, dir)
|
||||||
dir = filepath.Join(c.Dir, dir)
|
|
||||||
}
|
|
||||||
taskRangeFunc = getRangeFunc(dir)
|
taskRangeFunc = getRangeFunc(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,3 +171,23 @@ func (c *CompilerV3) ResetCache() {
|
|||||||
|
|
||||||
c.dynamicCache = nil
|
c.dynamicCache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CompilerV3) getSpecialVars(t *taskfile.Task) (map[string]string, error) {
|
||||||
|
taskfileDir, err := c.getTaskfileDir(t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{
|
||||||
|
"TASK": t.Task,
|
||||||
|
"ROOT_DIR": c.Dir,
|
||||||
|
"TASKFILE_DIR": taskfileDir,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CompilerV3) getTaskfileDir(t *taskfile.Task) (string, error) {
|
||||||
|
if t.IncludedTaskfile != nil {
|
||||||
|
return t.IncludedTaskfile.FullDirPath()
|
||||||
|
}
|
||||||
|
return c.Dir, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func IsExitError(err error) bool {
|
|||||||
// if available.
|
// if available.
|
||||||
func Expand(s string) (string, error) {
|
func Expand(s string) (string, error) {
|
||||||
s = filepath.ToSlash(s)
|
s = filepath.ToSlash(s)
|
||||||
s = strings.Replace(s, " ", `\ `, -1)
|
s = strings.ReplaceAll(s, " ", `\ `)
|
||||||
fields, err := shell.Fields(s, nil)
|
fields, err := shell.Fields(s, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
14
internal/filepathext/filepathext.go
Normal file
14
internal/filepathext/filepathext.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package filepathext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SmartJoin joins two paths, but only if the second is not already an
|
||||||
|
// absolute path.
|
||||||
|
func SmartJoin(a, b string) string {
|
||||||
|
if filepath.IsAbs(b) {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return filepath.Join(a, b)
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checksum validades if a task is up to date by calculating its source
|
// Checksum validades if a task is up to date by calculating its source
|
||||||
@@ -43,8 +45,8 @@ func (c *Checksum) IsUpToDate() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !c.Dry {
|
if !c.Dry {
|
||||||
_ = os.MkdirAll(filepath.Join(c.TempDir, "checksum"), 0755)
|
_ = os.MkdirAll(filepathext.SmartJoin(c.TempDir, "checksum"), 0o755)
|
||||||
if err = os.WriteFile(checksumFile, []byte(newMd5+"\n"), 0644); err != nil {
|
if err = os.WriteFile(checksumFile, []byte(newMd5+"\n"), 0o644); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package status
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/mattn/go-zglob"
|
"github.com/mattn/go-zglob"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
)
|
)
|
||||||
|
|
||||||
func globs(dir string, globs []string) ([]string, error) {
|
func globs(dir string, globs []string) ([]string, error) {
|
||||||
@@ -25,17 +25,18 @@ func globs(dir string, globs []string) ([]string, error) {
|
|||||||
|
|
||||||
func Glob(dir string, g string) ([]string, error) {
|
func Glob(dir string, g string) ([]string, error) {
|
||||||
files := make([]string, 0)
|
files := make([]string, 0)
|
||||||
if !filepath.IsAbs(g) {
|
g = filepathext.SmartJoin(dir, g)
|
||||||
g = filepath.Join(dir, g)
|
|
||||||
}
|
|
||||||
g, err := execext.Expand(g)
|
g, err := execext.Expand(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fs, err := zglob.Glob(g)
|
|
||||||
|
fs, err := zglob.GlobFollowSymlinks(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
info, err := os.Stat(f)
|
info, err := os.Stat(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ func init() {
|
|||||||
"OS": func() string { return runtime.GOOS },
|
"OS": func() string { return runtime.GOOS },
|
||||||
"ARCH": func() string { return runtime.GOARCH },
|
"ARCH": func() string { return runtime.GOARCH },
|
||||||
"catLines": func(s string) string {
|
"catLines": func(s string) string {
|
||||||
s = strings.Replace(s, "\r\n", " ", -1)
|
s = strings.ReplaceAll(s, "\r\n", " ")
|
||||||
return strings.Replace(s, "\n", " ", -1)
|
return strings.ReplaceAll(s, "\n", " ")
|
||||||
},
|
},
|
||||||
"splitLines": func(s string) []string {
|
"splitLines": func(s string) []string {
|
||||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||||
return strings.Split(s, "\n")
|
return strings.Split(s, "\n")
|
||||||
},
|
},
|
||||||
"fromSlash": func(path string) string {
|
"fromSlash": func(path string) string {
|
||||||
|
|||||||
28
setup.go
28
setup.go
@@ -12,6 +12,7 @@ import (
|
|||||||
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
||||||
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
|
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/logger"
|
"github.com/go-task/task/v3/internal/logger"
|
||||||
"github.com/go-task/task/v3/internal/output"
|
"github.com/go-task/task/v3/internal/output"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
@@ -19,6 +20,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (e *Executor) Setup() error {
|
func (e *Executor) Setup() error {
|
||||||
|
if err := e.setCurrentDir(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := e.readTaskfile(); err != nil {
|
if err := e.readTaskfile(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -52,6 +57,23 @@ func (e *Executor) Setup() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Executor) setCurrentDir() error {
|
||||||
|
if e.Dir == "" {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.Dir = wd
|
||||||
|
} else if !filepath.IsAbs(e.Dir) {
|
||||||
|
abs, err := filepath.Abs(e.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.Dir = abs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Executor) readTaskfile() error {
|
func (e *Executor) readTaskfile() error {
|
||||||
var err error
|
var err error
|
||||||
e.Taskfile, err = read.Taskfile(&read.ReaderNode{
|
e.Taskfile, err = read.Taskfile(&read.ReaderNode{
|
||||||
@@ -69,7 +91,7 @@ func (e *Executor) setupTempDir() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if os.Getenv("TASK_TEMP_DIR") == "" {
|
if os.Getenv("TASK_TEMP_DIR") == "" {
|
||||||
e.TempDir = filepath.Join(e.Dir, ".task")
|
e.TempDir = filepathext.SmartJoin(e.Dir, ".task")
|
||||||
} else if filepath.IsAbs(os.Getenv("TASK_TEMP_DIR")) || strings.HasPrefix(os.Getenv("TASK_TEMP_DIR"), "~") {
|
} else if filepath.IsAbs(os.Getenv("TASK_TEMP_DIR")) || strings.HasPrefix(os.Getenv("TASK_TEMP_DIR"), "~") {
|
||||||
tempDir, err := execext.Expand(os.Getenv("TASK_TEMP_DIR"))
|
tempDir, err := execext.Expand(os.Getenv("TASK_TEMP_DIR"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,9 +99,9 @@ func (e *Executor) setupTempDir() error {
|
|||||||
}
|
}
|
||||||
projectDir, _ := filepath.Abs(e.Dir)
|
projectDir, _ := filepath.Abs(e.Dir)
|
||||||
projectName := filepath.Base(projectDir)
|
projectName := filepath.Base(projectDir)
|
||||||
e.TempDir = filepath.Join(tempDir, projectName)
|
e.TempDir = filepathext.SmartJoin(tempDir, projectName)
|
||||||
} else {
|
} else {
|
||||||
e.TempDir = filepath.Join(e.Dir, os.Getenv("TASK_TEMP_DIR"))
|
e.TempDir = filepathext.SmartJoin(e.Dir, os.Getenv("TASK_TEMP_DIR"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NOTE(@andreynering): This function intercepts SIGINT and SIGTERM signals
|
// NOTE(@andreynering): This function intercepts SIGINT and SIGTERM signals
|
||||||
// so the Task process is not killed immediatelly and processes running have
|
// so the Task process is not killed immediately and processes running have
|
||||||
// time to do cleanup work.
|
// time to do cleanup work.
|
||||||
func (e *Executor) InterceptInterruptSignals() {
|
func (e *Executor) InterceptInterruptSignals() {
|
||||||
ch := make(chan os.Signal, 3)
|
ch := make(chan os.Signal, 3)
|
||||||
|
|||||||
2
task.go
2
task.go
@@ -181,7 +181,7 @@ func (e *Executor) mkdir(t *taskfile.Task) error {
|
|||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
|
|
||||||
if _, err := os.Stat(t.Dir); os.IsNotExist(err) {
|
if _, err := os.Stat(t.Dir); os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(t.Dir, 0755); err != nil {
|
if err := os.MkdirAll(t.Dir, 0o755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
127
task_test.go
127
task_test.go
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/go-task/task/v3"
|
"github.com/go-task/task/v3"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,12 +38,12 @@ func (fct fileContentTest) name(file string) string {
|
|||||||
|
|
||||||
func (fct fileContentTest) Run(t *testing.T) {
|
func (fct fileContentTest) Run(t *testing.T) {
|
||||||
for f := range fct.Files {
|
for f := range fct.Files {
|
||||||
_ = os.Remove(filepath.Join(fct.Dir, f))
|
_ = os.Remove(filepathext.SmartJoin(fct.Dir, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &task.Executor{
|
e := &task.Executor{
|
||||||
Dir: fct.Dir,
|
Dir: fct.Dir,
|
||||||
TempDir: filepath.Join(fct.Dir, ".task"),
|
TempDir: filepathext.SmartJoin(fct.Dir, ".task"),
|
||||||
Entrypoint: fct.Entrypoint,
|
Entrypoint: fct.Entrypoint,
|
||||||
Stdout: io.Discard,
|
Stdout: io.Discard,
|
||||||
Stderr: io.Discard,
|
Stderr: io.Discard,
|
||||||
@@ -52,7 +53,7 @@ func (fct fileContentTest) Run(t *testing.T) {
|
|||||||
|
|
||||||
for name, expectContent := range fct.Files {
|
for name, expectContent := range fct.Files {
|
||||||
t.Run(fct.name(name), func(t *testing.T) {
|
t.Run(fct.name(name), func(t *testing.T) {
|
||||||
path := filepath.Join(fct.Dir, name)
|
path := filepathext.SmartJoin(fct.Dir, name)
|
||||||
b, err := os.ReadFile(path)
|
b, err := os.ReadFile(path)
|
||||||
assert.NoError(t, err, "Error reading file")
|
assert.NoError(t, err, "Error reading file")
|
||||||
s := string(b)
|
s := string(b)
|
||||||
@@ -163,6 +164,39 @@ func TestMultilineVars(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSpecialVars(t *testing.T) {
|
||||||
|
const dir = "testdata/special_vars"
|
||||||
|
const target = "default"
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := &task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
Silent: true,
|
||||||
|
}
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: target}))
|
||||||
|
|
||||||
|
toAbs := func(rel string) string {
|
||||||
|
abs, err := filepath.Abs(rel)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return abs
|
||||||
|
}
|
||||||
|
|
||||||
|
output := buff.String()
|
||||||
|
|
||||||
|
// Root Taskfile
|
||||||
|
assert.Contains(t, output, "root/TASK=print")
|
||||||
|
assert.Contains(t, output, "root/ROOT_DIR="+toAbs("testdata/special_vars"))
|
||||||
|
assert.Contains(t, output, "root/TASKFILE_DIR="+toAbs("testdata/special_vars"))
|
||||||
|
|
||||||
|
// Included Taskfile
|
||||||
|
assert.Contains(t, output, "included/TASK=included:print")
|
||||||
|
assert.Contains(t, output, "included/ROOT_DIR="+toAbs("testdata/special_vars"))
|
||||||
|
assert.Contains(t, output, "included/TASKFILE_DIR="+toAbs("testdata/special_vars/included"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestVarsInvalidTmpl(t *testing.T) {
|
func TestVarsInvalidTmpl(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
dir = "testdata/vars/v2"
|
dir = "testdata/vars/v2"
|
||||||
@@ -235,7 +269,7 @@ func TestDeps(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
_ = os.Remove(filepath.Join(dir, f))
|
_ = os.Remove(filepathext.SmartJoin(dir, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &task.Executor{
|
e := &task.Executor{
|
||||||
@@ -247,7 +281,7 @@ func TestDeps(t *testing.T) {
|
|||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
f = filepath.Join(dir, f)
|
f = filepathext.SmartJoin(dir, f)
|
||||||
if _, err := os.Stat(f); err != nil {
|
if _, err := os.Stat(f); err != nil {
|
||||||
t.Errorf("File %s should exist", f)
|
t.Errorf("File %s should exist", f)
|
||||||
}
|
}
|
||||||
@@ -263,7 +297,7 @@ func TestStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
path := filepath.Join(dir, f)
|
path := filepathext.SmartJoin(dir, f)
|
||||||
_ = os.Remove(path)
|
_ = os.Remove(path)
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
t.Errorf("File should not exist: %v", err)
|
t.Errorf("File should not exist: %v", err)
|
||||||
@@ -273,7 +307,7 @@ func TestStatus(t *testing.T) {
|
|||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := &task.Executor{
|
e := &task.Executor{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
TempDir: filepath.Join(dir, ".task"),
|
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||||
Stdout: &buff,
|
Stdout: &buff,
|
||||||
Stderr: &buff,
|
Stderr: &buff,
|
||||||
Silent: true,
|
Silent: true,
|
||||||
@@ -283,7 +317,7 @@ func TestStatus(t *testing.T) {
|
|||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if _, err := os.Stat(filepath.Join(dir, f)); err != nil {
|
if _, err := os.Stat(filepathext.SmartJoin(dir, f)); err != nil {
|
||||||
t.Errorf("File should exist: %v", err)
|
t.Errorf("File should exist: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,10 +394,10 @@ func TestGenerates(t *testing.T) {
|
|||||||
fileWithSpaces = "my text file.txt"
|
fileWithSpaces = "my text file.txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var srcFile = filepath.Join(dir, srcTask)
|
var srcFile = filepathext.SmartJoin(dir, srcTask)
|
||||||
|
|
||||||
for _, task := range []string{srcTask, relTask, absTask, fileWithSpaces} {
|
for _, task := range []string{srcTask, relTask, absTask, fileWithSpaces} {
|
||||||
path := filepath.Join(dir, task)
|
path := filepathext.SmartJoin(dir, task)
|
||||||
_ = os.Remove(path)
|
_ = os.Remove(path)
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
t.Errorf("File should not exist: %v", err)
|
t.Errorf("File should not exist: %v", err)
|
||||||
@@ -379,7 +413,7 @@ func TestGenerates(t *testing.T) {
|
|||||||
assert.NoError(t, e.Setup())
|
assert.NoError(t, e.Setup())
|
||||||
|
|
||||||
for _, theTask := range []string{relTask, absTask, fileWithSpaces} {
|
for _, theTask := range []string{relTask, absTask, fileWithSpaces} {
|
||||||
var destFile = filepath.Join(dir, theTask)
|
var destFile = filepathext.SmartJoin(dir, theTask)
|
||||||
var upToDate = fmt.Sprintf("task: Task \"%s\" is up to date\n", srcTask) +
|
var upToDate = fmt.Sprintf("task: Task \"%s\" is up to date\n", srcTask) +
|
||||||
fmt.Sprintf("task: Task \"%s\" is up to date\n", theTask)
|
fmt.Sprintf("task: Task \"%s\" is up to date\n", theTask)
|
||||||
|
|
||||||
@@ -416,16 +450,16 @@ func TestStatusChecksum(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
_ = os.Remove(filepath.Join(dir, f))
|
_ = os.Remove(filepathext.SmartJoin(dir, f))
|
||||||
|
|
||||||
_, err := os.Stat(filepath.Join(dir, f))
|
_, err := os.Stat(filepathext.SmartJoin(dir, f))
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.Executor{
|
e := task.Executor{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
TempDir: filepath.Join(dir, ".task"),
|
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||||
Stdout: &buff,
|
Stdout: &buff,
|
||||||
Stderr: &buff,
|
Stderr: &buff,
|
||||||
}
|
}
|
||||||
@@ -433,7 +467,7 @@ func TestStatusChecksum(t *testing.T) {
|
|||||||
|
|
||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build"}))
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build"}))
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
_, err := os.Stat(filepath.Join(dir, f))
|
_, err := os.Stat(filepathext.SmartJoin(dir, f))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,13 +611,13 @@ func TestListCanListDescOnly(t *testing.T) {
|
|||||||
func TestStatusVariables(t *testing.T) {
|
func TestStatusVariables(t *testing.T) {
|
||||||
const dir = "testdata/status_vars"
|
const dir = "testdata/status_vars"
|
||||||
|
|
||||||
_ = os.RemoveAll(filepath.Join(dir, ".task"))
|
_ = os.RemoveAll(filepathext.SmartJoin(dir, ".task"))
|
||||||
_ = os.Remove(filepath.Join(dir, "generated.txt"))
|
_ = os.Remove(filepathext.SmartJoin(dir, "generated.txt"))
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.Executor{
|
e := task.Executor{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
TempDir: filepath.Join(dir, ".task"),
|
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||||
Stdout: &buff,
|
Stdout: &buff,
|
||||||
Stderr: &buff,
|
Stderr: &buff,
|
||||||
Silent: false,
|
Silent: false,
|
||||||
@@ -594,7 +628,7 @@ func TestStatusVariables(t *testing.T) {
|
|||||||
|
|
||||||
assert.Contains(t, buff.String(), "d41d8cd98f00b204e9800998ecf8427e")
|
assert.Contains(t, buff.String(), "d41d8cd98f00b204e9800998ecf8427e")
|
||||||
|
|
||||||
inf, err := os.Stat(filepath.Join(dir, "source.txt"))
|
inf, err := os.Stat(filepathext.SmartJoin(dir, "source.txt"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
ts := fmt.Sprintf("%d", inf.ModTime().Unix())
|
ts := fmt.Sprintf("%d", inf.ModTime().Unix())
|
||||||
tf := inf.ModTime().String()
|
tf := inf.ModTime().String()
|
||||||
@@ -605,7 +639,7 @@ func TestStatusVariables(t *testing.T) {
|
|||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
const dir = "testdata/init"
|
const dir = "testdata/init"
|
||||||
var file = filepath.Join(dir, "Taskfile.yaml")
|
var file = filepathext.SmartJoin(dir, "Taskfile.yaml")
|
||||||
|
|
||||||
_ = os.Remove(file)
|
_ = os.Remove(file)
|
||||||
if _, err := os.Stat(file); err == nil {
|
if _, err := os.Stat(file); err == nil {
|
||||||
@@ -694,7 +728,7 @@ func TestExpand(t *testing.T) {
|
|||||||
func TestDry(t *testing.T) {
|
func TestDry(t *testing.T) {
|
||||||
const dir = "testdata/dry"
|
const dir = "testdata/dry"
|
||||||
|
|
||||||
file := filepath.Join(dir, "file.txt")
|
file := filepathext.SmartJoin(dir, "file.txt")
|
||||||
_ = os.Remove(file)
|
_ = os.Remove(file)
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
@@ -719,12 +753,12 @@ func TestDry(t *testing.T) {
|
|||||||
func TestDryChecksum(t *testing.T) {
|
func TestDryChecksum(t *testing.T) {
|
||||||
const dir = "testdata/dry_checksum"
|
const dir = "testdata/dry_checksum"
|
||||||
|
|
||||||
checksumFile := filepath.Join(dir, ".task/checksum/default")
|
checksumFile := filepathext.SmartJoin(dir, ".task/checksum/default")
|
||||||
_ = os.Remove(checksumFile)
|
_ = os.Remove(checksumFile)
|
||||||
|
|
||||||
e := task.Executor{
|
e := task.Executor{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
TempDir: filepath.Join(dir, ".task"),
|
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||||
Stdout: io.Discard,
|
Stdout: io.Discard,
|
||||||
Stderr: io.Discard,
|
Stderr: io.Discard,
|
||||||
Dry: true,
|
Dry: true,
|
||||||
@@ -776,12 +810,6 @@ func TestIncludesMultiLevel(t *testing.T) {
|
|||||||
func TestIncludeCycle(t *testing.T) {
|
func TestIncludeCycle(t *testing.T) {
|
||||||
const dir = "testdata/includes_cycle"
|
const dir = "testdata/includes_cycle"
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
message := "task: include cycle detected between %s/%s/one/Taskfile.yml <--> %s/%s/Taskfile.yml"
|
|
||||||
expectedError := fmt.Sprintf(message, wd, dir, wd, dir)
|
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.Executor{
|
e := task.Executor{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
@@ -790,7 +818,9 @@ func TestIncludeCycle(t *testing.T) {
|
|||||||
Silent: true,
|
Silent: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.EqualError(t, e.Setup(), expectedError)
|
err := e.Setup()
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "task: include cycle detected between")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncorrectVersionIncludes(t *testing.T) {
|
func TestIncorrectVersionIncludes(t *testing.T) {
|
||||||
@@ -964,12 +994,12 @@ func TestSummary(t *testing.T) {
|
|||||||
assert.NoError(t, e.Setup())
|
assert.NoError(t, e.Setup())
|
||||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "task-with-summary"}, taskfile.Call{Task: "other-task-with-summary"}))
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "task-with-summary"}, taskfile.Call{Task: "other-task-with-summary"}))
|
||||||
|
|
||||||
data, err := os.ReadFile(filepath.Join(dir, "task-with-summary.txt"))
|
data, err := os.ReadFile(filepathext.SmartJoin(dir, "task-with-summary.txt"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
expectedOutput := string(data)
|
expectedOutput := string(data)
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
expectedOutput = strings.Replace(expectedOutput, "\r\n", "\n", -1)
|
expectedOutput = strings.ReplaceAll(expectedOutput, "\r\n", "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, expectedOutput, buff.String())
|
assert.Equal(t, expectedOutput, buff.String())
|
||||||
@@ -1337,3 +1367,36 @@ func TestErrorCode(t *testing.T) {
|
|||||||
assert.True(t, ok, "cannot cast returned error to *task.TaskRunError")
|
assert.True(t, ok, "cannot cast returned error to *task.TaskRunError")
|
||||||
assert.Equal(t, 42, casted.ExitCode(), "unexpected exit code from task")
|
assert.Equal(t, 42, casted.ExitCode(), "unexpected exit code from task")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEvaluateSymlinksInPaths(t *testing.T) {
|
||||||
|
const dir = "testdata/evaluate_symlinks_in_paths"
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := &task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
Silent: false,
|
||||||
|
}
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
err := e.Run(context.Background(), taskfile.Call{Task: "default"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEqual(t, `task: Task "default" is up to date`, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = e.Run(context.Background(), taskfile.Call{Task: "test-sym"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEqual(t, `task: Task "test-sym" is up to date`, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = e.Run(context.Background(), taskfile.Call{Task: "default"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEqual(t, `task: Task "default" is up to date`, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = e.Run(context.Background(), taskfile.Call{Task: "default"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `task: Task "default" is up to date`, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = e.Run(context.Background(), taskfile.Call{Task: "reset"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
buff.Reset()
|
||||||
|
err = os.RemoveAll(dir + "/.task")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -133,7 +134,7 @@ func (it *IncludedTaskfile) resolvePath(path string) (string, error) {
|
|||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := filepath.Abs(filepath.Join(it.BaseDir, path))
|
result, err := filepath.Abs(filepathext.SmartJoin(it.BaseDir, path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("task: error resolving path %s relative to %s: %w", path, it.BaseDir, err)
|
return "", fmt.Errorf("task: error resolving path %s relative to %s: %w", path, it.BaseDir, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package read
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/compiler"
|
"github.com/go-task/task/v3/internal/compiler"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
)
|
)
|
||||||
@@ -27,10 +27,11 @@ func Dotenv(c compiler.Compiler, tf *taskfile.Taskfile, dir string) (*taskfile.V
|
|||||||
|
|
||||||
for _, dotEnvPath := range tf.Dotenv {
|
for _, dotEnvPath := range tf.Dotenv {
|
||||||
dotEnvPath = tr.Replace(dotEnvPath)
|
dotEnvPath = tr.Replace(dotEnvPath)
|
||||||
|
if dotEnvPath == "" {
|
||||||
if !filepath.IsAbs(dotEnvPath) {
|
continue
|
||||||
dotEnvPath = filepath.Join(dir, dotEnvPath)
|
|
||||||
}
|
}
|
||||||
|
dotEnvPath = filepathext.SmartJoin(dir, dotEnvPath)
|
||||||
|
|
||||||
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
|
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
)
|
)
|
||||||
@@ -44,7 +45,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
readerNode.Dir = d
|
readerNode.Dir = d
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := exists(filepath.Join(readerNode.Dir, readerNode.Entrypoint))
|
path, err := exists(filepathext.SmartJoin(readerNode.Dir, readerNode.Entrypoint))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -140,12 +141,10 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, task := range includedTaskfile.Tasks {
|
for _, task := range includedTaskfile.Tasks {
|
||||||
if !filepath.IsAbs(task.Dir) {
|
task.Dir = filepathext.SmartJoin(dir, task.Dir)
|
||||||
task.Dir = filepath.Join(dir, task.Dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
task.IncludeVars = includedTask.Vars
|
task.IncludeVars = includedTask.Vars
|
||||||
task.IncludedTaskfileVars = includedTaskfile.Vars
|
task.IncludedTaskfileVars = includedTaskfile.Vars
|
||||||
|
task.IncludedTaskfile = &includedTask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +158,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v < 3.0 {
|
if v < 3.0 {
|
||||||
path = filepath.Join(readerNode.Dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS))
|
path = filepathext.SmartJoin(readerNode.Dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS))
|
||||||
if _, err = os.Stat(path); err == nil {
|
if _, err = os.Stat(path); err == nil {
|
||||||
osTaskfile, err := readTaskfile(path)
|
osTaskfile, err := readTaskfile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -191,29 +190,19 @@ func readTaskfile(file string) (*taskfile.Taskfile, error) {
|
|||||||
return &t, yaml.NewDecoder(f).Decode(&t)
|
return &t, yaml.NewDecoder(f).Decode(&t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// exists finds a Taskfile at the stated location, returning a fully qualified path to the file
|
|
||||||
func exists(path string) (string, error) {
|
func exists(path string) (string, error) {
|
||||||
fi, err := os.Stat(path)
|
fi, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if fi.Mode().IsRegular() {
|
if fi.Mode().IsRegular() {
|
||||||
// File exists, return a fully qualified path
|
return path, nil
|
||||||
result, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range defaultTaskfiles {
|
for _, n := range defaultTaskfiles {
|
||||||
fpath := filepath.Join(path, n)
|
fpath := filepathext.SmartJoin(path, n)
|
||||||
if _, err := os.Stat(fpath); err == nil {
|
if _, err := os.Stat(fpath); err == nil {
|
||||||
result, err := filepath.Abs(fpath)
|
return fpath, nil
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,14 +217,14 @@ func checkCircularIncludes(node *ReaderNode) error {
|
|||||||
return errors.New("task: failed to check for include cycle: node.Parent was nil")
|
return errors.New("task: failed to check for include cycle: node.Parent was nil")
|
||||||
}
|
}
|
||||||
var curNode = node
|
var curNode = node
|
||||||
var basePath = filepath.Join(node.Dir, node.Entrypoint)
|
var basePath = filepathext.SmartJoin(node.Dir, node.Entrypoint)
|
||||||
for curNode.Parent != nil {
|
for curNode.Parent != nil {
|
||||||
curNode = curNode.Parent
|
curNode = curNode.Parent
|
||||||
curPath := filepath.Join(curNode.Dir, curNode.Entrypoint)
|
curPath := filepathext.SmartJoin(curNode.Dir, curNode.Entrypoint)
|
||||||
if curPath == basePath {
|
if curPath == basePath {
|
||||||
return fmt.Errorf("task: include cycle detected between %s <--> %s",
|
return fmt.Errorf("task: include cycle detected between %s <--> %s",
|
||||||
curPath,
|
curPath,
|
||||||
filepath.Join(node.Parent.Dir, node.Parent.Entrypoint),
|
filepathext.SmartJoin(node.Parent.Dir, node.Parent.Entrypoint),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package read
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
func Taskvars(dir string) (*taskfile.Vars, error) {
|
func Taskvars(dir string) (*taskfile.Vars, error) {
|
||||||
vars := &taskfile.Vars{}
|
vars := &taskfile.Vars{}
|
||||||
|
|
||||||
path := filepath.Join(dir, "Taskvars.yml")
|
path := filepathext.SmartJoin(dir, "Taskvars.yml")
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
vars, err = readTaskvars(path)
|
vars, err = readTaskvars(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -23,7 +23,7 @@ func Taskvars(dir string) (*taskfile.Vars, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path = filepath.Join(dir, fmt.Sprintf("Taskvars_%s.yml", runtime.GOOS))
|
path = filepathext.SmartJoin(dir, fmt.Sprintf("Taskvars_%s.yml", runtime.GOOS))
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
osVars, err := readTaskvars(path)
|
osVars, err := readTaskvars(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type Task struct {
|
|||||||
Run string
|
Run string
|
||||||
IncludeVars *Vars
|
IncludeVars *Vars
|
||||||
IncludedTaskfileVars *Vars
|
IncludedTaskfileVars *Vars
|
||||||
|
IncludedTaskfile *IncludedTaskfile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) Name() string {
|
func (t *Task) Name() string {
|
||||||
|
|||||||
17
testdata/evaluate_symlinks_in_paths/Taskfile.yaml
vendored
Normal file
17
testdata/evaluate_symlinks_in_paths/Taskfile.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
sources:
|
||||||
|
- src/**/*
|
||||||
|
cmds:
|
||||||
|
- echo "some job"
|
||||||
|
|
||||||
|
test-sym:
|
||||||
|
cmds:
|
||||||
|
- echo "shared file source changed" > src/shared/b
|
||||||
|
|
||||||
|
reset:
|
||||||
|
cmds:
|
||||||
|
- echo "shared file source" > src/shared/b
|
||||||
|
- echo "file source" > src/a
|
||||||
1
testdata/evaluate_symlinks_in_paths/shared/b
vendored
Normal file
1
testdata/evaluate_symlinks_in_paths/shared/b
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
shared file source
|
||||||
1
testdata/evaluate_symlinks_in_paths/shared/inner_shared/c
vendored
Normal file
1
testdata/evaluate_symlinks_in_paths/shared/inner_shared/c
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
inner shared file source
|
||||||
1
testdata/evaluate_symlinks_in_paths/src/a
vendored
Normal file
1
testdata/evaluate_symlinks_in_paths/src/a
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
file source
|
||||||
1
testdata/evaluate_symlinks_in_paths/src/shared
vendored
Symbolic link
1
testdata/evaluate_symlinks_in_paths/src/shared
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../shared
|
||||||
18
testdata/special_vars/Taskfile.yml
vendored
Normal file
18
testdata/special_vars/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: ./included
|
||||||
|
dir: ./included
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: print
|
||||||
|
- task: included:print
|
||||||
|
|
||||||
|
print:
|
||||||
|
cmds:
|
||||||
|
- echo root/TASK={{.TASK}}
|
||||||
|
- echo root/ROOT_DIR={{.ROOT_DIR}}
|
||||||
|
- echo root/TASKFILE_DIR={{.TASKFILE_DIR}}
|
||||||
8
testdata/special_vars/included/Taskfile.yml
vendored
Normal file
8
testdata/special_vars/included/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print:
|
||||||
|
cmds:
|
||||||
|
- echo included/TASK={{.TASK}}
|
||||||
|
- echo included/ROOT_DIR={{.ROOT_DIR}}
|
||||||
|
- echo included/TASKFILE_DIR={{.TASKFILE_DIR}}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package task
|
package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/status"
|
"github.com/go-task/task/v3/internal/status"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
@@ -68,8 +68,8 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if e.Dir != "" && !filepath.IsAbs(new.Dir) {
|
if e.Dir != "" {
|
||||||
new.Dir = filepath.Join(e.Dir, new.Dir)
|
new.Dir = filepathext.SmartJoin(e.Dir, new.Dir)
|
||||||
}
|
}
|
||||||
if new.Prefix == "" {
|
if new.Prefix == "" {
|
||||||
new.Prefix = new.Task
|
new.Prefix = new.Task
|
||||||
|
|||||||
Reference in New Issue
Block a user