mirror of
https://github.com/go-task/task.git
synced 2026-05-18 13:15:41 +02:00
Compare commits
3 Commits
renovate/g
...
fix/specia
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc0cf49f54 | ||
|
|
58340492cb | ||
|
|
d96d6fe703 |
33
compiler.go
33
compiler.go
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/internal/version"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
@@ -201,10 +202,19 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, e
|
||||
// Use filepath.ToSlash for all paths to ensure consistent forward slashes
|
||||
// across platforms. This prevents issues with backslashes being interpreted
|
||||
// as escape sequences when paths are used in shell commands on Windows.
|
||||
var rootTaskfile, rootDir string
|
||||
if taskfile.IsRemoteEntrypoint(c.Entrypoint) {
|
||||
rootTaskfile = c.Entrypoint
|
||||
rootDir = ""
|
||||
} else {
|
||||
rootTaskfile = filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint))
|
||||
rootDir = filepath.ToSlash(c.Dir)
|
||||
}
|
||||
|
||||
allVars := map[string]string{
|
||||
"TASK_EXE": filepath.ToSlash(os.Args[0]),
|
||||
"ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)),
|
||||
"ROOT_DIR": filepath.ToSlash(c.Dir),
|
||||
"ROOT_TASKFILE": rootTaskfile,
|
||||
"ROOT_DIR": rootDir,
|
||||
"USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir),
|
||||
"TASK_VERSION": version.GetVersion(),
|
||||
"PATH_LIST_SEPARATOR": string(os.PathListSeparator),
|
||||
@@ -212,9 +222,22 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, e
|
||||
}
|
||||
if t != nil {
|
||||
allVars["TASK"] = t.Task
|
||||
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.Dir, t.Dir))
|
||||
allVars["TASKFILE"] = filepath.ToSlash(t.Location.Taskfile)
|
||||
allVars["TASKFILE_DIR"] = filepath.ToSlash(filepath.Dir(t.Location.Taskfile))
|
||||
if taskfile.IsRemoteEntrypoint(t.Location.Taskfile) {
|
||||
allVars["TASKFILE"] = t.Location.Taskfile
|
||||
allVars["TASKFILE_DIR"] = ""
|
||||
switch {
|
||||
case t.Dir == "":
|
||||
allVars["TASK_DIR"] = filepath.ToSlash(c.UserWorkingDir)
|
||||
case filepath.IsAbs(t.Dir):
|
||||
allVars["TASK_DIR"] = filepath.ToSlash(t.Dir)
|
||||
default:
|
||||
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.UserWorkingDir, t.Dir))
|
||||
}
|
||||
} else {
|
||||
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.Dir, t.Dir))
|
||||
allVars["TASKFILE"] = filepath.ToSlash(t.Location.Taskfile)
|
||||
allVars["TASKFILE_DIR"] = filepath.ToSlash(filepath.Dir(t.Location.Taskfile))
|
||||
}
|
||||
} else {
|
||||
allVars["TASK"] = ""
|
||||
allVars["TASK_DIR"] = ""
|
||||
|
||||
135
compiler_internal_test.go
Normal file
135
compiler_internal_test.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
func TestGetSpecialVarsRemote(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
uwd := t.TempDir()
|
||||
uwdSlash := filepath.ToSlash(uwd)
|
||||
localProj := filepath.Join(uwd, "proj")
|
||||
localProjSlash := filepath.ToSlash(localProj)
|
||||
localTaskfile := filepath.Join(localProj, "Taskfile.yml")
|
||||
localTaskfileSlash := filepath.ToSlash(localTaskfile)
|
||||
absTaskDir := filepath.Join(uwd, "opt", "work")
|
||||
absTaskDirSlash := filepath.ToSlash(absTaskDir)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
entrypoint string
|
||||
compilerDir string
|
||||
taskDir string
|
||||
taskfileLocation string
|
||||
wantRootTaskfile string
|
||||
wantRootDir string
|
||||
wantTaskfile string
|
||||
wantTaskfileDir string
|
||||
wantTaskDir string
|
||||
}{
|
||||
{
|
||||
name: "local entrypoint, local task",
|
||||
entrypoint: localTaskfile,
|
||||
compilerDir: localProj,
|
||||
taskDir: "",
|
||||
taskfileLocation: localTaskfile,
|
||||
wantRootTaskfile: localTaskfileSlash,
|
||||
wantRootDir: localProjSlash,
|
||||
wantTaskfile: localTaskfileSlash,
|
||||
wantTaskfileDir: localProjSlash,
|
||||
wantTaskDir: localProjSlash,
|
||||
},
|
||||
{
|
||||
name: "https entrypoint, empty task.dir",
|
||||
entrypoint: "https://taskfile.dev/Taskfile.yml",
|
||||
compilerDir: "",
|
||||
taskDir: "",
|
||||
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootDir: "",
|
||||
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantTaskfileDir: "",
|
||||
wantTaskDir: uwdSlash,
|
||||
},
|
||||
{
|
||||
name: "https entrypoint, relative task.dir",
|
||||
entrypoint: "https://taskfile.dev/Taskfile.yml",
|
||||
compilerDir: "",
|
||||
taskDir: "subdir",
|
||||
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootDir: "",
|
||||
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantTaskfileDir: "",
|
||||
wantTaskDir: filepath.ToSlash(filepathext.SmartJoin(uwd, "subdir")),
|
||||
},
|
||||
{
|
||||
name: "https entrypoint, absolute task.dir",
|
||||
entrypoint: "https://taskfile.dev/Taskfile.yml",
|
||||
compilerDir: "",
|
||||
taskDir: absTaskDir,
|
||||
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantRootDir: "",
|
||||
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
|
||||
wantTaskfileDir: "",
|
||||
wantTaskDir: absTaskDirSlash,
|
||||
},
|
||||
{
|
||||
name: "git entrypoint",
|
||||
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
|
||||
compilerDir: "",
|
||||
taskDir: "",
|
||||
taskfileLocation: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
|
||||
wantRootTaskfile: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
|
||||
wantRootDir: "",
|
||||
wantTaskfile: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
|
||||
wantTaskfileDir: "",
|
||||
wantTaskDir: uwdSlash,
|
||||
},
|
||||
{
|
||||
name: "local root, remote included task",
|
||||
entrypoint: localTaskfile,
|
||||
compilerDir: localProj,
|
||||
taskDir: "",
|
||||
taskfileLocation: "https://taskfile.dev/included.yml",
|
||||
wantRootTaskfile: localTaskfileSlash,
|
||||
wantRootDir: localProjSlash,
|
||||
wantTaskfile: "https://taskfile.dev/included.yml",
|
||||
wantTaskfileDir: "",
|
||||
wantTaskDir: uwdSlash,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Compiler{
|
||||
Dir: tt.compilerDir,
|
||||
Entrypoint: tt.entrypoint,
|
||||
UserWorkingDir: uwd,
|
||||
}
|
||||
task := &ast.Task{
|
||||
Task: "mytask",
|
||||
Dir: tt.taskDir,
|
||||
Location: &ast.Location{Taskfile: tt.taskfileLocation},
|
||||
}
|
||||
|
||||
vars, err := c.getSpecialVars(task, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.wantRootTaskfile, vars["ROOT_TASKFILE"], "ROOT_TASKFILE")
|
||||
assert.Equal(t, tt.wantRootDir, vars["ROOT_DIR"], "ROOT_DIR")
|
||||
assert.Equal(t, tt.wantTaskfile, vars["TASKFILE"], "TASKFILE")
|
||||
assert.Equal(t, tt.wantTaskfileDir, vars["TASKFILE_DIR"], "TASKFILE_DIR")
|
||||
assert.Equal(t, tt.wantTaskDir, vars["TASK_DIR"], "TASK_DIR")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func NewNode(
|
||||
return node, err
|
||||
}
|
||||
|
||||
func isRemoteEntrypoint(entrypoint string) bool {
|
||||
func IsRemoteEntrypoint(entrypoint string) bool {
|
||||
scheme, _ := getScheme(entrypoint)
|
||||
switch scheme {
|
||||
case "git", "http", "https":
|
||||
|
||||
@@ -60,7 +60,7 @@ func (node *FileNode) Read() ([]byte, error) {
|
||||
|
||||
func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if isRemoteEntrypoint(entrypoint) {
|
||||
if IsRemoteEntrypoint(entrypoint) {
|
||||
return entrypoint, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ func (node *GitNode) ReadContext(ctx context.Context) ([]byte, error) {
|
||||
|
||||
func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if isRemoteEntrypoint(entrypoint) {
|
||||
if IsRemoteEntrypoint(entrypoint) {
|
||||
return entrypoint, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func (node *StdinNode) Read() ([]byte, error) {
|
||||
|
||||
func (node *StdinNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if isRemoteEntrypoint(entrypoint) {
|
||||
if IsRemoteEntrypoint(entrypoint) {
|
||||
return entrypoint, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,21 @@ includes:
|
||||
my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
The file-path [special variables](../reference/templating.md#file-paths) behave
|
||||
differently when a Taskfile is loaded from a remote source, because there is no
|
||||
local file or directory that corresponds 1:1 to the Taskfile:
|
||||
|
||||
| Variable | Value when loaded remotely |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `TASKFILE` / `ROOT_TASKFILE` | The original URL, unchanged |
|
||||
| `TASKFILE_DIR` / `ROOT_DIR` | Empty string — a directory variable cannot point to a URL |
|
||||
| `TASK_DIR` | Resolved against `USER_WORKING_DIR` (relative `dir:` → joined with `USER_WORKING_DIR`, empty `dir:` → `USER_WORKING_DIR`, absolute `dir:` → kept as-is) |
|
||||
|
||||
If a remote Taskfile includes a local Taskfile (or vice-versa), each variable
|
||||
reflects the source of the Taskfile it refers to.
|
||||
|
||||
## Security
|
||||
|
||||
### Automatic checksums
|
||||
|
||||
Reference in New Issue
Block a user