From 191cb5d3f976c7fd4b4f56093e4513601519e76d Mon Sep 17 00:00:00 2001 From: Ferdinand Hofherr Date: Fri, 7 Feb 2025 15:45:29 +0100 Subject: [PATCH] feat: add TASK_SOURCES special variable This commit adds the `TASK_SOURCES` variable to tasks. If a task defines the `sources` key, `TASK_SOURCES` contains the list of paths referenced by `sources`. Globs are expanded. This was initially implemented by @hernandanielg in #1146 to fix #948. --- internal/compiler/compiler.go | 15 ++++++++++++--- task_test.go | 12 ++++++++++++ testdata/special_vars/Taskfile.yml | 11 +++++++++++ testdata/special_vars/sources-as-var/file.txt | 0 .../special_vars/sources-as-var/subdir1/file.txt | 0 .../special_vars/sources-as-var/subdir2/file.txt | 0 website/docs/reference/templating.mdx | 1 + 7 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 testdata/special_vars/sources-as-var/file.txt create mode 100644 testdata/special_vars/sources-as-var/subdir1/file.txt create mode 100644 testdata/special_vars/sources-as-var/subdir2/file.txt diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 527163acb9..35af85ee10 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -12,6 +12,7 @@ import ( "github.com/go-task/task/v3/internal/env" "github.com/go-task/task/v3/internal/execext" "github.com/go-task/task/v3/internal/filepathext" + "github.com/go-task/task/v3/internal/fingerprint" "github.com/go-task/task/v3/internal/logger" "github.com/go-task/task/v3/internal/templater" "github.com/go-task/task/v3/internal/version" @@ -184,8 +185,8 @@ func (c *Compiler) ResetCache() { c.dynamicCache = nil } -func (c *Compiler) getSpecialVars(t *ast.Task, call *ast.Call) (map[string]string, error) { - allVars := map[string]string{ +func (c *Compiler) getSpecialVars(t *ast.Task, call *ast.Call) (map[string]any, error) { + allVars := map[string]any{ "TASK_EXE": filepath.ToSlash(os.Args[0]), "ROOT_TASKFILE": filepathext.SmartJoin(c.Dir, c.Entrypoint), "ROOT_DIR": c.Dir, @@ -193,10 +194,18 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *ast.Call) (map[string]strin "TASK_VERSION": version.GetVersion(), } if t != nil { + dir := filepathext.SmartJoin(c.Dir, t.Dir) + + taskSources, err := fingerprint.Globs(dir, t.Sources) + if err != nil { + return allVars, fmt.Errorf("expand globs: %v", err) + } + allVars["TASK"] = t.Task - allVars["TASK_DIR"] = filepathext.SmartJoin(c.Dir, t.Dir) + allVars["TASK_DIR"] = dir allVars["TASKFILE"] = t.Location.Taskfile allVars["TASKFILE_DIR"] = filepath.Dir(t.Location.Taskfile) + allVars["TASK_SOURCES"] = taskSources } if call != nil { allVars["ALIAS"] = call.Task diff --git a/task_test.go b/task_test.go index 7acfe383e6..a78e732438 100644 --- a/task_test.go +++ b/task_test.go @@ -231,6 +231,15 @@ func TestSpecialVars(t *testing.T) { {target: "print-taskfile-dir", expected: toAbs(dir)}, {target: "print-task-version", expected: "unknown"}, {target: "print-task-dir", expected: toAbs(dir) + "/foo"}, + { + target: "print-task-sources", + expected: "[" + + toAbs(dir) + "/sources-as-var/file.txt, " + + toAbs(dir) + "/sources-as-var/subdir1/file.txt, " + + toAbs(dir) + "/sources-as-var/subdir2/file.txt" + + "]", + }, + {target: "print-task-sources-empty", expected: "[]"}, // Included {target: "included:print-task", expected: "included:print-task"}, {target: "included:print-root-dir", expected: toAbs(dir)}, @@ -251,6 +260,9 @@ func TestSpecialVars(t *testing.T) { Stderr: &buff, Silent: true, EnableVersionCheck: true, + // NOTE needed to enable Force to ignore fingerprints generated + // when setting source. + Force: true, } require.NoError(t, e.Setup()) require.NoError(t, e.Run(context.Background(), &ast.Call{Task: test.target})) diff --git a/testdata/special_vars/Taskfile.yml b/testdata/special_vars/Taskfile.yml index 3a650f5098..174cc202b8 100644 --- a/testdata/special_vars/Taskfile.yml +++ b/testdata/special_vars/Taskfile.yml @@ -22,3 +22,14 @@ tasks: print-task-dir: dir: 'foo' cmd: echo {{.TASK_DIR}} + + print-task-sources: + sources: + - sources-as-var/**/*.txt + cmds: + - echo "[{{.TASK_SOURCES | sortAlpha | join ", "}}]" + + print-task-sources-empty: + # No sources defined, yet we try to use TASK_SOURCES. + cmds: + - echo "{{.TASK_SOURCES}}" diff --git a/testdata/special_vars/sources-as-var/file.txt b/testdata/special_vars/sources-as-var/file.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/special_vars/sources-as-var/subdir1/file.txt b/testdata/special_vars/sources-as-var/subdir1/file.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/special_vars/sources-as-var/subdir2/file.txt b/testdata/special_vars/sources-as-var/subdir2/file.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website/docs/reference/templating.mdx b/website/docs/reference/templating.mdx index 98d45bae00..c3b265e7d8 100644 --- a/website/docs/reference/templating.mdx +++ b/website/docs/reference/templating.mdx @@ -115,6 +115,7 @@ special variable will be overridden. | `TASKFILE` | The absolute path of the included Taskfile. | | `TASKFILE_DIR` | The absolute path of the included Taskfile directory. | | `TASK_DIR` | The absolute path of the directory where the task is executed. | +| `TASK_SOURCES` | List of files referenced by task `sources` key. Empty if task does not define `sources`. | | `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. | | `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 listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |