Compare commits

..

27 Commits

Author SHA1 Message Date
Andrey Nering
fc378cfb92 v3.46.2 2025-12-18 17:55:19 -03:00
Andrey Nering
9488a2a744 docs(changelog): add entry for #2588 and #2589 2025-12-18 17:54:38 -03:00
Andrey Nering
6ece2445ae docs(changelog): change tag to match release on github 2025-12-18 17:51:33 -03:00
Valentin Maerten
9b95e758f4 fix: cli variables should take priority over aaskfile defaults (#2589)
When using `task FOO=bar` with a Taskfile containing
`FOO: '{{.FOO | default "foo"}}'`, the CLI value was being
overwritten by the Taskfile default.

Split the variable merging into two steps:
1. Merge CLI variables (FOO=bar) first so they override Taskfile vars
2. ReverseMerge special variables (CLI_ARGS, CLI_FORCE, etc.) so
   they're available for templating in Taskfile vars

Fixes regression introduced in #2403.

Co-authored-by: Timothy Rule <timothy.rule@gmail.com>
2025-12-18 17:50:00 -03:00
Valentin Maerten
28fee2c356 v3.46.1 2025-12-18 17:42:03 +01:00
Valentin Maerten
763e77467b fix: cloudsmith alpine upload 2025-12-18 17:41:54 +01:00
Valentin Maerten
f2385e625d v3.46.0 2025-12-18 17:29:29 +01:00
Valentin Maerten
e929cccd73 docs: better changelog (#2586) 2025-12-18 16:42:55 +01:00
Valentin Maerten
cb183349b7 refactor: migrate from go-git to go-getter (#2512) 2025-12-18 12:21:30 +01:00
Valentin Maerten
2ebbb99f58 improve website's SEO 2025-12-18 08:52:43 +01:00
Valentin Maerten
6660afc8d2 feat: auto-detect color output in CI environments (#2569) 2025-12-18 08:40:37 +01:00
Valentin Maerten
b710259bfa feat(completion): add zstyle verbose option for zsh completion (#2571) 2025-12-18 08:35:56 +01:00
Valentin Maerten
4ec6c453bd feat: add remote.cache-dir taskrc option (#2572) 2025-12-18 08:32:11 +01:00
Valentin Maerten
28408ef3f4 fix(schema): workaround IntelliJ JSON Schema validation bug (#2576) 2025-12-15 23:03:13 +01:00
Valentin Maerten
a2d34ffc4c chore: changelog for #2577 2025-12-15 22:45:52 +01:00
Semih Buyukgungor
1a190a118f feat: expose .CLI_ASSUME_YES templating variable (#2577) 2025-12-15 22:42:27 +01:00
renovate[bot]
18efa3982f chore(deps): update all non-major dependencies (#2580)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 14:33:40 -03:00
Valentin Maerten
655e83454e fix(completion): handle colons in task descriptions for fish (#2573) 2025-12-14 15:56:18 +01:00
Valentin Maerten
3ad4604c36 fix(completion): support --global flag in zsh completion (#2574) 2025-12-14 15:51:15 +01:00
Valentin Maerten
5a27d04655 chore: changelog for #2552 2025-12-12 22:30:18 +01:00
Timothy Rule
ea933bcc55 fix: support error_ignore for a task call (#2552) 2025-12-12 22:28:20 +01:00
Valentin Maerten
e0d6b71971 chore: changelog for #2568 2025-12-12 21:25:59 +01:00
Valentin Maerten
d7ee855e49 feat: emit error annotations in GitHub Actions (#2568) 2025-12-12 21:23:37 +01:00
Valentin Maerten
511f35a456 chore: changelog for #2403 2025-12-12 21:23:17 +01:00
Valentin Maerten
5889ff6b65 fix: globals vars are available in vars at root level (#2403) 2025-12-12 21:20:27 +01:00
Valentin Maerten
85a98b5f90 chore: changelog for #2566 2025-12-12 21:11:30 +01:00
Timothy Rule
89b6140166 fix: always run a watch task regardless of run setting (#2566) 2025-12-12 21:09:35 +01:00
41 changed files with 1071 additions and 361 deletions

View File

@@ -1,112 +0,0 @@
name: CI
on:
pull_request:
push:
tags:
- v*
branches:
- main
concurrency:
group: ci-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
build:
name: 🔨 Build (${{ matrix.go-version }})
strategy:
fail-fast: false
matrix:
go-version: [1.24.x, 1.25.x]
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: ⬇️ Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- name: 🔨 Build
run: go build -v ./cmd/task
test:
name: 🧪 Test (${{ matrix.go-version }}, ${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
go-version: [1.24.x, 1.25.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: ⬇️ Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- name: ⬇️ Setup Task
uses: go-task/setup-task@v1
- name: 🧪 Test
run: task test --output group --output-group-begin '::group::{{.TASK}}' --output-group-end '::endgroup::'
lint:
name: 🔍 Lint (${{ matrix.go-version }})
strategy:
fail-fast: false
matrix:
go-version: [1.24.x, 1.25.x]
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: ⬇️ Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- name: 🔍 Lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.7.1
lint-jsonschema:
name: 📋 Lint JSON Schema
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: ⬇️ Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.14
- name: ⬇️ Install check-jsonschema
run: python -m pip install 'check-jsonschema==0.27.3'
- name: 📋 Validate JSON Schema
run: check-jsonschema --check-metaschema website/src/public/schema.json
ci-status:
name: ✅ CI
runs-on: ubuntu-latest
needs: [build, test, lint, lint-jsonschema]
if: always()
steps:
- name: ✅ Check CI status
run: |
if [[ "${{ needs.build.result }}" != "success" ]] || \
[[ "${{ needs.test.result }}" != "success" ]] || \
[[ "${{ needs.lint.result }}" != "success" ]] || \
[[ "${{ needs.lint-jsonschema.result }}" != "success" ]]; then
echo "CI failed"
exit 1
fi
echo "CI passed"

43
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Lint
on:
pull_request:
push:
tags:
- v*
branches:
- main
jobs:
lint:
name: Lint
strategy:
matrix:
go-version: [1.24.x, 1.25.x]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v6
with:
go-version: ${{matrix.go-version}}
- uses: actions/checkout@v6
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.7.2
lint-jsonschema:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v6
with:
python-version: 3.14
- uses: actions/checkout@v6
- name: install check-jsonschema
run: python -m pip install 'check-jsonschema==0.27.3'
- name: check-jsonschema (metaschema)
run: check-jsonschema --check-metaschema website/src/public/schema.json

38
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Test
on:
pull_request:
push:
tags:
- v*
branches:
- main
jobs:
test:
name: Test
strategy:
matrix:
go-version: [1.24.x, 1.25.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.platform}}
steps:
- name: Set up Go ${{matrix.go-version}}
uses: actions/setup-go@v6
with:
go-version: ${{matrix.go-version}}
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v6
- name: Download Go modules
run: go mod download
env:
GOPROXY: https://proxy.golang.org
- name: Build
run: go build -o ./bin/task -v ./cmd/task
- name: Test
run: ./bin/task test --output=group --output-group-begin='::group::{{.TASK}}' --output-group-end='::endgroup::'

View File

@@ -169,6 +169,6 @@ cloudsmiths:
rpm:
- "any-distro/any-version"
alpine:
- "any-distro/any-version"
- "alpine/any-version"
component: main
republish: true

View File

@@ -1,39 +1,77 @@
# Changelog
## Unreleased
## v3.46.2 - 2025-12-18
- Fixed a regression on previous release that affected variables passed via
command line (#2588, #2589 by @vmaerten).
## v3.46.1 - 2025-12-18
### ✨ Features
- A small behavior change was made to dependencies. Task will now wait for all
dependencies to finish running before continuing, even if any of them fail.
To opt for the previous behavior, set `failfast: true` either on your
dependencies to finish running before continuing, even if any of them fail. To
opt for the previous behavior, set `failfast: true` either on your
`.taskrc.yml` or per task, or use the `--failfast` flag, which will also work
for `--parallel` (#1246, #2525 by @andreynering).
- Fix RPM upload to Cloudsmith by including the version in the filename to
ensure unique filenames (#2507 by @vmaerten).
- Fix `run: when_changed` to work properly for Taskfiles included multiple times
(#2508, #2511 by @trulede).
- The `--summary` flag now displays `vars:` (both global and task-level),
`env:`, and `requires:` sections. Dynamic variables show their shell command
(e.g., `sh: echo "hello"`) instead of the evaluated value (#2486 ,#2524 by
@vmaerten).
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
flags and dynamic experimental feature detection (#2532 by @vmaerten).
- Improved performance of fuzzy task name matching by implementing lazy
initialization. Added `--disable-fuzzy` flag and `disable-fuzzy` taskrc option
to allow disabling fuzzy matching entirely (#2521, #2523 by @vmaerten).
- Added LLM-optimized documentation via VitePress plugin, generating `llms.txt`
and `llms-full.txt` for AI-powered development tools (#2513 by @vmaerten).
- Fixed Zsh and Fish completions to stop suggesting task names after `--`
separator, allowing proper CLI_ARGS completion (#1843, #1844 by
@boiledfroginthewell).
- Remote Taskfiles now accept `application/octet-stream` Content-Type (#2536,
#1944 by @vmaerten).
- Added `--trusted-hosts` CLI flag and `remote.trusted-hosts` config option to
skip confirmation prompts for specified hosts when using Remote Taskfiles
(#2491, #2473 by @maciejlech).
- When running in GitHub Actions, Task now automatically emits error annotations
on failure, improving visibility in workflow summaries (#2568 by @vmaerten).
- The `--yes` flag is now accessible in templates via the new `CLI_ASSUME_YES`
variable (#2577, #2479 by @semihbkgr).
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
flags and dynamic experimental feature detection (#2532 by @vmaerten).
- Remote Taskfiles now accept `application/octet-stream` Content-Type (#2536,
#1944 by @vmaerten).
- Shell completion now works when Task is installed or aliased under a different
binary name via TASK_EXE environment variable (#2495, #2468 by @vmaerten).
- Some small fixes and improvements were made to `task --init` and to the
default Taskfile it generates (#2433 by @andreynering).
- Added `--remote-cache-dir` flag and `remote.cache-dir` taskrc option to
customize the cache directory for Remote Taskfiles (#2572 by @vmaerten).
- Zsh completion now supports zstyle verbose option to show or hide task
descriptions (#2571 by @vmaerten).
- Task now automatically enables colored output in CI environments (GitHub
Actions, GitLab CI, etc.) without requiring FORCE_COLOR=1 (#2569 by
@vmaerten).
- Added color taskrc option to explicitly enable or disable colored output
globally (#2569 by @vmaerten).
- Improved Git Remote Taskfiles by switching to go-getter: SSH authentication
now works out of the box and `applyOf` is properly supported (#2512 by
@vmaerten).
### 🐛 Fixes
- Fix RPM upload to Cloudsmith by including the version in the filename to
ensure unique filenames (#2507 by @vmaerten).
- Fix `run: when_changed` to work properly for Taskfiles included multiple times
(#2508, #2511 by @trulede).
- Fixed Zsh and Fish completions to stop suggesting task names after `--`
separator, allowing proper CLI_ARGS completion (#1843, #1844 by
@boiledfroginthewell).
- Watch mode (`--watch`) now always runs the task, regardless of `run: once` or
`run: when_changed` settings (#2566, #1388 by @trulede).
- Fixed global variables (CLI_ARGS, CLI_FORCE, etc.) not being accessible in
root-level vars section (#2403, #2397 by @trulede, @vmaerten).
- Fixed a bug where `ignore_error` was ignored when using `task:` to call
another task (#2552, #363 by @trulede).
- Fixed Zsh completion not suggesting global tasks when using `-g`/`--global`
flag (#1574, #2574 by @vmaerten).
- Fixed Fish completion failing to parse task descriptions containing colons
(e.g., URLs or namespaced functions) (#2101, #2573 by @vmaerten).
- Fixed false positive "property 'for' is not allowed" warnings in IntelliJ when
using `for` loops in Taskfiles (#2576 by @vmaerten).
## v3.45.5 - 2025-11-11

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"github.com/spf13/pflag"
@@ -28,19 +29,34 @@ func main() {
Color: flags.Color,
}
if err, ok := err.(*errors.TaskRunError); ok && flags.ExitCode {
emitCIErrorAnnotation(err)
l.Errf(logger.Red, "%v\n", err)
os.Exit(err.TaskExitCode())
}
if err, ok := err.(errors.TaskError); ok {
emitCIErrorAnnotation(err)
l.Errf(logger.Red, "%v\n", err)
os.Exit(err.Code())
}
emitCIErrorAnnotation(err)
l.Errf(logger.Red, "%v\n", err)
os.Exit(errors.CodeUnknown)
}
os.Exit(errors.CodeOk)
}
// emitCIErrorAnnotation emits an error annotation for supported CI providers.
func emitCIErrorAnnotation(err error) {
if isGA, _ := strconv.ParseBool(os.Getenv("GITHUB_ACTIONS")); !isGA {
return
}
if e, ok := err.(*errors.TaskRunError); ok {
fmt.Fprintf(os.Stdout, "::error title=Task '%s' failed::%v\n", e.TaskName, e.Err)
return
}
fmt.Fprintf(os.Stdout, "::error title=Task failed::%v\n", err)
}
func run() error {
log := &logger.Logger{
Stdout: os.Stdout,
@@ -156,18 +172,23 @@ func run() error {
calls = append(calls, &task.Call{Task: "default"})
}
// Merge CLI variables first (e.g. FOO=bar) so they take priority over Taskfile defaults
e.Taskfile.Vars.Merge(globals, nil)
// Then ReverseMerge special variables so they're available for templating
cliArgsPostDashQuoted, err := args.ToQuotedString(cliArgsPostDash)
if err != nil {
return err
}
globals.Set("CLI_ARGS", ast.Var{Value: cliArgsPostDashQuoted})
globals.Set("CLI_ARGS_LIST", ast.Var{Value: cliArgsPostDash})
globals.Set("CLI_FORCE", ast.Var{Value: flags.Force || flags.ForceAll})
globals.Set("CLI_SILENT", ast.Var{Value: flags.Silent})
globals.Set("CLI_VERBOSE", ast.Var{Value: flags.Verbose})
globals.Set("CLI_OFFLINE", ast.Var{Value: flags.Offline})
e.Taskfile.Vars.Merge(globals, nil)
specialVars := ast.NewVars()
specialVars.Set("CLI_ARGS", ast.Var{Value: cliArgsPostDashQuoted})
specialVars.Set("CLI_ARGS_LIST", ast.Var{Value: cliArgsPostDash})
specialVars.Set("CLI_FORCE", ast.Var{Value: flags.Force || flags.ForceAll})
specialVars.Set("CLI_SILENT", ast.Var{Value: flags.Silent})
specialVars.Set("CLI_VERBOSE", ast.Var{Value: flags.Verbose})
specialVars.Set("CLI_OFFLINE", ast.Var{Value: flags.Offline})
specialVars.Set("CLI_ASSUME_YES", ast.Var{Value: flags.AssumeYes})
e.Taskfile.Vars.ReverseMerge(specialVars, nil)
if !flags.Watch {
e.InterceptInterruptSignals()
}

View File

@@ -22,7 +22,7 @@ function _task()
# Handle special arguments of options.
case "$prev" in
-d|--dir)
-d|--dir|--remote-cache-dir)
_filedir -d
return $?
;;

View File

@@ -54,7 +54,7 @@ function __task_get_tasks --description "Prints all available tasks with their d
end
# Grab names and descriptions (if any) of the tasks
set -l output (echo $rawOutput | sed -e '1d; s/\* \(.*\):\s*\(.*\)\s*(\(aliases.*\))/\1\t\2\t\3/' -e 's/\* \(.*\):\s*\(.*\)/\1\t\2/'| string split0)
set -l output (echo $rawOutput | sed -e '1d; s/\* \(.*\):\s\{2,\}\(.*\)\s\{2,\}(\(aliases.*\))/\1\t\2\t\3/' -e 's/\* \(.*\):\s\{2,\}\(.*\)/\1\t\2/'| string split0)
if test $output
echo $output
end
@@ -106,9 +106,10 @@ complete -c $GO_TASK_PROGNAME -s y -l yes -d 'assume yes t
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled GENTLE_FORCE" -l force-all -d 'force execution of task and all dependencies'
# RemoteTaskfiles experiment - Options
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l remote-cache-dir -d 'directory to cache remote Taskfiles' -xa "(__fish_complete_directories)"
# RemoteTaskfiles experiment - Operations
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l download -d 'download remote Taskfile'

View File

@@ -75,6 +75,7 @@ Register-ArgumentCompleter -CommandName task -ScriptBlock {
$completions += [CompletionResult]::new('--offline', '--offline', [CompletionResultType]::ParameterName, 'use cached Taskfiles')
$completions += [CompletionResult]::new('--timeout', '--timeout', [CompletionResultType]::ParameterName, 'download timeout')
$completions += [CompletionResult]::new('--expiry', '--expiry', [CompletionResultType]::ParameterName, 'cache expiry')
$completions += [CompletionResult]::new('--remote-cache-dir', '--remote-cache-dir', [CompletionResultType]::ParameterName, 'cache directory')
# Operations
$completions += [CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile')
$completions += [CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache')

View File

@@ -33,6 +33,10 @@ function __task_list() {
cmd+=(--taskfile "$taskfile")
fi
# Check if global flag is set
if (( ${+opt_args[(i)-g|--global]} )); then
cmd+=(--global)
fi
if output=$("${cmd[@]}" $_GO_TASK_COMPLETION_LIST_OPTION 2>/dev/null); then
enabled=1
@@ -41,12 +45,27 @@ function __task_list() {
(( enabled )) || return 0
scripts=()
# Read zstyle verbose option (default = true via -T)
local show_desc
zstyle -T ":completion:${curcontext}:" verbose && show_desc=true || show_desc=false
for item in "${(@)${(f)output}[2,-1]#\* }"; do
task="${item%%:[[:space:]]*}"
desc="${item##[^[:space:]]##[[:space:]]##}"
scripts+=( "${task//:/\\:}:$desc" )
if [[ "$show_desc" == "true" ]]; then
local desc="${item##[^[:space:]]##[[:space:]]##}"
scripts+=( "${task//:/\\:}:$desc" )
else
scripts+=( "$task" )
fi
done
_describe 'Task to run' scripts
if [[ "$show_desc" == "true" ]]; then
_describe 'Task to run' scripts
else
compadd -Q -a scripts
fi
}
_task() {
@@ -96,6 +115,7 @@ _task() {
'(--offline --download)--offline[use only local or cached Taskfiles]'
'(--timeout)--timeout[timeout for remote Taskfile downloads]:duration: '
'(--expiry)--expiry[cache expiry duration]:duration: '
'(--remote-cache-dir)--remote-cache-dir[directory to cache remote Taskfiles]:cache dir:_dirs'
)
fi

View File

@@ -37,6 +37,7 @@ type (
TrustedHosts []string
Timeout time.Duration
CacheExpiryDuration time.Duration
RemoteCacheDir string
Watch bool
Verbose bool
Silent bool
@@ -271,6 +272,19 @@ func (o *cacheExpiryDurationOption) ApplyToExecutor(r *Executor) {
r.CacheExpiryDuration = o.duration
}
// WithRemoteCacheDir sets the directory where remote taskfiles are cached.
func WithRemoteCacheDir(dir string) ExecutorOption {
return &remoteCacheDirOption{dir: dir}
}
type remoteCacheDirOption struct {
dir string
}
func (o *remoteCacheDirOption) ApplyToExecutor(e *Executor) {
e.RemoteCacheDir = o.dir
}
// WithWatch tells the [Executor] to keep running in the background and watch
// for changes to the fingerprint of the tasks that are run. When changes are
// detected, a new task run is triggered.

View File

@@ -263,6 +263,23 @@ func TestVars(t *testing.T) {
task.WithSilent(true),
),
)
NewExecutorTest(t,
WithName("cli-var-priority-default"),
WithExecutorOptions(
task.WithDir("testdata/vars"),
task.WithSilent(true),
),
WithTask("cli-var-priority"),
)
NewExecutorTest(t,
WithName("cli-var-priority-override"),
WithExecutorOptions(
task.WithDir("testdata/vars"),
task.WithSilent(true),
),
WithTask("cli-var-priority"),
WithVar("CLI_VAR", "from_cli"),
)
}
func TestRequires(t *testing.T) {

66
go.mod
View File

@@ -12,11 +12,10 @@ require (
github.com/elliotchance/orderedmap/v3 v3.1.0
github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.9.0
github.com/go-git/go-billy/v5 v5.7.0
github.com/go-git/go-git/v5 v5.16.4
github.com/go-task/slim-sprig/v3 v3.0.0
github.com/go-task/template v0.2.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-getter v1.8.3
github.com/joho/godotenv v1.5.1
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/puzpuzpuz/xsync/v4 v4.2.0
@@ -26,42 +25,69 @@ require (
github.com/stretchr/testify v1.11.1
github.com/zeebo/xxh3 v1.0.2
go.yaml.in/yaml/v4 v4.0.0-rc.3
golang.org/x/sync v0.18.0
golang.org/x/term v0.37.0
golang.org/x/sync v0.19.0
golang.org/x/term v0.38.0
mvdan.cc/sh/moreinterp v0.0.0-20251109230715-65adef8e2c5b
mvdan.cc/sh/v3 v3.12.0
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
cloud.google.com/go/storage v1.29.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.15 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.68 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 // indirect
github.com/aws/smithy-go v1.22.3 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.7.1 // indirect
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/u-root/u-root v0.15.1-0.20251014130006-62f7144b33da // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.45.0 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.38.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.114.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.56.3 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

256
go.sum
View File

@@ -1,32 +1,70 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg=
github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
github.com/aws/aws-sdk-go-v2/config v1.29.15 h1:I5XjesVMpDZXZEZonVfjI12VNMrYa38LtLnw4NtY5Ss=
github.com/aws/aws-sdk-go-v2/config v1.29.15/go.mod h1:tNIp4JIPonlsgaO5hxO372a6gjhN63aSWl2GVl5QoBQ=
github.com/aws/aws-sdk-go-v2/credentials v1.17.68 h1:cFb9yjI02/sWHBSYXAtkamjzCuRymvmeFmt0TC0MbYY=
github.com/aws/aws-sdk-go-v2/credentials v1.17.68/go.mod h1:H6E+jBzyqUu8u0vGaU6POkK3P0NylYEeRZ6ynBpMqIk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 h1:BCG7DCXEXpNCcpwCxg1oi9pkJWH2+eZzTn9MY56MbVw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1 h1:xYEAf/6QHiTZDccKnPMbsMwlau13GsDsTgdue3wmHGw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1/go.mod h1:qbn305Je/IofWBJ4bJz/Q7pDEtnnoInw/dGt71v6rHE=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 h1:oIaQ1e17CSKaWmUTu62MtraRWVIosn/iONMuZt0gbqc=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ=
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -36,48 +74,68 @@ github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucV
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg=
github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM=
github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-task/template v0.2.0 h1:xW7ek0o65FUSTbKcSNeg2Vyf/I7wYXFgLUznptvviBE=
github.com/go-task/template v0.2.0/go.mod h1:dbdoUb6qKnHQi1y6o+IdIrs0J4o/SEhSTA6bbzZmdtc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A=
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 h1:81+kWbE1yErFBMjME0I5k3x3kojjKsWtPYHEAutoPow=
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65/go.mod h1:WtMzv9T++tfWVea+qB2MXoaqxw33S8bpJslzUike2mQ=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-getter v1.8.3 h1:gIS+oTNv3kyYAvlUVgMR46MiG0bM0KuSON/KZEvRoRg=
github.com/hashicorp/go-getter v1.8.3/go.mod h1:CUTt9x2bCtJ/sV8ihgrITL3IUE+0BE1j/e4n5P/GIM4=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
@@ -91,26 +149,20 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v4 v4.1.0 h1:x9eHRl4QhZFIPJ17yl4KKW9xLyVWbb3/Yq4SXpjF71U=
github.com/puzpuzpuz/xsync/v4 v4.1.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -122,69 +174,119 @@ github.com/sebdah/goldie/v2 v2.8.0/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvK
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/u-root/u-root v0.15.1-0.20251014130006-62f7144b33da h1:Vst9Tvq3G6f6pYBvxy7coi2arDsnOZ3Mkj8MkNarSK8=
github.com/u-root/u-root v0.15.1-0.20251014130006-62f7144b33da/go.mod h1:R49zft13memK20EgFAvmTbXBS0t29UvglnM0BCA1ldQ=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
mvdan.cc/sh/moreinterp v0.0.0-20251109230715-65adef8e2c5b h1:vTpx76nZDTP/BAGnnhEXYjM+8nPKe9+I86qCErBvjCw=
mvdan.cc/sh/moreinterp v0.0.0-20251109230715-65adef8e2c5b/go.mod h1:bDyKbUYKqkFunWmxxuSPrkYpln9QZcUsqu7W128qYW4=
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=

View File

@@ -5,13 +5,16 @@ import (
"log"
"os"
"path/filepath"
"strconv"
"time"
"github.com/fatih/color"
"github.com/spf13/pflag"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/experiments"
"github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/sort"
"github.com/go-task/task/v3/taskfile/ast"
"github.com/go-task/task/v3/taskrc"
@@ -79,6 +82,7 @@ var (
ClearCache bool
Timeout time.Duration
CacheExpiryDuration time.Duration
RemoteCacheDir string
)
func init() {
@@ -138,7 +142,7 @@ func init() {
pflag.StringVar(&Output.Group.Begin, "output-group-begin", "", "Message template to print before a task's grouped output.")
pflag.StringVar(&Output.Group.End, "output-group-end", "", "Message template to print after a task's grouped output.")
pflag.BoolVar(&Output.Group.ErrorOnly, "output-group-error-only", false, "Swallow output from successful tasks.")
pflag.BoolVarP(&Color, "color", "c", true, "Colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable.")
pflag.BoolVarP(&Color, "color", "c", getConfig(config, func() *bool { return config.Color }, true), "Colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable.")
pflag.IntVarP(&Concurrency, "concurrency", "C", getConfig(config, func() *int { return config.Concurrency }, 0), "Limit number of tasks to run concurrently.")
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
pflag.BoolVarP(&Failfast, "failfast", "F", getConfig(config, func() *bool { return &config.Failfast }, false), "When running tasks in parallel, stop all tasks if one fails.")
@@ -157,12 +161,36 @@ func init() {
if experiments.RemoteTaskfiles.Enabled() {
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.")
pflag.BoolVar(&Offline, "offline", getConfig(config, func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.")
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", config.Remote.TrustedHosts, "List of trusted hosts for remote Taskfiles (comma-separated).")
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).")
pflag.DurationVar(&Timeout, "timeout", getConfig(config, func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.")
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
pflag.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, func() *time.Duration { return config.Remote.CacheExpiry }, 0), "Expiry duration for cached remote Taskfiles.")
pflag.StringVar(&RemoteCacheDir, "remote-cache-dir", getConfig(config, func() *string { return config.Remote.CacheDir }, env.GetTaskEnv("REMOTE_DIR")), "Directory to cache remote Taskfiles.")
}
pflag.Parse()
// Auto-detect color based on environment when not explicitly configured
// Priority: CLI flag > taskrc config > NO_COLOR > FORCE_COLOR/CI > default
colorExplicitlySet := pflag.Lookup("color").Changed || (config != nil && config.Color != nil)
if !colorExplicitlySet {
if os.Getenv("NO_COLOR") != "" {
Color = false
color.NoColor = true
} else if os.Getenv("FORCE_COLOR") != "" || isCI() {
Color = true
color.NoColor = false // Force colors even without TTY
}
// Otherwise, let fatih/color auto-detect TTY
} else {
// Explicit config: sync with fatih/color
color.NoColor = !Color
}
}
// isCI returns true if running in a CI environment
func isCI() bool {
ci, _ := strconv.ParseBool(os.Getenv("CI"))
return ci
}
func Validate() error {
@@ -247,6 +275,7 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
task.WithTrustedHosts(TrustedHosts),
task.WithTimeout(Timeout),
task.WithCacheExpiryDuration(CacheExpiryDuration),
task.WithRemoteCacheDir(RemoteCacheDir),
task.WithWatch(Watch),
task.WithVerbose(Verbose),
task.WithSilent(Silent),

View File

@@ -3,7 +3,6 @@ package logger
import (
"bufio"
"io"
"os"
"slices"
"strconv"
"strings"
@@ -96,10 +95,6 @@ func BrightRed() PrintFunc {
}
func envColor(name string, defaultColor color.Attribute) []color.Attribute {
if os.Getenv("FORCE_COLOR") != "" {
color.NoColor = false
}
// Fetch the environment variable
override := env.GetTaskEnv(name)

View File

@@ -1 +1 @@
3.45.5
3.46.2

View File

@@ -153,16 +153,16 @@ func (e *Executor) setupTempDir() error {
}
}
remoteDir := env.GetTaskEnv("REMOTE_DIR")
if remoteDir != "" {
if filepath.IsAbs(remoteDir) || strings.HasPrefix(remoteDir, "~") {
remoteTempDir, err := execext.ExpandLiteral(remoteDir)
// RemoteCacheDir from taskrc/env can override the remote cache directory
if e.RemoteCacheDir != "" {
if filepath.IsAbs(e.RemoteCacheDir) || strings.HasPrefix(e.RemoteCacheDir, "~") {
remoteCacheDir, err := execext.ExpandLiteral(e.RemoteCacheDir)
if err != nil {
return err
}
e.TempDir.Remote = remoteTempDir
e.TempDir.Remote = remoteCacheDir
} else {
e.TempDir.Remote = filepathext.SmartJoin(e.Dir, ".task")
e.TempDir.Remote = filepathext.SmartJoin(e.Dir, e.RemoteCacheDir)
}
}

10
task.go
View File

@@ -311,10 +311,12 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
defer reacquire()
err := e.RunTask(ctx, &Call{Task: cmd.Task, Vars: cmd.Vars, Silent: cmd.Silent, Indirect: true})
if err != nil {
return err
var exitCode interp.ExitStatus
if errors.As(err, &exitCode) && cmd.IgnoreError {
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] task error ignored: %v\n", t.Name(), err)
return nil
}
return nil
return err
case cmd.Cmd != "":
if !shouldRunOnCurrentPlatform(cmd.Platforms) {
e.Logger.VerboseOutf(logger.Yellow, "task: [%s] %s not for current platform - ignored\n", t.Name(), cmd.Cmd)
@@ -370,7 +372,7 @@ func (e *Executor) startExecution(ctx context.Context, t *ast.Task, execute func
return err
}
if h == "" {
if h == "" || t.Watch {
return execute(ctx)
}

View File

@@ -93,6 +93,7 @@ func (c *Cmd) UnmarshalYAML(node *yaml.Node) error {
c.Vars = cmdStruct.Vars
c.For = cmdStruct.For
c.Silent = cmdStruct.Silent
c.IgnoreError = cmdStruct.IgnoreError
return nil
}

View File

@@ -118,7 +118,7 @@ func (vars *Vars) ToCacheMap() (m map[string]any) {
// Merge loops over other and merges it values with the variables in vars. If
// the include parameter is not nil and its it is an advanced import, the
// directory is set set to the value of the include parameter.
// directory is set to the value of the include parameter.
func (vars *Vars) Merge(other *Vars, include *Include) {
if vars == nil || vars.om == nil || other == nil {
return
@@ -133,6 +133,35 @@ func (vars *Vars) Merge(other *Vars, include *Include) {
}
}
// ReverseMerge merges other variables with the existing variables in vars, but
// keeps the other variables first in order. If the include parameter is not
// nil and it is an advanced import, the directory is set to the value of the
// include parameter.
func (vars *Vars) ReverseMerge(other *Vars, include *Include) {
if vars == nil || vars.om == nil || other == nil || other.om == nil {
return
}
newOM := orderedmap.NewOrderedMap[string, Var]()
other.mutex.RLock()
for pair := other.om.Front(); pair != nil; pair = pair.Next() {
val := pair.Value
if include != nil && include.AdvancedImport {
val.Dir = include.Dir
}
newOM.Set(pair.Key, val)
}
other.mutex.RUnlock()
vars.mutex.Lock()
for pair := vars.om.Front(); pair != nil; pair = pair.Next() {
newOM.Set(pair.Key, pair.Value)
}
vars.om = newOM
vars.mutex.Unlock()
}
func (vs *Vars) DeepCopy() *Vars {
if vs == nil {
return nil

View File

@@ -3,16 +3,14 @@ package taskfile
import (
"context"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
giturls "github.com/chainguard-dev/git-urls"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
"github.com/hashicorp/go-getter"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/execext"
@@ -28,6 +26,36 @@ type GitNode struct {
path string
}
type gitRepoCache struct {
mu sync.Mutex // Protects the locks map
locks map[string]*sync.Mutex // One mutex per repo cache key
}
func (c *gitRepoCache) getLockForRepo(cacheKey string) *sync.Mutex {
c.mu.Lock()
defer c.mu.Unlock()
if _, exists := c.locks[cacheKey]; !exists {
c.locks[cacheKey] = &sync.Mutex{}
}
return c.locks[cacheKey]
}
var globalGitRepoCache = &gitRepoCache{
locks: make(map[string]*sync.Mutex),
}
func CleanGitCache() error {
// Clear the in-memory locks map to prevent memory leak
globalGitRepoCache.mu.Lock()
globalGitRepoCache.locks = make(map[string]*sync.Mutex)
globalGitRepoCache.mu.Unlock()
cacheDir := filepath.Join(os.TempDir(), "task-git-repos")
return os.RemoveAll(cacheDir)
}
func NewGitNode(
entrypoint string,
dir string,
@@ -72,24 +100,78 @@ func (node *GitNode) Read() ([]byte, error) {
return node.ReadContext(context.Background())
}
func (node *GitNode) ReadContext(_ context.Context) ([]byte, error) {
fs := memfs.New()
storer := memory.NewStorage()
_, err := git.Clone(storer, fs, &git.CloneOptions{
URL: node.url.String(),
ReferenceName: plumbing.ReferenceName(node.ref),
SingleBranch: true,
Depth: 1,
})
func (node *GitNode) buildURL() string {
// Get the base URL
baseURL := node.url.String()
ref := node.ref
if ref == "" {
ref = "HEAD"
}
// Always use git:: prefix for git URLs (following Terraform's pattern)
// This forces go-getter to use git protocol
return fmt.Sprintf("git::%s?ref=%s&depth=1", baseURL, ref)
}
// getOrCloneRepo returns the path to a cached git repository.
// If the repository is not cached, it clones it first.
// This function is thread-safe: multiple goroutines cloning the same repo+ref
// will synchronize, and only one clone operation will occur.
//
// The cache directory is /tmp/task-git-repos/{cache_key}/
func (node *GitNode) getOrCloneRepo(ctx context.Context) (string, error) {
cacheKey := node.repoCacheKey()
repoMutex := globalGitRepoCache.getLockForRepo(cacheKey)
repoMutex.Lock()
defer repoMutex.Unlock()
// Check if context was cancelled while waiting for lock
if err := ctx.Err(); err != nil {
return "", fmt.Errorf("context cancelled while waiting for repository lock: %w", err)
}
cacheDir := filepath.Join(os.TempDir(), "task-git-repos", cacheKey)
// check if repo is already cached (under the lock)
gitDir := filepath.Join(cacheDir, ".git")
if _, err := os.Stat(gitDir); err == nil {
return cacheDir, nil
}
getterURL := node.buildURL()
client := &getter.Client{
Ctx: ctx,
Src: getterURL,
Dst: cacheDir,
Mode: getter.ClientModeDir,
}
if err := client.Get(); err != nil {
_ = os.RemoveAll(cacheDir)
return "", fmt.Errorf("failed to clone repository: %w", err)
}
return cacheDir, nil
}
func (node *GitNode) ReadContext(ctx context.Context) ([]byte, error) {
// Get or clone the repository into cache
repoDir, err := node.getOrCloneRepo(ctx)
if err != nil {
return nil, err
}
file, err := fs.Open(node.path)
if err != nil {
return nil, err
// Build path to Taskfile in the cached repo
taskfilePath := node.path
if taskfilePath == "" {
taskfilePath = "Taskfile.yml"
}
// Read the entire response body
b, err := io.ReadAll(file)
filePath := filepath.Join(repoDir, taskfilePath)
// Read file from cached repo
b, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
@@ -138,6 +220,22 @@ func (node *GitNode) CacheKey() string {
return fmt.Sprintf("git.%s.%s.%s", node.url.Host, prefix, checksum)
}
// repoCacheKey generates a unique cache key for the repository+ref combination.
// Unlike CacheKey() which includes the file path, this identifies the repository itself.
// Two GitNodes with the same repo+ref but different file paths will share the same cache.
//
// Returns a path like: github.com/user/repo.git/main
func (node *GitNode) repoCacheKey() string {
repoPath := strings.Trim(node.url.Path, "/")
ref := node.ref
if ref == "" {
ref = "HEAD"
}
return filepath.Join(node.url.Host, repoPath, ref)
}
func splitURLOnDoubleSlash(u *url.URL) (string, string) {
x := strings.Split(u.Path, "//")
switch len(x) {

View File

@@ -102,3 +102,146 @@ func TestGitNode_CacheKey(t *testing.T) {
assert.Equal(t, tt.expectedKey, key)
}
}
func TestGitNode_buildURL(t *testing.T) {
t.Parallel()
tests := []struct {
name string
entrypoint string
expectedURL string
}{
{
name: "HTTPS with ref",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
expectedURL: "git::https://github.com/foo/bar.git?ref=main&depth=1",
},
{
name: "SSH with ref",
entrypoint: "git@github.com:foo/bar.git//Taskfile.yml?ref=main",
expectedURL: "git::ssh://git@github.com/foo/bar.git?ref=main&depth=1",
},
{
name: "HTTPS with tag ref",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=v1.0.0",
expectedURL: "git::https://github.com/foo/bar.git?ref=v1.0.0&depth=1",
},
{
name: "HTTPS without ref (uses remote HEAD)",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml",
expectedURL: "git::https://github.com/foo/bar.git?ref=HEAD&depth=1",
},
{
name: "SSH with directory path",
entrypoint: "git@github.com:foo/bar.git//directory/Taskfile.yml?ref=dev",
expectedURL: "git::ssh://git@github.com/foo/bar.git?ref=dev&depth=1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
node, err := NewGitNode(tt.entrypoint, "", false)
require.NoError(t, err)
gotURL := node.buildURL()
assert.Equal(t, tt.expectedURL, gotURL)
})
}
}
func TestRepoCacheKey_SameRepoSameRef(t *testing.T) {
t.Parallel()
// Same repo, same ref, different files should have SAME cache key
node1, err := NewGitNode("https://github.com/foo/bar.git//file1.yml?ref=main", "", false)
require.NoError(t, err)
node2, err := NewGitNode("https://github.com/foo/bar.git//dir/file2.yml?ref=main", "", false)
require.NoError(t, err)
key1 := node1.repoCacheKey()
key2 := node2.repoCacheKey()
assert.Equal(t, key1, key2, "Same repo+ref should generate same cache key regardless of file path")
}
func TestRepoCacheKey_SameRepoDifferentRef(t *testing.T) {
t.Parallel()
// Same repo, different ref should have DIFFERENT cache keys
node1, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=main", "", false)
require.NoError(t, err)
node2, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=dev", "", false)
require.NoError(t, err)
key1 := node1.repoCacheKey()
key2 := node2.repoCacheKey()
assert.NotEqual(t, key1, key2, "Different refs should generate different cache keys")
}
func TestRepoCacheKey_DifferentRepos(t *testing.T) {
t.Parallel()
// Different repos should have DIFFERENT cache keys
node1, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=main", "", false)
require.NoError(t, err)
node2, err := NewGitNode("https://github.com/foo/other.git//file.yml?ref=main", "", false)
require.NoError(t, err)
key1 := node1.repoCacheKey()
key2 := node2.repoCacheKey()
assert.NotEqual(t, key1, key2, "Different repos should generate different cache keys")
}
func TestRepoCacheKey_NoRefVsHead(t *testing.T) {
t.Parallel()
// No ref (defaults to HEAD) vs explicit HEAD should have SAME cache key
node1, err := NewGitNode("https://github.com/foo/bar.git//file.yml", "", false)
require.NoError(t, err)
node2, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=HEAD", "", false)
require.NoError(t, err)
key1 := node1.repoCacheKey()
key2 := node2.repoCacheKey()
assert.Equal(t, key1, key2, "No ref and explicit HEAD should generate same cache key")
}
func TestRepoCacheKey_SSHvsHTTPS(t *testing.T) {
t.Parallel()
// SSH vs HTTPS pointing to same repo should have SAME cache key
// They clone the same repo, so we want to share the cache
node1, err := NewGitNode("git@github.com:foo/bar.git//file.yml?ref=main", "", false)
require.NoError(t, err)
node2, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=main", "", false)
require.NoError(t, err)
key1 := node1.repoCacheKey()
key2 := node2.repoCacheKey()
assert.Equal(t, key1, key2, "SSH and HTTPS for same repo should share cache")
}
func TestRepoCacheKey_Consistency(t *testing.T) {
t.Parallel()
// Calling repoCacheKey multiple times on same node should return same key
node, err := NewGitNode("https://github.com/foo/bar.git//file.yml?ref=main", "", false)
require.NoError(t, err)
key1 := node.repoCacheKey()
key2 := node.repoCacheKey()
key3 := node.repoCacheKey()
assert.Equal(t, key1, key2)
assert.Equal(t, key2, key3)
}

View File

@@ -204,9 +204,15 @@ func (o *promptFuncOption) ApplyToReader(r *Reader) {
// building an [ast.TaskfileGraph] as it goes. If any errors occur, they will be
// returned immediately.
func (r *Reader) Read(ctx context.Context, node Node) (*ast.TaskfileGraph, error) {
// Clean up git cache after reading all taskfiles
defer func() {
_ = CleanGitCache()
}()
if err := r.include(ctx, node); err != nil {
return nil, err
}
return r.graph, nil
}

View File

@@ -12,6 +12,7 @@ import (
type TaskRC struct {
Version *semver.Version `yaml:"version"`
Verbose *bool `yaml:"verbose"`
Color *bool `yaml:"color"`
DisableFuzzy *bool `yaml:"disable-fuzzy"`
Concurrency *int `yaml:"concurrency"`
Remote Remote `yaml:"remote"`
@@ -24,6 +25,7 @@ type Remote struct {
Offline *bool `yaml:"offline"`
Timeout *time.Duration `yaml:"timeout"`
CacheExpiry *time.Duration `yaml:"cache-expiry"`
CacheDir *string `yaml:"cache-dir"`
TrustedHosts []string `yaml:"trusted-hosts"`
}
@@ -46,7 +48,7 @@ func (t *TaskRC) Merge(other *TaskRC) {
t.Remote.Offline = cmp.Or(other.Remote.Offline, t.Remote.Offline)
t.Remote.Timeout = cmp.Or(other.Remote.Timeout, t.Remote.Timeout)
t.Remote.CacheExpiry = cmp.Or(other.Remote.CacheExpiry, t.Remote.CacheExpiry)
t.Remote.CacheDir = cmp.Or(other.Remote.CacheDir, t.Remote.CacheDir)
if len(other.Remote.TrustedHosts) > 0 {
merged := slices.Concat(other.Remote.TrustedHosts, t.Remote.TrustedHosts)
slices.Sort(merged)
@@ -54,6 +56,7 @@ func (t *TaskRC) Merge(other *TaskRC) {
}
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
t.Color = cmp.Or(other.Color, t.Color)
t.DisableFuzzy = cmp.Or(other.DisableFuzzy, t.DisableFuzzy)
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
t.Failfast = cmp.Or(other.Failfast, t.Failfast)

View File

@@ -49,3 +49,10 @@ tasks:
- echo "{{.MESSAGE}}"
from-dot-env: echo '{{.DOT_ENV_VAR}}'
# Test that CLI variables take priority over Taskfile defaults
cli-var-priority:
vars:
CLI_VAR: '{{.CLI_VAR | default "default_value"}}'
cmds:
- echo '{{.CLI_VAR}}'

View File

@@ -0,0 +1 @@
default_value

View File

@@ -0,0 +1 @@
from_cli

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'vitepress';
import { defineConfig, HeadConfig } from 'vitepress';
import githubLinksPlugin from './plugins/github-links';
import { readFileSync } from 'fs';
import { resolve } from 'path';
@@ -9,7 +9,7 @@ import {
localIconLoader
} from 'vitepress-plugin-group-icons';
import { team } from './team.ts';
import { taskDescription, taskName } from './meta.ts';
import { taskDescription, taskName, ogUrl, ogImage } from './meta.ts';
import { fileURLToPath, URL } from 'node:url';
import llmstxt, { copyOrDownloadAsMarkdownButtons } from 'vitepress-plugin-llms';
@@ -40,7 +40,7 @@ export default defineConfig({
{
rel: 'icon',
type: 'image/x-icon',
href: '/img/favicon.icon',
href: '/img/favicon.ico',
sizes: '48x48'
}
],
@@ -53,17 +53,23 @@ export default defineConfig({
href: '/img/logo.svg'
}
],
[
'link',
{
rel: 'canonical',
href: 'https://taskfile.dev/'
}
],
[
'meta',
{ name: 'author', content: `${team.map((c) => c.name).join(', ')}` }
],
// Open Graph
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:site_name', content: taskName }],
['meta', { property: 'og:title', content: taskName }],
['meta', { property: 'og:description', content: taskDescription }],
['meta', { property: 'og:image', content: ogImage }],
['meta', { property: 'og:url', content: ogUrl }],
// Twitter Card
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['meta', { name: 'twitter:site', content: '@taskfiledev' }],
['meta', { name: 'twitter:title', content: taskName }],
['meta', { name: 'twitter:description', content: taskDescription }],
['meta', { name: 'twitter:image', content: ogImage }],
[
'meta',
{
@@ -81,6 +87,22 @@ export default defineConfig({
}
]
],
transformHead({ pageData }) {
const head: HeadConfig[] = []
// Canonical URL dynamique
const canonicalUrl = `https://taskfile.dev/${pageData.relativePath
.replace(/\.md$/, '')
.replace(/index$/, '')}`
head.push(['link', { rel: 'canonical', href: canonicalUrl }])
// Noindex pour 404
if (pageData.relativePath === '404.md') {
head.push(['meta', { name: 'robots', content: 'noindex, nofollow' }])
}
return head
},
srcDir: 'src',
cleanUrls: true,
markdown: {
@@ -342,6 +364,12 @@ export default defineConfig({
}
},
sitemap: {
hostname: 'https://taskfile.dev'
hostname: 'https://taskfile.dev',
transformItems: (items) => {
return items.map((item) => ({
...item,
lastmod: new Date().toISOString()
}));
}
}
});

View File

@@ -3,3 +3,4 @@ export const taskDescription =
'A fast, cross-platform build tool inspired by Make, designed for modern workflows.';
export const ogUrl = 'https://taskfile.dev/';
export const ogImage = 'https://taskfile.dev/img/logo.png';

View File

@@ -20,10 +20,8 @@
"vitepress": "^1.6.3",
"vitepress-plugin-group-icons": "^1.6.1",
"vitepress-plugin-tabs": "^0.7.1",
"vitepress-plugin-llms": "^1.9.1",
"vue": "^3.5.18"
},
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a",
"dependencies": {
"vitepress-plugin-llms": "^1.9.1"
}
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
}

77
website/pnpm-lock.yaml generated
View File

@@ -7,32 +7,31 @@ settings:
importers:
.:
dependencies:
vitepress-plugin-llms:
specifier: ^1.9.1
version: 1.9.3
devDependencies:
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/node':
specifier: ^24.1.0
version: 24.10.1
version: 24.10.4
netlify-cli:
specifier: ^23.1.1
version: 23.12.3(@types/node@24.10.1)(picomatch@4.0.3)(rollup@4.46.2)
version: 23.12.3(@types/node@24.10.4)(picomatch@4.0.3)(rollup@4.46.2)
prettier:
specifier: ^3.6.2
version: 3.7.4
vitepress:
specifier: ^1.6.3
version: 1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.1)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3)
version: 1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.4)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3)
vitepress-plugin-group-icons:
specifier: ^1.6.1
version: 1.6.5(vite@5.4.19(@types/node@24.10.1))
version: 1.6.5(vite@5.4.19(@types/node@24.10.4))
vitepress-plugin-llms:
specifier: ^1.9.1
version: 1.9.3
vitepress-plugin-tabs:
specifier: ^0.7.1
version: 0.7.3(vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.1)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))
version: 0.7.3(vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.4)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))
vue:
specifier: ^3.5.18
version: 3.5.25(typescript@5.9.3)
@@ -1543,8 +1542,8 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@24.10.1':
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
'@types/node@24.10.4':
resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -5639,12 +5638,12 @@ snapshots:
'@import-maps/resolve@2.0.0': {}
'@inquirer/external-editor@1.0.3(@types/node@24.10.1)':
'@inquirer/external-editor@1.0.3(@types/node@24.10.4)':
dependencies:
chardet: 2.1.1
iconv-lite: 0.7.0
optionalDependencies:
'@types/node': 24.10.1
'@types/node': 24.10.4
'@isaacs/balanced-match@4.0.1': {}
@@ -5727,7 +5726,7 @@ snapshots:
yaml: 2.8.2
yargs: 17.7.2
'@netlify/build@35.5.2(@opentelemetry/api@1.8.0)(@types/node@24.10.1)(picomatch@4.0.3)(rollup@4.46.2)':
'@netlify/build@35.5.2(@opentelemetry/api@1.8.0)(@types/node@24.10.4)(picomatch@4.0.3)(rollup@4.46.2)':
dependencies:
'@bugsnag/js': 8.6.0
'@netlify/blobs': 10.4.2(supports-color@10.2.2)
@@ -5775,7 +5774,7 @@ snapshots:
string-width: 7.2.0
supports-color: 10.2.2
terminal-link: 4.0.0
ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
ts-node: 10.9.2(@types/node@24.10.4)(typescript@5.9.3)
typescript: 5.9.3
uuid: 11.1.0
yaml: 2.8.2
@@ -6481,7 +6480,7 @@ snapshots:
'@types/http-proxy@1.17.17':
dependencies:
'@types/node': 24.10.1
'@types/node': 24.10.4
'@types/linkify-it@5.0.0': {}
@@ -6498,7 +6497,7 @@ snapshots:
'@types/ms@2.1.0': {}
'@types/node@24.10.1':
'@types/node@24.10.4':
dependencies:
undici-types: 7.16.0
@@ -6514,7 +6513,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 24.10.1
'@types/node': 24.10.4
optional: true
'@typescript-eslint/project-service@8.48.1(supports-color@10.2.2)(typescript@5.9.3)':
@@ -6573,9 +6572,9 @@ snapshots:
- rollup
- supports-color
'@vitejs/plugin-vue@5.2.4(vite@5.4.19(@types/node@24.10.1))(vue@3.5.25(typescript@5.9.3))':
'@vitejs/plugin-vue@5.2.4(vite@5.4.19(@types/node@24.10.4))(vue@3.5.25(typescript@5.9.3))':
dependencies:
vite: 5.4.19(@types/node@24.10.1)
vite: 5.4.19(@types/node@24.10.4)
vue: 3.5.25(typescript@5.9.3)
'@vue/compiler-core@3.5.25':
@@ -8157,18 +8156,18 @@ snapshots:
ini@4.1.1: {}
inquirer-autocomplete-prompt@1.4.0(inquirer@8.2.7(@types/node@24.10.1)):
inquirer-autocomplete-prompt@1.4.0(inquirer@8.2.7(@types/node@24.10.4)):
dependencies:
ansi-escapes: 4.3.2
chalk: 4.1.2
figures: 3.2.0
inquirer: 8.2.7(@types/node@24.10.1)
inquirer: 8.2.7(@types/node@24.10.4)
run-async: 2.4.1
rxjs: 6.6.7
inquirer@8.2.7(@types/node@24.10.1):
inquirer@8.2.7(@types/node@24.10.4):
dependencies:
'@inquirer/external-editor': 1.0.3(@types/node@24.10.1)
'@inquirer/external-editor': 1.0.3(@types/node@24.10.4)
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-cursor: 3.1.0
@@ -8869,13 +8868,13 @@ snapshots:
negotiator@0.6.3: {}
netlify-cli@23.12.3(@types/node@24.10.1)(picomatch@4.0.3)(rollup@4.46.2):
netlify-cli@23.12.3(@types/node@24.10.4)(picomatch@4.0.3)(rollup@4.46.2):
dependencies:
'@fastify/static': 7.0.4
'@netlify/ai': 0.3.4(@netlify/api@14.0.11)
'@netlify/api': 14.0.11
'@netlify/blobs': 10.1.0
'@netlify/build': 35.5.2(@opentelemetry/api@1.8.0)(@types/node@24.10.1)(picomatch@4.0.3)(rollup@4.46.2)
'@netlify/build': 35.5.2(@opentelemetry/api@1.8.0)(@types/node@24.10.4)(picomatch@4.0.3)(rollup@4.46.2)
'@netlify/build-info': 10.0.10
'@netlify/config': 24.1.1
'@netlify/dev-utils': 4.3.2
@@ -8926,8 +8925,8 @@ snapshots:
http-proxy: 1.18.1(debug@4.4.3)
http-proxy-middleware: 2.0.9(debug@4.4.3)
https-proxy-agent: 7.0.6(supports-color@10.2.2)
inquirer: 8.2.7(@types/node@24.10.1)
inquirer-autocomplete-prompt: 1.4.0(inquirer@8.2.7(@types/node@24.10.1))
inquirer: 8.2.7(@types/node@24.10.4)
inquirer-autocomplete-prompt: 1.4.0(inquirer@8.2.7(@types/node@24.10.4))
ipx: 3.1.1(@netlify/blobs@10.1.0)
is-docker: 3.0.0
is-stream: 4.0.1
@@ -10024,14 +10023,14 @@ snapshots:
dependencies:
typescript: 5.9.3
ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3):
ts-node@10.9.2(@types/node@24.10.4)(typescript@5.9.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.12
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
'@types/node': 24.10.1
'@types/node': 24.10.4
acorn: 8.15.0
acorn-walk: 8.3.4
arg: 4.1.3
@@ -10202,22 +10201,22 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
vite@5.4.19(@types/node@24.10.1):
vite@5.4.19(@types/node@24.10.4):
dependencies:
esbuild: 0.21.5
postcss: 8.5.6
rollup: 4.46.2
optionalDependencies:
'@types/node': 24.10.1
'@types/node': 24.10.4
fsevents: 2.3.3
vitepress-plugin-group-icons@1.6.5(vite@5.4.19(@types/node@24.10.1)):
vitepress-plugin-group-icons@1.6.5(vite@5.4.19(@types/node@24.10.4)):
dependencies:
'@iconify-json/logos': 1.2.10
'@iconify-json/vscode-icons': 1.2.33
'@iconify/utils': 3.0.2
optionalDependencies:
vite: 5.4.19(@types/node@24.10.1)
vite: 5.4.19(@types/node@24.10.4)
transitivePeerDependencies:
- supports-color
@@ -10240,12 +10239,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
vitepress-plugin-tabs@0.7.3(vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.1)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)):
vitepress-plugin-tabs@0.7.3(vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.4)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)):
dependencies:
vitepress: 1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.1)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3)
vitepress: 1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.4)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.1)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3):
vitepress@1.6.4(@algolia/client-search@5.35.0)(@types/node@24.10.4)(jwt-decode@4.0.0)(postcss@8.5.6)(search-insights@2.17.3)(typescript@5.9.3):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.35.0)(search-insights@2.17.3)
@@ -10254,7 +10253,7 @@ snapshots:
'@shikijs/transformers': 2.5.0
'@shikijs/types': 2.5.0
'@types/markdown-it': 14.1.2
'@vitejs/plugin-vue': 5.2.4(vite@5.4.19(@types/node@24.10.1))(vue@3.5.25(typescript@5.9.3))
'@vitejs/plugin-vue': 5.2.4(vite@5.4.19(@types/node@24.10.4))(vue@3.5.25(typescript@5.9.3))
'@vue/devtools-api': 7.7.7
'@vue/shared': 3.5.18
'@vueuse/core': 12.8.2(typescript@5.9.3)
@@ -10263,7 +10262,7 @@ snapshots:
mark.js: 8.11.1
minisearch: 7.1.2
shiki: 2.5.0
vite: 5.4.19(@types/node@24.10.1)
vite: 5.4.19(@types/node@24.10.4)
vue: 3.5.25(typescript@5.9.3)
optionalDependencies:
postcss: 8.5.6

View File

@@ -7,6 +7,79 @@ outline: deep
::: v-pre
## v3.46.2 - 2025-12-18
- Fixed a regression on previous release that affected variables passed via
command line (#2588, #2589 by @vmaerten).
## v3.46.1 - 2025-12-18
### ✨ Features
- A small behavior change was made to dependencies. Task will now wait for all
dependencies to finish running before continuing, even if any of them fail. To
opt for the previous behavior, set `failfast: true` either on your
`.taskrc.yml` or per task, or use the `--failfast` flag, which will also work
for `--parallel` (#1246, #2525 by @andreynering).
- The `--summary` flag now displays `vars:` (both global and task-level),
`env:`, and `requires:` sections. Dynamic variables show their shell command
(e.g., `sh: echo "hello"`) instead of the evaluated value (#2486 ,#2524 by
@vmaerten).
- Improved performance of fuzzy task name matching by implementing lazy
initialization. Added `--disable-fuzzy` flag and `disable-fuzzy` taskrc option
to allow disabling fuzzy matching entirely (#2521, #2523 by @vmaerten).
- Added LLM-optimized documentation via VitePress plugin, generating `llms.txt`
and `llms-full.txt` for AI-powered development tools (#2513 by @vmaerten).
- Added `--trusted-hosts` CLI flag and `remote.trusted-hosts` config option to
skip confirmation prompts for specified hosts when using Remote Taskfiles
(#2491, #2473 by @maciejlech).
- When running in GitHub Actions, Task now automatically emits error annotations
on failure, improving visibility in workflow summaries (#2568 by @vmaerten).
- The `--yes` flag is now accessible in templates via the new `CLI_ASSUME_YES`
variable (#2577, #2479 by @semihbkgr).
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
flags and dynamic experimental feature detection (#2532 by @vmaerten).
- Remote Taskfiles now accept `application/octet-stream` Content-Type (#2536,
#1944 by @vmaerten).
- Shell completion now works when Task is installed or aliased under a different
binary name via TASK_EXE environment variable (#2495, #2468 by @vmaerten).
- Some small fixes and improvements were made to `task --init` and to the
default Taskfile it generates (#2433 by @andreynering).
- Added `--remote-cache-dir` flag and `remote.cache-dir` taskrc option to
customize the cache directory for Remote Taskfiles (#2572 by @vmaerten).
- Zsh completion now supports zstyle verbose option to show or hide task
descriptions (#2571 by @vmaerten).
- Task now automatically enables colored output in CI environments (GitHub
Actions, GitLab CI, etc.) without requiring FORCE_COLOR=1 (#2569 by
@vmaerten).
- Added color taskrc option to explicitly enable or disable colored output
globally (#2569 by @vmaerten).
- Improved Git Remote Taskfiles by switching to go-getter: SSH authentication
now works out of the box and `applyOf` is properly supported (#2512 by
@vmaerten).
### 🐛 Fixes
- Fix RPM upload to Cloudsmith by including the version in the filename to
ensure unique filenames (#2507 by @vmaerten).
- Fix `run: when_changed` to work properly for Taskfiles included multiple times
(#2508, #2511 by @trulede).
- Fixed Zsh and Fish completions to stop suggesting task names after `--`
separator, allowing proper CLI_ARGS completion (#1843, #1844 by
@boiledfroginthewell).
- Watch mode (`--watch`) now always runs the task, regardless of `run: once` or
`run: when_changed` settings (#2566, #1388 by @trulede).
- Fixed global variables (CLI_ARGS, CLI_FORCE, etc.) not being accessible in
root-level vars section (#2403, #2397 by @trulede, @vmaerten).
- Fixed a bug where `ignore_error` was ignored when using `task:` to call
another task (#2552, #363 by @trulede).
- Fixed Zsh completion not suggesting global tasks when using `-g`/`--global`
flag (#1574, #2574 by @vmaerten).
- Fixed Fish completion failing to parse task descriptions containing colons
(e.g., URLs or namespaced functions) (#2101, #2573 by @vmaerten).
- Fixed false positive "property 'for' is not allowed" warnings in IntelliJ when
using `for` loops in Taskfiles (#2576 by @vmaerten).
## v3.45.5 - 2025-11-11
- Fixed bug that made a generic message, instead of an useful one, appear when a
@@ -22,7 +95,8 @@ outline: deep
parts won't be mixed up from different tasks (#1208, #2349, #2350 by
@trulede).
- Do not re-evaluate variables for `defer:` (#2244, #2418 by @trulede).
- Improve error message when a Taskfile is not found (#2441, #2494 by @vmaerten).
- Improve error message when a Taskfile is not found (#2441, #2494 by
@vmaerten).
- Fixed generic error message `exit status 1` when a dependency task failed
(#2286 by @GrahamDennis).
- Fixed YAML library from the unmaintained `gopkg.in/yaml.v3` to the new fork
@@ -30,9 +104,8 @@ outline: deep
- On Windows, the built-in version of the `rm` core utils contains a fix related
to the `-f` flag (#2426,
[u-root/u-root#3464](https://github.com/u-root/u-root/pull/3464),
[mvdan/sh#1199](https://github.com/mvdan/sh/pull/1199),
#2506 by @andreynering).
[mvdan/sh#1199](https://github.com/mvdan/sh/pull/1199), #2506 by
@andreynering).
## v3.45.4 - 2025-09-17
@@ -183,8 +256,8 @@ Reverted the changes made in #2113 and #2186 that affected the
- The default taskfile (output when using the `--init` flag) is now an embedded
file in the binary instead of being stored in the code (#2112 by @pd93).
- Improved the way we report the Task version when using the `--version` flag or
`{{.TASK_VERSION}}` variable. This should now be more
consistent and easier for package maintainers to use (#2131 by @pd93).
`{{.TASK_VERSION}}` variable. This should now be more consistent and easier
for package maintainers to use (#2131 by @pd93).
- Fixed a bug where globstar (`**`) matching in `sources` only resolved the
first result (#2073, #2075 by @pd93).
- Fixed a bug where sorting tasks by "none" would use the default sorting
@@ -198,7 +271,7 @@ Reverted the changes made in #2113 and #2186 that affected the
- Fix Fish completions when `--global` (`-g`) is given (#2134 by @atusy).
- Fixed variables not available when using `defer:` (#1909, #2173 by @vmaerten).
### Package API
#### Package API
- The [`Executor`](https://pkg.go.dev/github.com/go-task/task/v3#Executor) now
uses the functional options pattern (#2085, #2147, #2148 by @pd93).
@@ -255,7 +328,7 @@ Reverted the changes made in #2113 and #2186 that affected the
used, all other variables become unavailable in the templating system within
the include (#2092 by @vmaerten).
### Package API
#### Package API
Unlike our CLI tool,
[Task's package API is not currently stable](https://taskfile.dev/reference/package).
@@ -645,9 +718,8 @@ stabilize the API in the future. #121 now tracks this piece of work.
@FilipSolich).
- Fix `defer` on JSON Schema (#1288 by @calvinmclean and @andreynering).
- Fix bug in usage of special variables like `{{.USER_WORKING_DIR}}` in
combination with `includes`
(#1046, #1205, #1250, #1293, #1312, #1274 by @andarto, #1309 by
@andreynering).
combination with `includes` (#1046, #1205, #1250, #1293, #1312, #1274 by
@andarto, #1309 by @andreynering).
- Fix bug on `--status` flag. Running this flag should not have side-effects: it
should not update the checksum on `.task`, only report its status (#1305,
#1307 by @visciang, #1313 by @andreynering).
@@ -752,9 +824,9 @@ it a go and let us know what you think via a
- Added task location data to the `--json` flag output (#1056 by @pd93)
- Change the name of the file generated by `task --init` from `Taskfile.yaml` to
`Taskfile.yml` (#1062 by @misitebao).
- Added new `splitArgs` template function (`{{splitArgs "foo bar 'foo bar
baz'"}}`) to ensure string is split as arguments (#1040, #1059 by
@dhanusaputra).
- Added new `splitArgs` template function
(`{{splitArgs "foo bar 'foo bar baz'"}}`) to ensure string is split as
arguments (#1040, #1059 by @dhanusaputra).
- Fix the value of `{{.CHECKSUM}}` variable in status (#1076, #1080 by @pd93).
- Fixed deep copy implementation (#1072 by @pd93)
- Created a tool to assist with releases (#1086 by @pd93).
@@ -979,8 +1051,8 @@ it a go and let us know what you think via a
## v3.9.0 - 2021-10-02
- A new `shellQuote` function was added to the template system (`{{shellQuote
"a string"}}`) to ensure a string is safe for use in shell
- A new `shellQuote` function was added to the template system
(`{{shellQuote "a string"}}`) to ensure a string is safe for use in shell
([mvdan/sh#727](https://github.com/mvdan/sh/pull/727),
[mvdan/sh#737](https://github.com/mvdan/sh/pull/737),
[Documentation](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote))
@@ -1367,4 +1439,4 @@ document, since it describes in depth what changed for this version.
- Add LICENSE file
:::
:::

View File

@@ -284,10 +284,11 @@ and look for a cached copy instead. This timeout can be configured by setting
the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will
set the timeout to 5 seconds.
By default, the cache is stored in the Task temp directory, represented by the
`TASK_TEMP_DIR` environment variable. You can override the location of the cache
by setting the `TASK_REMOTE_DIR` environment variable. This way, you can share
the cache between different projects.
By default, the cache is stored in the Task temp directory (`.task`). You can
override the location of the cache by using the `--remote-cache-dir` flag, the
`remote.cache-dir` option in your [configuration file](#cache-dir), or the
`TASK_REMOTE_DIR` environment variable. This way, you can share the cache
between different projects.
You can force Task to ignore the cache and download the latest version by using
the `--download` flag.
@@ -308,6 +309,7 @@ remote:
offline: false
timeout: "30s"
cache-expiry: "24h"
cache-dir: ~/.task
trusted-hosts:
- github.com
- gitlab.com
@@ -360,6 +362,20 @@ remote:
cache-expiry: "6h"
```
#### `cache-dir`
- **Type**: `string`
- **Default**: `.task`
- **Description**: Directory where remote Taskfiles are cached. Can be an
absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory.
- **CLI equivalent**: `--remote-cache-dir`
- **Environment variable**: `TASK_REMOTE_DIR` (lowest priority)
```yaml
remote:
cache-dir: ~/.task
```
#### `trusted-hosts`
- **Type**: `array of strings`

View File

@@ -2290,6 +2290,28 @@ The `output` option can also be specified by the `--output` or `-o` flags.
:::
## CI Integration
### Colored output
Task automatically enables colored output when running in CI environments
(`CI=true`). Most CI providers set this variable automatically.
You can also force colored output with `FORCE_COLOR=1` or disable it with
`NO_COLOR=1`.
### Error annotations
When running in GitHub Actions (`GITHUB_ACTIONS=true`), Task automatically emits
error annotations when a task fails. These annotations appear in the workflow
summary, making it easier to spot failures without scrolling through logs.
```shell
::error title=Task 'build' failed::exit status 1
```
This feature requires no configuration and works automatically.
## Interactive CLI application
When running interactive CLI applications inside Task they can sometimes behave

View File

@@ -384,3 +384,13 @@ task --completion fish > ~/.config/fish/completions/task.fish
```
:::
### Zsh customization
The Zsh completion supports the standard `verbose` zstyle to control whether task
descriptions are shown. By default, descriptions are displayed. To show only task
names without descriptions, add this to your `~/.zshrc` (after the completion is loaded):
```shell
zstyle ':completion:*:*:task:*' verbose false
```

View File

@@ -91,6 +91,17 @@ experiments:
verbose: true
```
### `color`
- **Type**: `boolean`
- **Default**: `true`
- **Description**: Enable colored output. Colors are automatically enabled in CI environments (`CI=true`).
- **CLI equivalent**: [`-c, --color`](./cli.md#-c---color)
```yaml
color: false
```
### `disable-fuzzy`
- **Type**: `boolean`
@@ -131,6 +142,7 @@ Here's a complete example of a `.taskrc.yml` file with all available options:
```yaml
# Global settings
verbose: true
color: true
disable-fuzzy: false
concurrency: 2

View File

@@ -172,6 +172,11 @@ tasks:
- **Type**: `bool`
- **Description**: Whether `--offline` flag was set
#### `CLI_ASSUME_YES`
- **Type**: `bool`
- **Description**: Whether `--yes` flag was set
### Task
#### `TASK`

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -57,6 +57,10 @@
"type": "boolean",
"description": "Enable verbose output"
},
"color": {
"type": "boolean",
"description": "Enable colored output"
},
"disable-fuzzy": {
"type": "boolean",
"description": "Disable fuzzy matching for task names"

View File

@@ -233,7 +233,10 @@
"$ref": "#/definitions/defer_cmd_call"
},
{
"$ref": "#/definitions/for_cmds_call"
"$ref": "#/definitions/for_cmd_call"
},
{
"$ref": "#/definitions/for_task_call"
}
]
},
@@ -401,7 +404,7 @@
"additionalProperties": false,
"required": ["defer"]
},
"for_cmds_call": {
"for_cmd_call": {
"type": "object",
"properties": {
"for": {
@@ -415,6 +418,20 @@
"description": "Silent mode disables echoing of command before Task runs it",
"type": "boolean"
},
"platforms": {
"description": "Specifies which platforms the command should be run on.",
"$ref": "#/definitions/platforms"
}
},
"additionalProperties": false,
"required": ["for", "cmd"]
},
"for_task_call": {
"type": "object",
"properties": {
"for": {
"$ref": "#/definitions/for"
},
"task": {
"description": "Task to run",
"type": "string"
@@ -423,14 +440,17 @@
"description": "Values passed to the task called",
"$ref": "#/definitions/vars"
},
"silent": {
"description": "Silent mode disables echoing of command before Task runs it",
"type": "boolean"
},
"platforms": {
"description": "Specifies which platforms the command should be run on.",
"$ref": "#/definitions/platforms"
}
},
"oneOf": [{ "required": ["cmd"] }, { "required": ["task"] }],
"additionalProperties": false,
"required": ["for"]
"required": ["for", "task"]
},
"for_deps_call": {
"type": "object",
@@ -451,9 +471,8 @@
"$ref": "#/definitions/vars"
}
},
"oneOf": [{ "required": ["cmd"] }, { "required": ["task"] }],
"additionalProperties": false,
"required": ["for"]
"required": ["for", "task"]
},
"for": {
"anyOf": [
@@ -475,7 +494,7 @@
"description": "A list of values to iterate over",
"type": "array",
"items": {
"type": "string"
"type": ["string", "number"]
}
},
"for_attribute": {