Skip to content

fix: resolve templated task dir before running dynamic variables - #2944

Open
semx wants to merge 1 commit into
go-task:mainfrom
semx:fix/templated-dir-dynamic-vars
Open

fix: resolve templated task dir before running dynamic variables#2944
semx wants to merge 1 commit into
go-task:mainfrom
semx:fix/templated-dir-dynamic-vars

Conversation

@semx

@semx semx commented Jul 27, 2026

Copy link
Copy Markdown

Fixes the task dir being templated too early, which made dynamic variables run in the wrong directory.

The problem

getVariables resolves the task dir with the variables collected so far, but at that point result only holds the environment and the special variables. The Taskfile vars are added a few lines below. So a dir like '{{.DIRECTORY}}', where DIRECTORY comes from the Taskfile vars:, expands to an empty string and the task dynamic variables run in the Taskfile dir instead of the task dir.

The commands themselves are unaffected — they already run in the right directory. Only the sh: variables see the wrong one.

Reproducer

version: '3'

vars:
  DIRECTORY: subdirectory

tasks:
  literal-dir:
    dir: subdirectory
    cmds:
      - 'echo "  cmds ran in       $(basename $(pwd))"'
      - 'echo "  dynamic var saw   {{.W}}"'
    vars:
      W:
        sh: basename "$(pwd)"

  templated-dir:
    dir: '{{.DIRECTORY}}'
    cmds:
      - 'echo "  cmds ran in       $(basename $(pwd))"'
      - 'echo "  dynamic var saw   {{.W}}"'
    vars:
      W:
        sh: basename "$(pwd)"
$ task literal-dir
  cmds ran in       subdirectory
  dynamic var saw   subdirectory

$ task templated-dir
  cmds ran in       subdirectory
  dynamic var saw   example        # <- the Taskfile dir

The same dir works when DIRECTORY comes from the environment (DIRECTORY=subdirectory task templated-dir), because environment variables are already in result when the dir is resolved. That is what pointed at the ordering.

The fix

Resolve the dir after the Taskfile env and vars have been added to the result, right before the first use of taskRangeFunc. The order in which variables are added is unchanged, only the point where the dir is computed moves down.

Note on the existing test

TestDynamicVariablesShouldRunOnTheTaskDir covers a templated dir already (from_interpolated_dir), but it passes on main for the wrong reason: every task in that fixture runs the same basename "$(pwd)" command, and the dynamic variable cache is keyed by the command alone, so the templated-dir task reuses a value another task computed in subdirectory. The new fixture uses a single task so the cache cannot mask the result.

That cache is a separate issue (#2928) with fixes already proposed, so this PR leaves it alone.

The task dir was templated against the variables gathered so far, which
at that point only held the environment and the special variables. A dir
like '{{.DIRECTORY}}', where DIRECTORY comes from the Taskfile vars,
expanded to an empty string, so the task dynamic variables silently ran
in the Taskfile dir instead of the task one.

Resolve the dir after the Taskfile vars have been added to the result.
The commands themselves already ran in the right dir, only the dynamic
variables were affected.

Signed-off-by: semx <7532921+semx@users.noreply.github.com>
@trulede

trulede commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Is this any different than PR #2813 ?

@semx

semx commented Jul 27, 2026

Copy link
Copy Markdown
Author

Different problem — I built both branches and ran them against each other's case.

Same Taskfile, one task with a literal dir: that doesn't exist yet, one with dir: '{{.DIRECTORY}}' where DIRECTORY is a Taskfile var:

dir: newdir (missing) dir: '{{.DIRECTORY}}'
#2813 dynamic var saw newdir dynamic var saw repro4 — wrong
#2944 chdir ...: no such file or directory dynamic var saw subdirectory
both correct correct

#2813 skips templated dirs on purpose — !strings.Contains(t.Dir, "{"), with the comment saying as much — because it's solving "the directory isn't there yet, so cd fails". Mine is solving "the path is computed wrong in the first place": getVariables templates t.Dir against a result that so far holds only the environment and the special vars, so {{.DIRECTORY}} expands to an empty string and the sh: vars silently run in the Taskfile dir. Neither patch helps with the other's failure.

They compose, though. With both applied both cases pass — the only merge conflict is in task_test.go, where we each appended tests to the same spot.

So no objection from me if #2813 lands first; I'll rebase and drop the conflicting hunk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants