feat: Add temp dir option (#2891)

Co-authored-by: Valentin Maerten <maerten.valentin@gmail.com>
This commit is contained in:
kjasn
2026-06-29 22:13:37 +08:00
committed by GitHub
parent f9e52fab40
commit 1c743de2b7
10 changed files with 99 additions and 8 deletions

View File

@@ -5,6 +5,12 @@
"Taskfile.yaml",
"taskfile.yml",
"taskfile.yaml"
],
"./website/src/public/schema-taskrc.json": [
".taskrc.yml",
".taskrc.yaml",
"taskrc.yml",
"taskrc.yaml"
]
},
"gopls": {

View File

@@ -24,6 +24,10 @@
- Added support for configuring output flags (`--output`, `--output-group-begin`,
`--output-group-end`, `--output-group-error-only`) via the `TASK_OUTPUT*`
environment variables (#2873 by @liiight).
- Added a `--temp-dir` flag (with `TASK_TEMP_DIR` env var and `temp-dir` taskrc
config) to customise the directory where Task stores temporary files such as
checksums. Relative paths are resolved against the root Taskfile (#2891 by
@kjasn).
## v3.51.1 - 2026-05-16

View File

@@ -29,6 +29,7 @@ type (
Dir string
Entrypoint string
TempDir TempDir
TempDirPath string
Force bool
ForceAll bool
Insecure bool
@@ -165,6 +166,22 @@ func (o *tempDirOption) ApplyToExecutor(e *Executor) {
e.TempDir = o.tempDir
}
// WithTempDirPath sets an unresolved path used to build [Executor.TempDir]
// during [Executor.Setup]. Relative paths are resolved from the root Taskfile
// directory. Use [WithTempDir] when the remote and fingerprint directories have
// already been resolved.
func WithTempDirPath(path string) ExecutorOption {
return &tempDirPathOption{path: path}
}
type tempDirPathOption struct {
path string
}
func (o *tempDirPathOption) ApplyToExecutor(e *Executor) {
e.TempDirPath = o.path
}
// WithForce ensures that the [Executor] always runs a task, even when
// fingerprinting or prompts would normally stop it.
func WithForce(force bool) ExecutorOption {

View File

@@ -87,6 +87,7 @@ var (
Cert string
CertKey string
Interactive bool
TempDir string
)
func init() {
@@ -143,6 +144,7 @@ func init() {
pflag.BoolVarP(&ExitCode, "exit-code", "x", false, "Pass-through the exit code of the task command.")
pflag.StringVarP(&Dir, "dir", "d", "", "Sets the directory in which Task will execute and look for a Taskfile.")
pflag.StringVarP(&Entrypoint, "taskfile", "t", "", `Choose which Taskfile to run. Defaults to "Taskfile.yml".`)
pflag.StringVar(&TempDir, "temp-dir", getConfig(config, "TEMP_DIR", func() *string { return config.TempDir }, ""), "Sets the directory used to store Task temporary files, such as checksums. Relative paths are relative to the root Taskfile.")
pflag.StringVarP(&Output.Name, "output", "o", getConfig(config, "OUTPUT", func() *string { return nil }, ""), "Sets output style: [interleaved|group|prefixed].")
pflag.StringVar(&Output.Group.Begin, "output-group-begin", getConfig(config, "OUTPUT_GROUP_BEGIN", func() *string { return nil }, ""), "Message template to print before a task's grouped output.")
pflag.StringVar(&Output.Group.End, "output-group-end", getConfig(config, "OUTPUT_GROUP_END", func() *string { return nil }, ""), "Message template to print after a task's grouped output.")
@@ -308,6 +310,7 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
task.WithTaskSorter(sorter),
task.WithVersionCheck(true),
task.WithFailfast(Failfast),
task.WithTempDirPath(TempDir),
)
}

View File

@@ -1,6 +1,7 @@
package task
import (
"cmp"
"context"
"fmt"
"os"
@@ -13,7 +14,6 @@ import (
"github.com/sajari/fuzzy"
"github.com/go-task/task/v3/errors"
"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/logger"
@@ -133,13 +133,9 @@ func (e *Executor) setupTempDir() error {
return nil
}
tempDir := env.GetTaskEnv("TEMP_DIR")
if tempDir == "" {
e.TempDir = TempDir{
Remote: filepathext.SmartJoin(e.Dir, ".task"),
Fingerprint: filepathext.SmartJoin(e.Dir, ".task"),
}
} else if filepath.IsAbs(tempDir) || strings.HasPrefix(tempDir, "~") {
// e.TempDirPath carries the resolved CLI precedence (flag > TASK_TEMP_DIR > taskrc).
tempDir := cmp.Or(e.TempDirPath, ".task")
if filepath.IsAbs(tempDir) || strings.HasPrefix(tempDir, "~") {
tempDir, err := execext.ExpandLiteral(tempDir)
if err != nil {
return err

View File

@@ -19,6 +19,7 @@ type TaskRC struct {
Interactive *bool `yaml:"interactive"`
Remote Remote `yaml:"remote"`
Failfast bool `yaml:"failfast"`
TempDir *string `yaml:"temp-dir"`
Experiments map[string]int `yaml:"experiments"`
}
@@ -70,4 +71,5 @@ func (t *TaskRC) Merge(other *TaskRC) {
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
t.Interactive = cmp.Or(other.Interactive, t.Interactive)
t.Failfast = cmp.Or(other.Failfast, t.Failfast)
t.TempDir = cmp.Or(other.TempDir, t.TempDir)
}

View File

@@ -112,6 +112,40 @@ func TestGetConfig_OnlyLocal(t *testing.T) { //nolint:paralleltest // cannot run
}, cfg)
}
func TestGetConfig_TempDir(t *testing.T) { //nolint:paralleltest // cannot run in parallel
_, _, localDir := setupDirs(t)
writeFile(t, localDir, ".taskrc.yml", `
temp-dir: .task-cache
`)
cfg, err := GetConfig(localDir)
require.NoError(t, err)
require.NotNil(t, cfg)
require.NotNil(t, cfg.TempDir)
assert.Equal(t, ".task-cache", *cfg.TempDir)
}
func TestGetConfig_TempDirMergePrecedence(t *testing.T) { //nolint:paralleltest // cannot run in parallel
xdgConfigDir, homeDir, localDir := setupDirs(t)
writeFile(t, xdgConfigDir, "taskrc.yml", `
temp-dir: xdg-cache
`)
writeFile(t, homeDir, ".taskrc.yml", `
temp-dir: home-cache
`)
writeFile(t, localDir, ".taskrc.yml", `
temp-dir: local-cache
`)
cfg, err := GetConfig(localDir)
require.NoError(t, err)
require.NotNil(t, cfg)
require.NotNil(t, cfg.TempDir)
assert.Equal(t, "local-cache", *cfg.TempDir)
}
func TestGetConfig_All(t *testing.T) { //nolint:paralleltest // cannot run in parallel
xdgConfigDir, homeDir, localDir := setupDirs(t)

View File

@@ -220,6 +220,18 @@ Run the global Taskfile from `$HOME/Taskfile.{yml,yaml}`.
task backup --global
```
#### `--temp-dir <path>`
Set the directory used to store Task temporary files, such as checksums.
Relative paths are relative to the root Taskfile.
- **Config equivalent**: [`temp-dir`](./config.md#temp-dir)
- **Environment variable**: [`TASK_TEMP_DIR`](./environment.md#task-temp-dir)
```bash
task build --temp-dir .task-cache
```
### Output Control
#### `-o, --output <mode>`

View File

@@ -166,6 +166,18 @@ failfast: true
interactive: true
```
### `temp-dir`
- **Type**: `string`
- **Default**: `./.task`
- **Description**: Directory to store Task temporary files, such as checksums
and temporary metadata. Relative paths are relative to the root Taskfile.
- **Environment variable**: [`TASK_TEMP_DIR`](./environment.md#task-temp-dir)
```yaml
temp-dir: .task
```
## Example Configuration
Here's a complete example of a `.taskrc.yml` file with all available options:
@@ -177,6 +189,7 @@ silent: false
color: true
disable-fuzzy: false
concurrency: 2
temp-dir: .task
# Enable experimental features
experiments:

View File

@@ -88,6 +88,10 @@
"description": "Prompt for missing required variables instead of failing. Requires a TTY.",
"type": "boolean",
"default": false
},
"temp-dir": {
"type": "string",
"description": "Directory to store Task temporary files, such as checksums and temporary metadata. Relative paths are relative to the root Taskfile."
}
},
"additionalProperties": false