From ab98b6e82988b6c2ce1376a788bf1bc43ecec216 Mon Sep 17 00:00:00 2001 From: Niklas Rousset Date: Mon, 21 Oct 2024 10:45:14 +0200 Subject: [PATCH 1/2] feat: make checksum and timestamp vars available in cmds --- task_test.go | 31 ++++++++++ testdata/cmds_vars/Taskfile.yml | 10 ++++ testdata/cmds_vars/source.txt | 1 + variables.go | 101 ++++++++++++++++---------------- 4 files changed, 94 insertions(+), 49 deletions(-) create mode 100644 testdata/cmds_vars/Taskfile.yml create mode 100644 testdata/cmds_vars/source.txt diff --git a/task_test.go b/task_test.go index 599277c8c5..9d219a82f1 100644 --- a/task_test.go +++ b/task_test.go @@ -900,6 +900,37 @@ func TestStatusVariables(t *testing.T) { assert.Contains(t, buff.String(), tf) } +func TestCmdsVariables(t *testing.T) { + const dir = "testdata/cmds_vars" + + _ = os.RemoveAll(filepathext.SmartJoin(dir, ".task")) + + var buff bytes.Buffer + e := task.Executor{ + Dir: dir, + TempDir: task.TempDir{ + Remote: filepathext.SmartJoin(dir, ".task"), + Fingerprint: filepathext.SmartJoin(dir, ".task"), + }, + Stdout: &buff, + Stderr: &buff, + Silent: false, + Verbose: true, + } + require.NoError(t, e.Setup()) + require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "build"})) + + assert.Contains(t, buff.String(), "3e464c4b03f4b65d740e1e130d4d108a") + + inf, err := os.Stat(filepathext.SmartJoin(dir, "source.txt")) + require.NoError(t, err) + ts := fmt.Sprintf("%d", inf.ModTime().Unix()) + tf := inf.ModTime().String() + + assert.Contains(t, buff.String(), ts) + assert.Contains(t, buff.String(), tf) +} + func TestInit(t *testing.T) { const dir = "testdata/init" file := filepathext.SmartJoin(dir, "Taskfile.yml") diff --git a/testdata/cmds_vars/Taskfile.yml b/testdata/cmds_vars/Taskfile.yml new file mode 100644 index 0000000000..4857129f97 --- /dev/null +++ b/testdata/cmds_vars/Taskfile.yml @@ -0,0 +1,10 @@ +version: '3' + +tasks: + build: + sources: + - ./source.txt + cmds: + - echo "{{.CHECKSUM}}" + - echo "{{.TIMESTAMP.Unix}}" + - echo "{{.TIMESTAMP}}" diff --git a/testdata/cmds_vars/source.txt b/testdata/cmds_vars/source.txt new file mode 100644 index 0000000000..8ab686eafe --- /dev/null +++ b/testdata/cmds_vars/source.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/variables.go b/variables.go index 6dac3a6c3e..a1c3d3d2cb 100644 --- a/variables.go +++ b/variables.go @@ -128,53 +128,6 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task, } } - if len(origTask.Cmds) > 0 { - new.Cmds = make([]*ast.Cmd, 0, len(origTask.Cmds)) - for _, cmd := range origTask.Cmds { - if cmd == nil { - continue - } - if cmd.For != nil { - list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, vars, origTask.Location) - if err != nil { - return nil, err - } - // Name the iterator variable - var as string - if cmd.For.As != "" { - as = cmd.For.As - } else { - as = "ITEM" - } - // Create a new command for each item in the list - for i, loopValue := range list { - extra := map[string]any{ - as: loopValue, - } - if len(keys) > 0 { - extra["KEY"] = keys[i] - } - newCmd := cmd.DeepCopy() - newCmd.Cmd = templater.ReplaceWithExtra(cmd.Cmd, cache, extra) - newCmd.Task = templater.ReplaceWithExtra(cmd.Task, cache, extra) - newCmd.Vars = templater.ReplaceVarsWithExtra(cmd.Vars, cache, extra) - new.Cmds = append(new.Cmds, newCmd) - } - continue - } - // Defer commands are replaced in a lazy manner because - // we need to include EXIT_CODE. - if cmd.Defer { - new.Cmds = append(new.Cmds, cmd.DeepCopy()) - continue - } - newCmd := cmd.DeepCopy() - newCmd.Cmd = templater.Replace(cmd.Cmd, cache) - newCmd.Task = templater.Replace(cmd.Task, cache) - newCmd.Vars = templater.ReplaceVars(cmd.Vars, cache) - new.Cmds = append(new.Cmds, newCmd) - } - } if len(origTask.Deps) > 0 { new.Deps = make([]*ast.Dep, 0, len(origTask.Deps)) for _, dep := range origTask.Deps { @@ -228,7 +181,7 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task, } } - if len(origTask.Status) > 0 { + if len(origTask.Cmds) > 0 || len(origTask.Status) > 0 { timestampChecker := fingerprint.NewTimestampChecker(e.TempDir.Fingerprint, e.Dry) checksumChecker := fingerprint.NewChecksumChecker(e.TempDir.Fingerprint, e.Dry) @@ -244,7 +197,57 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task, // cache of the the values manually cache.ResetCache() - new.Status = templater.Replace(origTask.Status, cache) + if len(origTask.Cmds) > 0 { + new.Cmds = make([]*ast.Cmd, 0, len(origTask.Cmds)) + for _, cmd := range origTask.Cmds { + if cmd == nil { + continue + } + if cmd.For != nil { + list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, vars, origTask.Location) + if err != nil { + return nil, err + } + // Name the iterator variable + var as string + if cmd.For.As != "" { + as = cmd.For.As + } else { + as = "ITEM" + } + // Create a new command for each item in the list + for i, loopValue := range list { + extra := map[string]any{ + as: loopValue, + } + if len(keys) > 0 { + extra["KEY"] = keys[i] + } + newCmd := cmd.DeepCopy() + newCmd.Cmd = templater.ReplaceWithExtra(cmd.Cmd, cache, extra) + newCmd.Task = templater.ReplaceWithExtra(cmd.Task, cache, extra) + newCmd.Vars = templater.ReplaceVarsWithExtra(cmd.Vars, cache, extra) + new.Cmds = append(new.Cmds, newCmd) + } + continue + } + // Defer commands are replaced in a lazy manner because + // we need to include EXIT_CODE. + if cmd.Defer { + new.Cmds = append(new.Cmds, cmd.DeepCopy()) + continue + } + newCmd := cmd.DeepCopy() + newCmd.Cmd = templater.Replace(cmd.Cmd, cache) + newCmd.Task = templater.Replace(cmd.Task, cache) + newCmd.Vars = templater.ReplaceVars(cmd.Vars, cache) + new.Cmds = append(new.Cmds, newCmd) + } + } + + if len(origTask.Status) > 0 { + new.Status = templater.Replace(origTask.Status, cache) + } } // We only care about templater errors if we are evaluating shell variables From abeb16fd85ef9f816eacbbc62a82f5456e3df629 Mon Sep 17 00:00:00 2001 From: Niklas Rousset Date: Mon, 21 Oct 2024 11:09:49 +0200 Subject: [PATCH 2/2] update docs --- website/docs/usage.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/usage.mdx b/website/docs/usage.mdx index 0cb12c246f..e18b07d328 100644 --- a/website/docs/usage.mdx +++ b/website/docs/usage.mdx @@ -886,7 +886,7 @@ checksum source and timestamps require either access to the artifact or for an out-of-band refresh of the `.checksum` fingerprint file. Two special variables `{{.CHECKSUM}}` and `{{.TIMESTAMP}}` are available for -interpolation within `status` commands, depending on the method assigned to +interpolation within `cmds` and `status` commands, depending on the method assigned to fingerprint the sources. Only `source` globs are fingerprinted. Note that the `{{.TIMESTAMP}}` variable is a "live" Go `time.Time` struct, and