Compare commits

...

50 Commits

Author SHA1 Message Date
Andrey Nering
aa83651da2 v3.49.1 2026-03-08 17:01:25 -03:00
Andrey Nering
4ddad9f9f7 Revert "fix: Call ReplaceVars() to resolve Ref's for imported global vars." (#2723) 2026-03-08 20:00:12 +00:00
Jannis
080ee8869f docs: schema: add tasks.task.method (#2718) 2026-03-08 11:45:27 +01:00
Andrey Nering
af943b064b ci: fix netlify prod deploy after release 2026-03-07 20:02:53 -03:00
Andrey Nering
962eada344 docs: update releasing guide
We have now more package managers being released automatically by
GoReleaser. Only Snapcraft still require manual steps.
2026-03-07 19:42:03 -03:00
Andrey Nering
a0d9750edf docs(changelog): fix case: git -> Git 2026-03-07 19:26:22 -03:00
Andrey Nering
a1b8985df0 v3.49.0 2026-03-07 19:20:58 -03:00
dependabot[bot]
21daf6160a chore(deps): bump go.opentelemetry.io/otel/sdk from 1.39.0 to 1.40.0 (#2712)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-06 19:49:38 -03:00
renovate[bot]
c70d28f7b8 chore(deps): update actions/upload-artifact action to v7 (#2714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 19:48:51 -03:00
Andrey Nering
90e6ef88dc security: pin github actions by commit (#2719) 2026-03-06 19:20:25 -03:00
renovate[bot]
a788034148 chore(deps): update all non-major dependencies (#2713)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 22:32:30 +01:00
Timothy Rule
90bcbe9ba5 fix: address "taskfile not found" in some environments like docker (#2709) 2026-02-27 09:47:59 -03:00
Andrey Nering
60a808ca23 docs(readme): update | to 2026-02-23 17:26:14 -03:00
renovate[bot]
edc80aed81 chore(deps): update goreleaser/goreleaser-action action to v7 (#2706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-23 15:35:02 -03:00
renovate[bot]
68bea7f273 chore(deps): update pnpm to v10.30.1 (#2705)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-23 15:34:23 -03:00
Valentin Maerten
c62f9c7147 fix(build): exclude unsupported windows/arm target 2026-02-21 15:18:04 +01:00
Valentin Maerten
c4ecff753d chore: changelog for #2607 2026-02-18 19:00:15 +01:00
Valentin Maerten
2ed77716be feat(config): add environment variable support for all taskrc options (#2607) 2026-02-18 18:58:13 +01:00
Valentin Maerten
a2f8e144ca chore: changelog for #2632 2026-02-18 18:57:53 +01:00
Timothy Rule
2cdd7d3e43 fix: Call ReplaceVars() to resolve Ref's for imported global vars. (#2632) 2026-02-18 18:55:20 +01:00
Andrey Nering
56b316a124 ci: fix lint 2026-02-17 15:43:13 -03:00
renovate[bot]
39ce6a21ac chore(deps): update all non-major dependencies 2026-02-17 15:43:13 -03:00
Andrey Nering
fc5f6fa3aa fix: pin yaml package to v3 for now (#2693) 2026-02-17 15:29:51 -03:00
Valentin Maerten
44a2f2e5f5 docs: add Cloudsmith attribution for deb/rpm package hosting 2026-02-15 17:22:01 +01:00
Valentin Maerten
d356c649aa chore: changelog for #2682 2026-02-15 17:01:02 +01:00
Valentin Maerten
ca24d32f37 chore: changelog for #2669 2026-02-15 14:56:52 +01:00
Timothy Rule
f63a63fa6c fix: improve error message when searching for Taskfile. (#2682) 2026-02-15 14:56:35 +01:00
renovate[bot]
c0ff7105e7 chore(deps): update peter-evans/find-comment action to v4 (#2684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-15 14:49:49 +01:00
Valentin Maerten
8b063d6b92 fix(git): check cache before context timeout in getOrCloneRepo (#2669) 2026-02-15 14:46:55 +01:00
Valentin Maerten
dc8ac5e79f chore: changelog for #2686 2026-02-15 14:45:47 +01:00
Timothy Rule
df7810ab63 fix: copy watch when merging tasks during import (#2686) 2026-02-15 14:42:59 +01:00
Pete Davison
82783417ea docs: update integration doc with details of extension config namespace change (#2428)
* docs: update integration doc with details of extension config namespace change

* docs: add descriptions of sorting modes
2026-02-14 20:47:06 +00:00
renovate[bot]
d5bed6b716 chore(deps): update peter-evans/create-or-update-comment action to v5 (#2673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 09:42:48 +01:00
renovate[bot]
c8f722c0d5 chore(deps): update actions/upload-artifact action to v6 (#2672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 09:35:52 +01:00
Andrey Nering
b7743eda88 chore(goreleaser): update descriptions 2026-01-31 16:20:31 -03:00
Valentin Maerten
c0796e9701 chore: changelog for #2656 2026-01-31 18:53:52 +01:00
Trim21
cf54be3266 fix(node_git): always use unix path style (#2656) 2026-01-31 18:49:22 +01:00
Jens Erat
e129ae2fac docs: fix dir headline level (#2665)
The other commands in this section are on headline level 4, which probably is also the expected one for `dir`.
2026-01-28 18:21:50 +00:00
Andrey Nering
ed69256512 chore: update readme title and description to match website 2026-01-27 22:28:02 -03:00
Andrey Nering
40ad9719d4 chore(website): improve home page title, including on opengraph 2026-01-27 22:18:49 -03:00
Andrey Nering
48f75f0913 docs(cli): mention --list with --silent 2026-01-27 21:53:52 -03:00
Andrey Nering
f000ea2b22 chore(website): have a good opengraph image 2026-01-27 21:53:52 -03:00
Andrey Nering
e8be687a40 chore(website): add "edit this page on github" links 2026-01-27 21:53:52 -03:00
renovate[bot]
788605a3a9 chore(deps): update actions/setup-go action to v6 (#2662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-26 21:42:04 +01:00
Andrey Nering
697cf442a2 docs(blog): adjust post title 2026-01-26 09:51:43 -03:00
Andrey Nering
e957edf783 chore(website): add goodx sponsor 2026-01-26 09:39:06 -03:00
Andrey Nering
09e7247d05 v3.48.0 2026-01-26 09:26:23 -03:00
Andrey Nering
502f24a2ad docs(changelog): add entry for #2658 and #2660 2026-01-26 09:24:26 -03:00
Valentin Maerten
f09f31c6d5 fix: skip prompting for vars when task if condition fails
Move the prompt for required variables AFTER the if condition check.
This avoids asking the user for input when the task won't run anyway.

The order in RunTask() is now:
1. FastCompiledTask
2. Check required vars early (non-interactive mode only)
3. CompiledTask (resolve dynamic vars)
4. Check if condition → exit early if false
5. Prompt for missing vars (only if task will run)
6. Validate required vars
2026-01-26 09:21:09 -03:00
Valentin Maerten
5a78808caa fix: evaluate task-level if condition after resolving dynamic variables 2026-01-26 09:21:09 -03:00
80 changed files with 2436 additions and 1031 deletions

View File

@@ -8,7 +8,7 @@ jobs:
issue-awaiting-response: issue-awaiting-response:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |

View File

@@ -8,7 +8,7 @@ jobs:
issue-closed: issue-closed:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |

View File

@@ -9,7 +9,7 @@ jobs:
if: github.event.label.name == format('status{0} proposed', ':') if: github.event.label.name == format('status{0} proposed', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -23,7 +23,7 @@ jobs:
if: github.event.label.name == format('status{0} draft', ':') if: github.event.label.name == format('status{0} draft', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -37,7 +37,7 @@ jobs:
if: github.event.label.name == format('status{0} candidate', ':') if: github.event.label.name == format('status{0} candidate', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -51,7 +51,7 @@ jobs:
if: github.event.label.name == format('status{0} stable', ':') if: github.event.label.name == format('status{0} stable', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -65,7 +65,7 @@ jobs:
if: github.event.label.name == format('status{0} released', ':') if: github.event.label.name == format('status{0} released', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -85,7 +85,7 @@ jobs:
if: github.event.label.name == format('status{0} abandoned', ':') if: github.event.label.name == format('status{0} abandoned', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |
@@ -105,7 +105,7 @@ jobs:
if: github.event.label.name == format('status{0} superseded', ':') if: github.event.label.name == format('status{0} superseded', ':')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |

View File

@@ -8,7 +8,7 @@ jobs:
issue-needs-triage: issue-needs-triage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with: with:
github-token: ${{secrets.GH_PAT}} github-token: ${{secrets.GH_PAT}}
script: | script: |

View File

@@ -16,25 +16,25 @@ jobs:
go-version: [1.24.x, 1.25.x] go-version: [1.24.x, 1.25.x]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-go@v6 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: ${{matrix.go-version}} go-version: ${{matrix.go-version}}
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v9 uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with: with:
version: v2.8.0 version: v2.11.1
lint-jsonschema: lint-jsonschema:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: 3.14 python-version: 3.14
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: install check-jsonschema - name: install check-jsonschema
run: python -m pip install 'check-jsonschema==0.27.3' run: python -m pip install 'check-jsonschema==0.27.3'

View File

@@ -13,49 +13,49 @@ jobs:
if: contains(github.event.pull_request.labels.*.name, 'needs-build') if: contains(github.event.pull_request.labels.*.name, 'needs-build')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-go@v5 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: '1.25.x' go-version: '1.26.x'
cache: true cache: true
- uses: goreleaser/goreleaser-action@v6 - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with: with:
version: '~> v2' version: '~> v2'
args: release --snapshot --clean --config .goreleaser-pr.yml args: release --snapshot --clean --config .goreleaser-pr.yml
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: task_linux_amd64 name: task_linux_amd64
path: dist/task_linux_amd64.tar.gz path: dist/task_linux_amd64.tar.gz
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: task_linux_arm64 name: task_linux_arm64
path: dist/task_linux_arm64.tar.gz path: dist/task_linux_arm64.tar.gz
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: task_darwin_amd64 name: task_darwin_amd64
path: dist/task_darwin_amd64.tar.gz path: dist/task_darwin_amd64.tar.gz
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: task_darwin_arm64 name: task_darwin_arm64
path: dist/task_darwin_arm64.tar.gz path: dist/task_darwin_arm64.tar.gz
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: task_windows_amd64 name: task_windows_amd64
path: dist/task_windows_amd64.zip path: dist/task_windows_amd64.zip
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: checksums name: checksums
path: dist/task_checksums.txt path: dist/task_checksums.txt
- uses: peter-evans/find-comment@v3 - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: find-comment id: find-comment
with: with:
token: ${{ secrets.GH_PAT || github.token }} token: ${{ secrets.GH_PAT || github.token }}
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body-includes: '📦 Build artifacts ready!' body-includes: '📦 Build artifacts ready!'
- uses: peter-evans/create-or-update-comment@v4 - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with: with:
token: ${{ secrets.GH_PAT || github.token }} token: ${{ secrets.GH_PAT || github.token }}
comment-id: ${{ steps.find-comment.outputs.comment-id }} comment-id: ${{ steps.find-comment.outputs.comment-id }}

View File

@@ -9,17 +9,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: 1.25.x go-version: 1.26.x
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6 uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with: with:
distribution: goreleaser-pro distribution: goreleaser-pro
version: latest version: latest

View File

@@ -14,16 +14,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: 1.25.x go-version: 1.26.x
- uses: actions/setup-node@v6 - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with: with:
node-version: '24' node-version: '24'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
@@ -32,16 +32,16 @@ jobs:
run: npm install -g npm@latest run: npm install -g npm@latest
- name: Install Task - name: Install Task
uses: go-task/setup-task@v1 uses: go-task/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
with: with:
package_json_file: 'website/package.json' package_json_file: 'website/package.json'
run_install: 'true' run_install: 'true'
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6 uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with: with:
distribution: goreleaser-pro distribution: goreleaser-pro
version: latest version: latest
@@ -55,3 +55,5 @@ jobs:
shell: bash shell: bash
run: | run: |
task website:deploy:prod task website:deploy:prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

View File

@@ -18,13 +18,13 @@ jobs:
runs-on: ${{matrix.platform}} runs-on: ${{matrix.platform}}
steps: steps:
- name: Set up Go ${{matrix.go-version}} - name: Set up Go ${{matrix.go-version}}
uses: actions/setup-go@v6 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: ${{matrix.go-version}} go-version: ${{matrix.go-version}}
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download Go modules - name: Download Go modules
run: go mod download run: go mod download

View File

@@ -22,6 +22,8 @@ builds:
goarch: '386' goarch: '386'
- goos: darwin - goos: darwin
goarch: riscv64 goarch: riscv64
- goos: windows
goarch: arm
- goos: windows - goos: windows
goarch: riscv64 goarch: riscv64
env: env:
@@ -60,7 +62,7 @@ nfpms:
- vendor: Task - vendor: Task
homepage: https://taskfile.dev homepage: https://taskfile.dev
maintainer: The Task authors <task@taskfile.dev> maintainer: The Task authors <task@taskfile.dev>
description: Simple task runner written in Go description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
section: golang section: golang
license: MIT license: MIT
conflicts: conflicts:
@@ -80,7 +82,7 @@ nfpms:
brews: brews:
- name: go-task - name: go-task
description: Task runner / simpler Make alternative written in Go description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
license: MIT license: MIT
homepage: https://taskfile.dev homepage: https://taskfile.dev
directory: Formula directory: Formula
@@ -100,8 +102,8 @@ brews:
winget: winget:
- name: Task - name: Task
publisher: Task publisher: Task
short_description: A task runner / simpler Make alternative written in Go short_description: The modern task runner.
description: Task is a task runner / build tool that aims to be simpler and easier to use than, for example, GNU Make. description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
license: MIT license: MIT
homepage: https://taskfile.dev/ homepage: https://taskfile.dev/
publisher_url: https://taskfile.dev/ publisher_url: https://taskfile.dev/
@@ -144,7 +146,7 @@ npms:
- name: "@go-task/cli" - name: "@go-task/cli"
repository: "git+https://github.com/go-task/task.git" repository: "git+https://github.com/go-task/task.git"
bugs: https://github.com/go-task/task/issues bugs: https://github.com/go-task/task/issues
description: A task runner / simpler Make alternative written in Go description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
homepage: https://taskfile.dev homepage: https://taskfile.dev
license: MIT license: MIT
author: "The Task authors" author: "The Task authors"
@@ -155,7 +157,6 @@ npms:
- "build-tool" - "build-tool"
- "task-runner" - "task-runner"
cloudsmiths: cloudsmiths:
- organization: "task" - organization: "task"
repository: "{{if not .IsNightly}}task{{end}}" repository: "{{if not .IsNightly}}task{{end}}"

View File

@@ -1,7 +1,25 @@
# Changelog # Changelog
## Unreleased ## v3.49.0 - 2026-03-07
- Fixed included Taskfiles with `watch: true` not triggering watch mode when
called from the root Taskfile (#2686, #1763 by @trulede).
- Fixed Remote Git Taskfiles failing on Windows due to backslashes in URL paths
(#2656 by @Trim21).
- Fixed remote Git Taskfiles timing out when resolving includes after accepting
the trust prompt (#2669, #2668 by @vmaerten).
- Fixed unclear error message when Taskfile search stops at a directory
ownership boundary (#2682, #1683 by @trulede).
- Fixed global variables from imported Taskfiles not resolving `ref:` values
correctly (#2632 by @trulede).
- Every `.taskrc.yml` option can now be overridden with a `TASK_`-prefixed
environment variable, making CI and container configuration easier (#2607,
#1066 by @vmaerten).
## v3.48.0 - 2026-01-26
- Fixed `if:` conditions when using to check dynamic variables. Also, skip
variable prompt if task would be skipped by `if:` (#2658, #2660 by @vmaerten).
- Fixed `ROOT_TASKFILE` variable pointing to directory instead of the actual - Fixed `ROOT_TASKFILE` variable pointing to directory instead of the actual
Taskfile path when no explicit `-t` flag is provided (#2635, #1706 by Taskfile path when no explicit `-t` flag is provided (#2635, #1706 by
@trulede). @trulede).

View File

@@ -3,14 +3,14 @@
<img src="website/src/public/img/logo.svg" width="200px" height="200px" /> <img src="website/src/public/img/logo.svg" width="200px" height="200px" />
</a> </a>
<h1>Task</h1> <h1>Task: The Modern Task Runner</h1>
<p> <p>
Task is a task runner / build tool that aims to be simpler and easier to use than, for example, <a href="https://www.gnu.org/software/make/">GNU Make<a>. A fast, cross-platform build tool inspired by Make, designed for modern workflows.
</p> </p>
<p> <p>
<a href="https://taskfile.dev/docs/installation">Installation</a> | <a href="https://taskfile.dev/docs/getting-started">Getting Started</a> | <a href="https://taskfile.dev/docs/guide">Docs</a> | <a href="https://twitter.com/taskfiledev">Twitter</a> | <a href="https://bsky.app/profile/taskfile.dev">Bluesky</a> | <a href="https://fosstodon.org/@task">Mastodon</a> | <a href="https://discord.gg/6TY36E39UK">Discord</a> <a href="https://taskfile.dev/docs/installation">Installation</a> &bullet; <a href="https://taskfile.dev/docs/getting-started">Getting Started</a> &bullet; <a href="https://taskfile.dev/docs/guide">Docs</a> &bullet; <a href="https://twitter.com/taskfiledev">Twitter</a> &bullet; <a href="https://bsky.app/profile/taskfile.dev">Bluesky</a> &bullet; <a href="https://fosstodon.org/@task">Mastodon</a> &bullet; <a href="https://discord.gg/6TY36E39UK">Discord</a>
</p> </p>
<h1>Gold Sponsors</h1> <h1>Gold Sponsors</h1>
@@ -22,6 +22,11 @@
<img src="website/src/public/img/devowl.io.svg" height="100px" width="200px" title="devowl.io" /> <img src="website/src/public/img/devowl.io.svg" height="100px" width="200px" title="devowl.io" />
</a> </a>
</td> </td>
<td align="center" valign="middle">
<a target="_blank" href="https://goodx.international/">
<img src="website/src/public/img/goodx.svg" height="80px" width="200px" title="GoodX" />
</a>
</td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a target="_blank" href="https://magic.dev/"> <a target="_blank" href="https://magic.dev/">
<img src="website/src/public/img/magic.png" height="100px" width="200px" title="Magic" /> <img src="website/src/public/img/magic.png" height="100px" width="200px" title="Magic" />

View File

@@ -8,7 +8,7 @@ import (
"strings" "strings"
"github.com/fatih/color" "github.com/fatih/color"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
) )
type ( type (
@@ -50,10 +50,10 @@ func (err *TaskfileDecodeError) Error() string {
if len(te.Errors) > 1 { if len(te.Errors) > 1 {
fmt.Fprintln(buf, color.RedString("errs:")) fmt.Fprintln(buf, color.RedString("errs:"))
for _, message := range te.Errors { for _, message := range te.Errors {
fmt.Fprintln(buf, color.RedString("- %s", message.Err.Error())) fmt.Fprintln(buf, color.RedString("- %s", message))
} }
} else { } else {
fmt.Fprintln(buf, color.RedString("err: %s", te.Errors[0].Err.Error())) fmt.Fprintln(buf, color.RedString("err: %s", te.Errors[0]))
} }
} else { } else {
// Otherwise print the error message normally // Otherwise print the error message normally

View File

@@ -195,9 +195,9 @@ type TaskNotAllowedVarsError struct {
func (err *TaskNotAllowedVarsError) Error() string { func (err *TaskNotAllowedVarsError) Error() string {
var builder strings.Builder var builder strings.Builder
builder.WriteString(fmt.Sprintf("task: Task %q cancelled because it is missing required variables:\n", err.TaskName)) builder.WriteString(fmt.Sprintf("task: Task %q cancelled because it is missing required variables:\n", err.TaskName)) //nolint:staticcheck
for _, s := range err.NotAllowedVars { for _, s := range err.NotAllowedVars {
builder.WriteString(fmt.Sprintf(" - %s has an invalid value : '%s' (allowed values : %v)\n", s.Name, s.Value, s.Enum)) builder.WriteString(fmt.Sprintf(" - %s has an invalid value : '%s' (allowed values : %v)\n", s.Name, s.Value, s.Enum)) //nolint:staticcheck
} }
return builder.String() return builder.String()

View File

@@ -11,14 +11,17 @@ import (
// TaskfileNotFoundError is returned when no appropriate Taskfile is found when // TaskfileNotFoundError is returned when no appropriate Taskfile is found when
// searching the filesystem. // searching the filesystem.
type TaskfileNotFoundError struct { type TaskfileNotFoundError struct {
URI string URI string
Walk bool Walk bool
AskInit bool AskInit bool
OwnerChange bool
} }
func (err TaskfileNotFoundError) Error() string { func (err TaskfileNotFoundError) Error() string {
var walkText string var walkText string
if err.Walk { if err.OwnerChange {
walkText = " (or any of the parent directories until ownership changed)."
} else if err.Walk {
walkText = " (or any of the parent directories)." walkText = " (or any of the parent directories)."
} }
if err.AskInit { if err.AskInit {

View File

@@ -1160,6 +1160,10 @@ func TestIf(t *testing.T) {
// For loop with if // For loop with if
{name: "if-in-for-loop", task: "if-in-for-loop", verbose: true}, {name: "if-in-for-loop", task: "if-in-for-loop", verbose: true},
// Task-level if with dynamic variable
{name: "task-if-dynamic-true", task: "task-if-dynamic-true"},
{name: "task-if-dynamic-false", task: "task-if-dynamic-false", verbose: true},
} }
for _, test := range tests { for _, test := range tests {

44
go.mod
View File

@@ -2,15 +2,15 @@ module github.com/go-task/task/v3
go 1.24.6 go 1.24.6
toolchain go1.25.6 toolchain go1.26.1
require ( require (
charm.land/bubbles/v2 v2.0.0-rc.1 charm.land/bubbles/v2 v2.0.0
charm.land/bubbletea/v2 v2.0.0-rc.2 charm.land/bubbletea/v2 v2.0.1
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7 charm.land/lipgloss/v2 v2.0.0
github.com/Ladicle/tabwriter v1.0.0 github.com/Ladicle/tabwriter v1.0.0
github.com/Masterminds/semver/v3 v3.4.0 github.com/Masterminds/semver/v3 v3.4.0
github.com/alecthomas/chroma/v2 v2.23.0 github.com/alecthomas/chroma/v2 v2.23.1
github.com/chainguard-dev/git-urls v1.0.2 github.com/chainguard-dev/git-urls v1.0.2
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/dominikbraun/graph v0.23.0 github.com/dominikbraun/graph v0.23.0
@@ -23,15 +23,15 @@ require (
github.com/hashicorp/go-getter v1.8.4 github.com/hashicorp/go-getter v1.8.4
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/puzpuzpuz/xsync/v4 v4.3.0 github.com/puzpuzpuz/xsync/v4 v4.4.0
github.com/sajari/fuzzy v1.0.0 github.com/sajari/fuzzy v1.0.0
github.com/sebdah/goldie/v2 v2.8.0 github.com/sebdah/goldie/v2 v2.8.0
github.com/spf13/pflag v1.0.10 github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/zeebo/xxh3 v1.0.2 github.com/zeebo/xxh3 v1.1.0
go.yaml.in/yaml/v4 v4.0.0-rc.3 go.yaml.in/yaml/v3 v3.0.4
golang.org/x/sync v0.19.0 golang.org/x/sync v0.19.0
golang.org/x/term v0.39.0 golang.org/x/term v0.40.0
mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997
mvdan.cc/sh/v3 v3.12.1-0.20260124232039-e74afc18e65b mvdan.cc/sh/v3 v3.12.1-0.20260124232039-e74afc18e65b
) )
@@ -70,15 +70,15 @@ require (
github.com/aws/smithy-go v1.24.0 // indirect github.com/aws/smithy-go v1.24.0 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.3.3 // indirect github.com/charmbracelet/colorprofile v0.4.2 // indirect
github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38 // indirect github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
github.com/charmbracelet/x/ansi v0.11.1 // indirect github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.5.0 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
@@ -95,12 +95,12 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect github.com/hashicorp/go-version v1.8.0 // indirect
github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect
@@ -119,15 +119,15 @@ require (
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel v1.40.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.40.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.40.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect
golang.org/x/crypto v0.46.0 // indirect golang.org/x/crypto v0.46.0 // indirect
golang.org/x/net v0.48.0 // indirect golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.33.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect
golang.org/x/sys v0.40.0 // indirect golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.32.0 // indirect golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect golang.org/x/time v0.14.0 // indirect
google.golang.org/api v0.256.0 // indirect google.golang.org/api v0.256.0 // indirect

67
go.sum
View File

@@ -2,10 +2,16 @@ cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
charm.land/bubbles/v2 v2.0.0-rc.1 h1:EiIFVAc3Zi/yY86td+79mPhHR7AqZ1OxF+6ztpOCRaM= charm.land/bubbles/v2 v2.0.0-rc.1 h1:EiIFVAc3Zi/yY86td+79mPhHR7AqZ1OxF+6ztpOCRaM=
charm.land/bubbles/v2 v2.0.0-rc.1/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4= charm.land/bubbles/v2 v2.0.0-rc.1/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4=
charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
charm.land/bubbletea/v2 v2.0.0-rc.2 h1:TdTbUOFzbufDJmSz/3gomL6q+fR6HwfY+P13hXQzD7k= charm.land/bubbletea/v2 v2.0.0-rc.2 h1:TdTbUOFzbufDJmSz/3gomL6q+fR6HwfY+P13hXQzD7k=
charm.land/bubbletea/v2 v2.0.0-rc.2/go.mod h1:IXFmnCnMLTWw/KQ9rEatSYqbAPAYi8kA3Yqwa1SFnLk= charm.land/bubbletea/v2 v2.0.0-rc.2/go.mod h1:IXFmnCnMLTWw/KQ9rEatSYqbAPAYi8kA3Yqwa1SFnLk=
charm.land/bubbletea/v2 v2.0.1 h1:B8e9zzK7x9JJ+XvHGF4xnYu9Xa0E0y0MyggY6dbaCfQ=
charm.land/bubbletea/v2 v2.0.1/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7 h1:059k1h5vvZ4ASinki9nmBguxu9Rq0UDDSa6q8LOUphk= charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7 h1:059k1h5vvZ4ASinki9nmBguxu9Rq0UDDSa6q8LOUphk=
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7/go.mod h1:1qZyvvVCenJO2M1ac2mX0yyiIZJoZmDM4DG4s0udJkU= charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7/go.mod h1:1qZyvvVCenJO2M1ac2mX0yyiIZJoZmDM4DG4s0udJkU=
charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo=
charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14=
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4=
@@ -40,8 +46,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 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/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.23.0 h1:u/Orux1J0eLuZDeQ44froV8smumheieI0EofhbyKhhk= github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
github.com/alecthomas/chroma/v2 v2.23.0/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
@@ -94,10 +100,16 @@ github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiw
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
github.com/charmbracelet/colorprofile v0.3.3 h1:DjJzJtLP6/NZ8p7Cgjno0CKGr7wwRJGxWUwh2IyhfAI= github.com/charmbracelet/colorprofile v0.3.3 h1:DjJzJtLP6/NZ8p7Cgjno0CKGr7wwRJGxWUwh2IyhfAI=
github.com/charmbracelet/colorprofile v0.3.3/go.mod h1:nB1FugsAbzq284eJcjfah2nhdSLppN2NqvfotkfRYP4= github.com/charmbracelet/colorprofile v0.3.3/go.mod h1:nB1FugsAbzq284eJcjfah2nhdSLppN2NqvfotkfRYP4=
github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=
github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=
github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38 h1:7Rs87fbKJoIIxsQS8YKJYGYa0tlsDwwb0twQjV1KB+g= github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38 h1:7Rs87fbKJoIIxsQS8YKJYGYa0tlsDwwb0twQjV1KB+g=
github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38/go.mod h1:6lfcr3MNP+kZR25sF1nQwJFuQnNYBlFy3PGX5rvslXc= github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38/go.mod h1:6lfcr3MNP+kZR25sF1nQwJFuQnNYBlFy3PGX5rvslXc=
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
github.com/charmbracelet/x/ansi v0.11.1 h1:iXAC8SyMQDJgtcz9Jnw+HU8WMEctHzoTAETIeA3JXMk= github.com/charmbracelet/x/ansi v0.11.1 h1:iXAC8SyMQDJgtcz9Jnw+HU8WMEctHzoTAETIeA3JXMk=
github.com/charmbracelet/x/ansi v0.11.1/go.mod h1:M49wjzpIujwPceJ+t5w3qh2i87+HRtHohgb5iTyepL0= github.com/charmbracelet/x/ansi v0.11.1/go.mod h1:M49wjzpIujwPceJ+t5w3qh2i87+HRtHohgb5iTyepL0=
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
@@ -108,10 +120,14 @@ github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2
github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
github.com/clipperhouse/displaywidth v0.5.0 h1:AIG5vQaSL2EKqzt0M9JMnvNxOCRTKUc4vUnLWGgP89I= github.com/clipperhouse/displaywidth v0.5.0 h1:AIG5vQaSL2EKqzt0M9JMnvNxOCRTKUc4vUnLWGgP89I=
github.com/clipperhouse/displaywidth v0.5.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= github.com/clipperhouse/displaywidth v0.5.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
@@ -183,8 +199,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -202,6 +218,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 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/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 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
@@ -216,8 +234,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v4 v4.3.0 h1:w/bWkEJdYuRNYhHn5eXnIT8LzDM1O629X1I9MJSkD7Q= github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo=
github.com/puzpuzpuz/xsync/v4 v4.3.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -252,8 +270,8 @@ 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/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
@@ -262,20 +280,20 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
@@ -286,12 +304,11 @@ golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= 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/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=

62
internal/env/env.go vendored
View File

@@ -3,7 +3,9 @@ package env
import ( import (
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"
"time"
"github.com/go-task/task/v3/experiments" "github.com/go-task/task/v3/experiments"
"github.com/go-task/task/v3/taskfile/ast" "github.com/go-task/task/v3/taskfile/ast"
@@ -61,3 +63,63 @@ func isTypeAllowed(v any) bool {
func GetTaskEnv(key string) string { func GetTaskEnv(key string) string {
return os.Getenv(taskVarPrefix + key) return os.Getenv(taskVarPrefix + key)
} }
// GetTaskEnvBool returns the boolean value of a TASK_ prefixed env var.
// Returns the value and true if set and valid, or false and false if not set or invalid.
func GetTaskEnvBool(key string) (bool, bool) {
v := GetTaskEnv(key)
if v == "" {
return false, false
}
b, err := strconv.ParseBool(v)
return b, err == nil
}
// GetTaskEnvInt returns the integer value of a TASK_ prefixed env var.
// Returns the value and true if set and valid, or 0 and false if not set or invalid.
func GetTaskEnvInt(key string) (int, bool) {
v := GetTaskEnv(key)
if v == "" {
return 0, false
}
i, err := strconv.Atoi(v)
return i, err == nil
}
// GetTaskEnvDuration returns the duration value of a TASK_ prefixed env var.
// Returns the value and true if set and valid, or 0 and false if not set or invalid.
func GetTaskEnvDuration(key string) (time.Duration, bool) {
v := GetTaskEnv(key)
if v == "" {
return 0, false
}
d, err := time.ParseDuration(v)
return d, err == nil
}
// GetTaskEnvString returns the string value of a TASK_ prefixed env var.
// Returns the value and true if set (non-empty), or empty string and false if not set.
func GetTaskEnvString(key string) (string, bool) {
v := GetTaskEnv(key)
return v, v != ""
}
// GetTaskEnvStringSlice returns a comma-separated list from a TASK_ prefixed env var.
// Returns the slice and true if set (non-empty), or nil and false if not set.
func GetTaskEnvStringSlice(key string) ([]string, bool) {
v := GetTaskEnv(key)
if v == "" {
return nil, false
}
parts := strings.Split(v, ",")
result := make([]string, 0, len(parts))
for _, p := range parts {
if trimmed := strings.TrimSpace(p); trimmed != "" {
result = append(result, trimmed)
}
}
if len(result) == 0 {
return nil, false
}
return result, true
}

View File

@@ -130,15 +130,15 @@ func init() {
pflag.BoolVar(&Status, "status", false, "Exits with non-zero exit code if any of the given tasks is not up-to-date.") pflag.BoolVar(&Status, "status", false, "Exits with non-zero exit code if any of the given tasks is not up-to-date.")
pflag.BoolVar(&NoStatus, "no-status", false, "Ignore status when listing tasks as JSON") pflag.BoolVar(&NoStatus, "no-status", false, "Ignore status when listing tasks as JSON")
pflag.BoolVar(&Nested, "nested", false, "Nest namespaces when listing tasks as JSON") pflag.BoolVar(&Nested, "nested", false, "Nest namespaces when listing tasks as JSON")
pflag.BoolVar(&Insecure, "insecure", getConfig(config, func() *bool { return config.Remote.Insecure }, false), "Forces Task to download Taskfiles over insecure connections.") pflag.BoolVar(&Insecure, "insecure", getConfig(config, "REMOTE_INSECURE", func() *bool { return config.Remote.Insecure }, false), "Forces Task to download Taskfiles over insecure connections.")
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.") pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, func() *bool { return config.Verbose }, false), "Enables verbose mode.") pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, "VERBOSE", func() *bool { return config.Verbose }, false), "Enables verbose mode.")
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.") pflag.BoolVarP(&Silent, "silent", "s", getConfig(config, "SILENT", func() *bool { return config.Silent }, false), "Disables echoing.")
pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.") pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, "DISABLE_FUZZY", func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.")
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.") pflag.BoolVarP(&AssumeYes, "yes", "y", getConfig(config, "ASSUME_YES", func() *bool { return nil }, false), "Assume \"yes\" as answer to all prompts.")
pflag.BoolVar(&Interactive, "interactive", getConfig(config, func() *bool { return config.Interactive }, false), "Prompt for missing required variables.") pflag.BoolVar(&Interactive, "interactive", getConfig(config, "INTERACTIVE", func() *bool { return config.Interactive }, false), "Prompt for missing required variables.")
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.") pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
pflag.BoolVarP(&Dry, "dry", "n", false, "Compiles and prints tasks in the order that they would be run, without executing them.") pflag.BoolVarP(&Dry, "dry", "n", getConfig(config, "DRY", func() *bool { return nil }, false), "Compiles and prints tasks in the order that they would be run, without executing them.")
pflag.BoolVar(&Summary, "summary", false, "Show summary about a task.") pflag.BoolVar(&Summary, "summary", false, "Show summary about a task.")
pflag.BoolVarP(&ExitCode, "exit-code", "x", false, "Pass-through the exit code of the task command.") pflag.BoolVarP(&ExitCode, "exit-code", "x", false, "Pass-through the exit code of the task command.")
pflag.StringVarP(&Dir, "dir", "d", "", "Sets the directory in which Task will execute and look for a Taskfile.") pflag.StringVarP(&Dir, "dir", "d", "", "Sets the directory in which Task will execute and look for a Taskfile.")
@@ -147,10 +147,10 @@ func init() {
pflag.StringVar(&Output.Group.Begin, "output-group-begin", "", "Message template to print before a task's grouped output.") 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.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.BoolVar(&Output.Group.ErrorOnly, "output-group-error-only", false, "Swallow output from successful tasks.")
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.BoolVarP(&Color, "color", "c", getConfig(config, "COLOR", 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.IntVarP(&Concurrency, "concurrency", "C", getConfig(config, "CONCURRENCY", 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.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.") pflag.BoolVarP(&Failfast, "failfast", "F", getConfig(config, "FAILFAST", func() *bool { return &config.Failfast }, false), "When running tasks in parallel, stop all tasks if one fails.")
pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.") pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.")
pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.") pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.")
@@ -165,21 +165,21 @@ func init() {
// Remote Taskfiles experiment will adds the "download" and "offline" flags // Remote Taskfiles experiment will adds the "download" and "offline" flags
if experiments.RemoteTaskfiles.Enabled() { if experiments.RemoteTaskfiles.Enabled() {
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.") 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.BoolVar(&Offline, "offline", getConfig(config, "REMOTE_OFFLINE", func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.")
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).") pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, "REMOTE_TRUSTED_HOSTS", 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.DurationVar(&Timeout, "timeout", getConfig(config, "REMOTE_TIMEOUT", 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.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.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, "REMOTE_CACHE_EXPIRY", 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.StringVar(&RemoteCacheDir, "remote-cache-dir", getConfig(config, "REMOTE_CACHE_DIR", func() *string { return config.Remote.CacheDir }, env.GetTaskEnv("REMOTE_DIR")), "Directory to cache remote Taskfiles.")
pflag.StringVar(&CACert, "cacert", getConfig(config, func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.") pflag.StringVar(&CACert, "cacert", getConfig(config, "REMOTE_CACERT", func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.")
pflag.StringVar(&Cert, "cert", getConfig(config, func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.") pflag.StringVar(&Cert, "cert", getConfig(config, "REMOTE_CERT", func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.")
pflag.StringVar(&CertKey, "cert-key", getConfig(config, func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.") pflag.StringVar(&CertKey, "cert-key", getConfig(config, "REMOTE_CERT_KEY", func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.")
} }
pflag.Parse() pflag.Parse()
// Auto-detect color based on environment when not explicitly configured // Auto-detect color based on environment when not explicitly configured
// Priority: CLI flag > taskrc config > NO_COLOR > FORCE_COLOR/CI > default // Priority: CLI flag > TASK_COLOR env > taskrc config > NO_COLOR > FORCE_COLOR/CI > default
colorExplicitlySet := pflag.Lookup("color").Changed || (config != nil && config.Color != nil) colorExplicitlySet := pflag.Lookup("color").Changed || env.GetTaskEnv("COLOR") != "" || (config != nil && config.Color != nil)
if !colorExplicitlySet { if !colorExplicitlySet {
if os.Getenv("NO_COLOR") != "" { if os.Getenv("NO_COLOR") != "" {
Color = false Color = false
@@ -311,15 +311,45 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
) )
} }
// getConfig extracts a config value directly from a pointer field with a fallback default // getConfig extracts a config value with priority: env var > taskrc config > fallback
func getConfig[T any](config *taskrcast.TaskRC, fieldFunc func() *T, fallback T) T { func getConfig[T any](config *taskrcast.TaskRC, envKey string, fieldFunc func() *T, fallback T) T {
if config == nil { if envKey != "" {
return fallback if val, ok := getEnvAs[T](envKey); ok {
return val
}
} }
if config != nil {
field := fieldFunc() if field := fieldFunc(); field != nil {
if field != nil { return *field
return *field }
} }
return fallback return fallback
} }
// getEnvAs parses a TASK_ prefixed env var as type T
func getEnvAs[T any](envKey string) (T, bool) {
var zero T
switch any(zero).(type) {
case bool:
if val, ok := env.GetTaskEnvBool(envKey); ok {
return any(val).(T), true
}
case int:
if val, ok := env.GetTaskEnvInt(envKey); ok {
return any(val).(T), true
}
case time.Duration:
if val, ok := env.GetTaskEnvDuration(envKey); ok {
return any(val).(T), true
}
case string:
if val, ok := env.GetTaskEnvString(envKey); ok {
return any(val).(T), true
}
case []string:
if val, ok := env.GetTaskEnvStringSlice(envKey); ok {
return any(val).(T), true
}
}
return zero, false
}

View File

@@ -108,10 +108,10 @@ func SearchAll(entrypoint, dir string, possibleFilenames []string) ([]string, er
} }
} }
paths, err := SearchNPathRecursively(dir, possibleFilenames, -1) paths, err := SearchNPathRecursively(dir, possibleFilenames, -1)
if err != nil { // The call to SearchNPathRecursively is ambiguous and may return
return nil, err // os.ErrPermission if its search ends, however it may have still
} // returned valid paths. Caller may choose to ignore that error.
return append(entrypoints, paths...), nil return append(entrypoints, paths...), err
} }
// SearchPath will check if a file at the given path exists or not. If it does, // SearchPath will check if a file at the given path exists or not. If it does,
@@ -153,13 +153,16 @@ func SearchPath(path string, possibleFilenames []string) (string, error) {
// also check if the user ID of the directory changes and abort if it does. // also check if the user ID of the directory changes and abort if it does.
func SearchPathRecursively(path string, possibleFilenames []string) (string, error) { func SearchPathRecursively(path string, possibleFilenames []string) (string, error) {
paths, err := SearchNPathRecursively(path, possibleFilenames, 1) paths, err := SearchNPathRecursively(path, possibleFilenames, 1)
if err != nil { if len(paths) > 0 {
return "", err // Regardless of the error, return the first possible filename.
return paths[0], nil
} else {
if err != nil {
return "", err
} else {
return "", os.ErrNotExist
}
} }
if len(paths) == 0 {
return "", os.ErrNotExist
}
return paths[0], nil
} }
// SearchNPathRecursively walks up the directory tree starting at the given // SearchNPathRecursively walks up the directory tree starting at the given
@@ -188,10 +191,13 @@ func SearchNPathRecursively(path string, possibleFilenames []string, n int) ([]s
return nil, err return nil, err
} }
// Error if we reached the root directory and still haven't found a file // If the user id of the directory changes indicate a permission error, otherwise
// OR if the user id of the directory changes // the calling code will infer an error condition based on the accumulated
if path == parentPath || (parentOwner != owner) { // contents of paths.
if path == parentPath {
return paths, nil return paths, nil
} else if parentOwner != owner {
return paths, os.ErrPermission
} }
owner = parentOwner owner = parentOwner

View File

@@ -231,7 +231,7 @@ func formatMap(m map[string]any, indent int) string {
spaces := strings.Repeat(" ", indent) spaces := strings.Repeat(" ", indent)
for k, v := range m { for k, v := range m {
result.WriteString(fmt.Sprintf("%s%s: %v\n", spaces, k, v)) result.WriteString(fmt.Sprintf("%s%s: %v\n", spaces, k, v)) //nolint:staticcheck
} }
return result.String() return result.String()

View File

@@ -9,7 +9,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/google/uuid" "github.com/google/uuid"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"mvdan.cc/sh/v3/shell" "mvdan.cc/sh/v3/shell"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"

View File

@@ -1 +1 @@
3.47.0 3.49.1

View File

@@ -16,7 +16,6 @@ import (
"github.com/go-task/task/v3/internal/env" "github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/execext" "github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/filepathext" "github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/internal/fsext"
"github.com/go-task/task/v3/internal/logger" "github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/output" "github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/internal/version" "github.com/go-task/task/v3/internal/version"
@@ -60,12 +59,10 @@ func (e *Executor) getRootNode() (taskfile.Node, error) {
taskfile.WithCert(e.Cert), taskfile.WithCert(e.Cert),
taskfile.WithCertKey(e.CertKey), taskfile.WithCertKey(e.CertKey),
) )
if os.IsNotExist(err) { var taskNotFoundError errors.TaskfileNotFoundError
return nil, errors.TaskfileNotFoundError{ if errors.As(err, &taskNotFoundError) {
URI: fsext.DefaultDir(e.Entrypoint, e.Dir), taskNotFoundError.AskInit = true
Walk: true, return nil, taskNotFoundError
AskInit: true,
}
} }
if err != nil { if err != nil {
return nil, err return nil, err

21
task.go
View File

@@ -148,6 +148,20 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
return nil return nil
} }
// Check required vars early (before template compilation) if we can't prompt.
// This gives a clear "missing required variables" error instead of a template error.
if !e.canPrompt() {
if err := e.areTaskRequiredVarsSet(t); err != nil {
return err
}
}
t, err = e.CompiledTask(call)
if err != nil {
return err
}
// Check if condition after CompiledTask so dynamic variables are resolved
if strings.TrimSpace(t.If) != "" { if strings.TrimSpace(t.If) != "" {
if err := execext.RunCommand(ctx, &execext.RunCommandOptions{ if err := execext.RunCommand(ctx, &execext.RunCommandOptions{
Command: t.If, Command: t.If,
@@ -159,7 +173,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
} }
} }
// Prompt for missing required vars (just-in-time for sequential task calls) // Prompt for missing required vars after if check (avoid prompting if task won't run)
prompted, err := e.promptTaskVars(t, call) prompted, err := e.promptTaskVars(t, call)
if err != nil { if err != nil {
return err return err
@@ -176,11 +190,6 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
return err return err
} }
t, err = e.CompiledTask(call)
if err != nil {
return err
}
if err := e.areTaskRequiredVarsAllowedValuesSet(t); err != nil { if err := e.areTaskRequiredVarsAllowedValuesSet(t); err != nil {
return err return err
} }

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -5,7 +5,7 @@ import (
"sync" "sync"
"github.com/elliotchance/orderedmap/v3" "github.com/elliotchance/orderedmap/v3"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -4,7 +4,7 @@ import (
"iter" "iter"
"github.com/elliotchance/orderedmap/v3" "github.com/elliotchance/orderedmap/v3"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/goext" "github.com/go-task/task/v3/internal/goext"

View File

@@ -3,7 +3,7 @@ package ast
import ( import (
"fmt" "fmt"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -5,7 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/taskfile/ast" "github.com/go-task/task/v3/taskfile/ast"
) )

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -5,7 +5,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"
@@ -242,6 +242,7 @@ func (t *Task) DeepCopy() *Task {
Requires: t.Requires.DeepCopy(), Requires: t.Requires.DeepCopy(),
Namespace: t.Namespace, Namespace: t.Namespace,
FullName: t.FullName, FullName: t.FullName,
Watch: t.Watch,
Failfast: t.Failfast, Failfast: t.Failfast,
} }
return c return c

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -5,7 +5,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/taskfile/ast" "github.com/go-task/task/v3/taskfile/ast"
) )

View File

@@ -8,7 +8,7 @@ import (
"sync" "sync"
"github.com/elliotchance/orderedmap/v3" "github.com/elliotchance/orderedmap/v3"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/filepathext" "github.com/go-task/task/v3/internal/filepathext"

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
) )

View File

@@ -5,7 +5,7 @@ import (
"sync" "sync"
"github.com/elliotchance/orderedmap/v3" "github.com/elliotchance/orderedmap/v3"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy" "github.com/go-task/task/v3/internal/deepcopy"

View File

@@ -22,7 +22,13 @@ func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error)
resolvedEntrypoint, err := fsext.Search(entrypoint, dir, DefaultTaskfiles) resolvedEntrypoint, err := fsext.Search(entrypoint, dir, DefaultTaskfiles)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: false} if entrypoint == "" {
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: true}
} else {
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: false}
}
} else if errors.Is(err, os.ErrPermission) {
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: true, OwnerChange: true}
} }
return nil, err return nil, err
} }

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
@@ -127,19 +128,19 @@ func (node *GitNode) getOrCloneRepo(ctx context.Context) (string, error) {
repoMutex.Lock() repoMutex.Lock()
defer repoMutex.Unlock() 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) cacheDir := filepath.Join(os.TempDir(), "task-git-repos", cacheKey)
// check if repo is already cached (under the lock) // Check cache FIRST - if already cloned, no network needed, timeout irrelevant
gitDir := filepath.Join(cacheDir, ".git") gitDir := filepath.Join(cacheDir, ".git")
if _, err := os.Stat(gitDir); err == nil { if _, err := os.Stat(gitDir); err == nil {
return cacheDir, nil return cacheDir, nil
} }
// Only check context if we need to clone (requires network)
if err := ctx.Err(); err != nil {
return "", fmt.Errorf("context cancelled while waiting for repository lock: %w", err)
}
getterURL := node.buildURL() getterURL := node.buildURL()
client := &getter.Client{ client := &getter.Client{
@@ -191,8 +192,8 @@ func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
return entrypoint, nil return entrypoint, nil
} }
dir, _ := filepath.Split(node.path) dir, _ := path.Split(node.path)
resolvedEntrypoint := fmt.Sprintf("%s//%s", node.url, filepath.Join(dir, entrypoint)) resolvedEntrypoint := fmt.Sprintf("%s//%s", node.url, path.Join(dir, entrypoint))
if node.ref != "" { if node.ref != "" {
return fmt.Sprintf("%s?ref=%s", resolvedEntrypoint, node.ref), nil return fmt.Sprintf("%s?ref=%s", resolvedEntrypoint, node.ref), nil
} }

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/dominikbraun/graph" "github.com/dominikbraun/graph"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/errors"

View File

@@ -12,6 +12,7 @@ import (
type TaskRC struct { type TaskRC struct {
Version *semver.Version `yaml:"version"` Version *semver.Version `yaml:"version"`
Verbose *bool `yaml:"verbose"` Verbose *bool `yaml:"verbose"`
Silent *bool `yaml:"silent"`
Color *bool `yaml:"color"` Color *bool `yaml:"color"`
DisableFuzzy *bool `yaml:"disable-fuzzy"` DisableFuzzy *bool `yaml:"disable-fuzzy"`
Concurrency *int `yaml:"concurrency"` Concurrency *int `yaml:"concurrency"`
@@ -63,6 +64,7 @@ func (t *TaskRC) Merge(other *TaskRC) {
t.Remote.CertKey = cmp.Or(other.Remote.CertKey, t.Remote.CertKey) t.Remote.CertKey = cmp.Or(other.Remote.CertKey, t.Remote.CertKey)
t.Verbose = cmp.Or(other.Verbose, t.Verbose) t.Verbose = cmp.Or(other.Verbose, t.Verbose)
t.Silent = cmp.Or(other.Silent, t.Silent)
t.Color = cmp.Or(other.Color, t.Color) t.Color = cmp.Or(other.Color, t.Color)
t.DisableFuzzy = cmp.Or(other.DisableFuzzy, t.DisableFuzzy) t.DisableFuzzy = cmp.Or(other.DisableFuzzy, t.DisableFuzzy)
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency) t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)

View File

@@ -3,7 +3,7 @@ package taskrc
import ( import (
"os" "os"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v3"
"github.com/go-task/task/v3/taskrc/ast" "github.com/go-task/task/v3/taskrc/ast"
) )

View File

@@ -6,6 +6,7 @@ import (
"slices" "slices"
"strings" "strings"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/fsext" "github.com/go-task/task/v3/internal/fsext"
"github.com/go-task/task/v3/taskrc/ast" "github.com/go-task/task/v3/taskrc/ast"
) )
@@ -62,6 +63,9 @@ func GetConfig(dir string) (*ast.TaskRC, error) {
return config, err return config, err
} }
entrypoints, err := fsext.SearchAll("", absDir, defaultTaskRCs) entrypoints, err := fsext.SearchAll("", absDir, defaultTaskRCs)
if errors.Is(err, os.ErrPermission) {
err = nil
}
if err != nil { if err != nil {
return config, err return config, err
} }

View File

@@ -158,3 +158,21 @@ tasks:
if: '{{ eq .ENV "dev" }}' if: '{{ eq .ENV "dev" }}'
cmds: cmds:
- echo "should not appear" - echo "should not appear"
# Task-level if with dynamic variable (condition met)
task-if-dynamic-true:
vars:
ENABLE_FEATURE:
sh: 'echo "true"'
if: '{{ eq .ENABLE_FEATURE "true" }}'
cmds:
- echo "dynamic feature enabled"
# Task-level if with dynamic variable (condition not met)
task-if-dynamic-false:
vars:
ENABLE_FEATURE:
sh: 'echo "false"'
if: '{{ eq .ENABLE_FEATURE "true" }}'
cmds:
- echo "should not appear"

View File

@@ -0,0 +1,2 @@
task: dynamic variable: "echo \"false\"" result: "false"
task: if condition not met - skipped: "task-if-dynamic-false"

View File

@@ -0,0 +1 @@
dynamic feature enabled

View File

@@ -90,12 +90,16 @@ export default defineConfig({
head.push(['link', { rel: 'canonical', href: canonicalUrl }]) head.push(['link', { rel: 'canonical', href: canonicalUrl }])
// Dynamic Open Graph and Twitter meta tags // Dynamic Open Graph and Twitter meta tags
const pageTitle = pageData.frontmatter.title || pageData.title || taskName const isHome = pageData.relativePath === 'index.md';
var pageTitle = pageData.frontmatter.title || pageData.title || taskName;
if (!isHome) {
pageTitle = `${pageTitle} | ${taskName}`;
}
const pageDescription = pageData.frontmatter.description || pageData.description || taskDescription const pageDescription = pageData.frontmatter.description || pageData.description || taskDescription
head.push(['meta', { property: 'og:title', content: `${pageTitle} | Task` }]) head.push(['meta', { property: 'og:title', content: pageTitle }])
head.push(['meta', { property: 'og:description', content: pageDescription }]) head.push(['meta', { property: 'og:description', content: pageDescription }])
head.push(['meta', { property: 'og:url', content: canonicalUrl }]) head.push(['meta', { property: 'og:url', content: canonicalUrl }])
head.push(['meta', { name: 'twitter:title', content: `${pageTitle} | Task` }]) head.push(['meta', { name: 'twitter:title', content: pageTitle }])
head.push(['meta', { name: 'twitter:description', content: pageDescription }]) head.push(['meta', { name: 'twitter:description', content: pageDescription }])
// Noindex pour 404 // Noindex pour 404
@@ -370,6 +374,11 @@ export default defineConfig({
{ icon: 'mastodon', link: 'https://fosstodon.org/@task' } { icon: 'mastodon', link: 'https://fosstodon.org/@task' }
], ],
editLink: {
text: 'Edit this page on GitHub',
pattern: 'https://github.com/go-task/task/edit/main/website/src/:path'
},
footer: { footer: {
message: message:
'Built with <a target="_blank" href="https://www.netlify.com">Netlify</a>' 'Built with <a target="_blank" href="https://www.netlify.com">Netlify</a>'

View File

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

View File

@@ -8,6 +8,11 @@ export const sponsors = [
url: 'https://devowl.io/', url: 'https://devowl.io/',
img: '/img/devowl.io.svg' img: '/img/devowl.io.svg'
}, },
{
name: 'GoodX',
url: 'https://goodx.international/',
img: '/img/goodx.svg'
},
{ {
name: 'Magic', name: 'Magic',
url: 'https://magic.dev/', url: 'https://magic.dev/',

View File

@@ -19,9 +19,9 @@
"prettier": "^3.6.2", "prettier": "^3.6.2",
"vitepress": "^1.6.3", "vitepress": "^1.6.3",
"vitepress-plugin-group-icons": "^1.6.1", "vitepress-plugin-group-icons": "^1.6.1",
"vitepress-plugin-tabs": "^0.7.1", "vitepress-plugin-tabs": "^0.8.0",
"vitepress-plugin-llms": "^1.9.1", "vitepress-plugin-llms": "^1.9.1",
"vue": "^3.5.18" "vue": "^3.5.18"
}, },
"packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316" "packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017"
} }

2501
website/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ title: Any Variables
author: pd93 author: pd93
date: 2024-05-09 date: 2024-05-09
outline: deep outline: deep
editLink: false
--- ---
# Any Variables # Any Variables

View File

@@ -4,9 +4,10 @@ description: Introduction of the `if:` control and required variable prompts.
author: vmaerten author: vmaerten
date: 2026-01-24 date: 2026-01-24
outline: deep outline: deep
editLink: false
--- ---
# New `if:` control and interactivity support # New `if:` Control and Variable Prompt
<AuthorCard :author="$frontmatter.author" /> <AuthorCard :author="$frontmatter.author" />

View File

@@ -1,6 +1,7 @@
--- ---
title: Blog title: Blog
description: Latest news and updates from the Task team description: Latest news and updates from the Task team
editLink: false
--- ---
<BlogPost <BlogPost

View File

@@ -5,6 +5,7 @@ description:
author: pd93 author: pd93
date: 2024-05-09 date: 2024-05-09
outline: deep outline: deep
editLink: false
--- ---
# Introducing Experiments # Introducing Experiments

View File

@@ -4,6 +4,7 @@ description: The journey of enhancing Windows support in Task.
author: andreynering author: andreynering
date: 2025-09-15 date: 2025-09-15
outline: deep outline: deep
editLink: false
--- ---
# Announcing Built-in Core Utilities for Windows # Announcing Built-in Core Utilities for Windows

View File

@@ -1,12 +1,43 @@
--- ---
title: Changelog title: Changelog
outline: deep outline: deep
editLink: false
--- ---
# Changelog # Changelog
::: v-pre ::: v-pre
## v3.49.0 - 2026-03-07
- Fixed included Taskfiles with `watch: true` not triggering watch mode when
called from the root Taskfile (#2686, #1763 by @trulede).
- Fixed Remote Git Taskfiles failing on Windows due to backslashes in URL paths
(#2656 by @Trim21).
- Fixed remote Git Taskfiles timing out when resolving includes after accepting
the trust prompt (#2669, #2668 by @vmaerten).
- Fixed unclear error message when Taskfile search stops at a directory
ownership boundary (#2682, #1683 by @trulede).
- Fixed global variables from imported Taskfiles not resolving `ref:` values
correctly (#2632 by @trulede).
- Every `.taskrc.yml` option can now be overridden with a `TASK_`-prefixed
environment variable, making CI and container configuration easier (#2607,
#1066 by @vmaerten).
## v3.48.0 - 2026-01-26
- Fixed `if:` conditions when using to check dynamic variables. Also, skip
variable prompt if task would be skipped by `if:` (#2658, #2660 by @vmaerten).
- Fixed `ROOT_TASKFILE` variable pointing to directory instead of the actual
Taskfile path when no explicit `-t` flag is provided (#2635, #1706 by
@trulede).
- Included Taskfiles with `silent: true` now properly propagate silence to their
tasks, while still allowing individual tasks to override with `silent: false`
(#2640, #1319 by @trulede).
- Added TLS certificate options for Remote Taskfiles: use `--cacert` for
self-signed certificates and `--cert`/`--cert-key` for mTLS authentication
(#2537, #2242 by @vmaerten).
## v3.47.0 - 2026-01-24 ## v3.47.0 - 2026-01-24
- Fixed remote git Taskfiles: cloning now works without explicit ref, and - Fixed remote git Taskfiles: cloning now works without explicit ref, and

View File

@@ -355,6 +355,8 @@ remote:
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `false` - **Default**: `false`
- **Description**: Allow insecure connections when fetching remote Taskfiles - **Description**: Allow insecure connections when fetching remote Taskfiles
- **CLI equivalent**: `--insecure`
- **Environment variable**: `TASK_REMOTE_INSECURE`
```yaml ```yaml
remote: remote:
@@ -366,6 +368,8 @@ remote:
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `false` - **Default**: `false`
- **Description**: Work in offline mode, preventing remote Taskfile fetching - **Description**: Work in offline mode, preventing remote Taskfile fetching
- **CLI equivalent**: `--offline`
- **Environment variable**: `TASK_REMOTE_OFFLINE`
```yaml ```yaml
remote: remote:
@@ -378,6 +382,8 @@ remote:
- **Default**: 10s - **Default**: 10s
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` - **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Timeout duration for remote operations (e.g., '30s', '5m') - **Description**: Timeout duration for remote operations (e.g., '30s', '5m')
- **CLI equivalent**: `--timeout`
- **Environment variable**: `TASK_REMOTE_TIMEOUT`
```yaml ```yaml
remote: remote:
@@ -391,6 +397,8 @@ remote:
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` - **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h', - **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h',
'24h') '24h')
- **CLI equivalent**: `--expiry`
- **Environment variable**: `TASK_REMOTE_CACHE_EXPIRY`
```yaml ```yaml
remote: remote:
@@ -404,7 +412,7 @@ remote:
- **Description**: Directory where remote Taskfiles are cached. Can be an - **Description**: Directory where remote Taskfiles are cached. Can be an
absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory. absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory.
- **CLI equivalent**: `--remote-cache-dir` - **CLI equivalent**: `--remote-cache-dir`
- **Environment variable**: `TASK_REMOTE_DIR` (lowest priority) - **Environment variable**: `TASK_REMOTE_CACHE_DIR`
```yaml ```yaml
remote: remote:
@@ -418,6 +426,7 @@ remote:
- **Description**: List of trusted hosts for remote Taskfiles. Hosts in this - **Description**: List of trusted hosts for remote Taskfiles. Hosts in this
list will not prompt for confirmation when downloading Taskfiles list will not prompt for confirmation when downloading Taskfiles
- **CLI equivalent**: `--trusted-hosts` - **CLI equivalent**: `--trusted-hosts`
- **Environment variable**: `TASK_REMOTE_TRUSTED_HOSTS` (comma-separated)
```yaml ```yaml
remote: remote:

View File

@@ -45,6 +45,17 @@ Then you can install Task with:
apt install task apt install task
``` ```
:::info Package Repository Hosting
[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=for-the-badge)](https://cloudsmith.com)
Package repository hosting for deb/rpm is graciously provided by [Cloudsmith](https://cloudsmith.com).
Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that
enables your organization to create, store and share packages in any format, to any place, with total
confidence.
:::
### [Homebrew](https://brew.sh) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) {#homebrew} ### [Homebrew](https://brew.sh) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) {#homebrew}
Task is available via our official Homebrew tap Task is available via our official Homebrew tap

View File

@@ -12,9 +12,9 @@ outline: deep
Task has an Task has an
[official extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=task.vscode-task). [official extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=task.vscode-task).
The code for this project can be found The code for this project can be found in
[here](https://github.com/go-task/vscode-task). To use this extension, you must [our GitHub repository](https://github.com/go-task/vscode-task). To use this
have Task v3.23.0+ installed on your system. extension, you must have Task v3.45.3+ installed on your system.
This extension provides the following features (and more): This extension provides the following features (and more):
@@ -30,6 +30,19 @@ To get autocompletion and validation for your Taskfile, see the
![Task for Visual Studio Code](https://github.com/go-task/vscode-task/blob/main/res/preview.png?raw=true) ![Task for Visual Studio Code](https://github.com/go-task/vscode-task/blob/main/res/preview.png?raw=true)
### Configuration namespace change
In v1.0.0 of the extension, the configuration namespace was changed from `task`
to `taskfile` in order to fix
[an issue](https://github.com/go-task/vscode-task/issues/56).
![Configuration namespace change warning](../public/img/config-namespace-change.png)
If you receive a warning like the one above, you will need to update your
settings to use the new `taskfile` namespace instead:
![Configuration namespace diff](../public/img/config-namespace-diff.png)
## Schema ## Schema
This was initially created by @KROSF in This was initially created by @KROSF in

View File

@@ -10,8 +10,8 @@ outline: deep
Task has multiple ways of being configured. These methods are parsed, in Task has multiple ways of being configured. These methods are parsed, in
sequence, in the following order with the highest priority last: sequence, in the following order with the highest priority last:
- [Environment variables](./environment.md)
- [Configuration files](./config.md) - [Configuration files](./config.md)
- [Environment variables](./environment.md)
- _Command-line flags_ - _Command-line flags_
In this document, we will look at the last of the three options, command-line In this document, we will look at the last of the three options, command-line
@@ -72,6 +72,14 @@ task --init
task -i task -i
``` ```
::: tip
Combine `--list` or `--list-all` with `--silent` (`-ls` or `-as` for shortants)
to list only the task names in each line. Useful for scripting with `grep` or
similar.
:::
## Options ## Options
### General ### General
@@ -96,6 +104,9 @@ task --version
Enable verbose mode for detailed output. Enable verbose mode for detailed output.
- **Config equivalent**: [`verbose`](./config.md#verbose)
- **Environment variable**: [`TASK_VERBOSE`](./environment.md#task-verbose)
```bash ```bash
task build --verbose task build --verbose
``` ```
@@ -104,13 +115,20 @@ task build --verbose
Disable command echoing. Disable command echoing.
- **Config equivalent**: [`silent`](./config.md#silent)
- **Environment variable**: [`TASK_SILENT`](./environment.md#task-silent)
```bash ```bash
task deploy --silent task deploy --silent
``` ```
#### `--disable-fuzzy` #### `--disable-fuzzy`
Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name. Disable fuzzy matching for task names. When enabled, Task will not suggest
similar task names when you mistype a task name.
- **Config equivalent**: [`disable-fuzzy`](./config.md#disable-fuzzy)
- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy)
```bash ```bash
task buidl --disable-fuzzy task buidl --disable-fuzzy
@@ -124,6 +142,9 @@ task buidl --disable-fuzzy
Stop executing dependencies as soon as one of them fails. Stop executing dependencies as soon as one of them fails.
- **Config equivalent**: [`failfast`](./config.md#failfast)
- **Environment variable**: [`TASK_FAILFAST`](./environment.md#task-failfast)
```bash ```bash
task build --failfast task build --failfast
``` ```
@@ -140,6 +161,8 @@ task build --force
Compile and print tasks without executing them. Compile and print tasks without executing them.
- **Environment variable**: [`TASK_DRY`](./environment.md#task-dry)
```bash ```bash
task deploy --dry task deploy --dry
``` ```
@@ -156,6 +179,9 @@ task test lint --parallel
Limit the number of concurrent tasks. Zero means unlimited. Limit the number of concurrent tasks. Zero means unlimited.
- **Config equivalent**: [`concurrency`](./config.md#concurrency)
- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency)
```bash ```bash
task test --concurrency 4 task test --concurrency 4
``` ```
@@ -232,6 +258,9 @@ task test --output group --output-group-error-only
Control colored output. Enabled by default. Control colored output. Enabled by default.
- **Config equivalent**: [`color`](./config.md#color)
- **Environment variable**: [`TASK_COLOR`](./environment.md#task-color)
```bash ```bash
task build --color=false task build --color=false
# or use environment variable # or use environment variable
@@ -266,7 +295,12 @@ task --list --json
#### `--sort <mode>` #### `--sort <mode>`
Change task listing order. Available modes: `default`, `alphanumeric`, `none`. Change task listing order. Available modes:
- `default` - Sorts tasks alphabetically by name, but ensures that root tasks
(tasks without a namespace) are listed before namespaced tasks.
- `alphanumeric` - Sort tasks alphabetically by name.
- `none` - No sorting. Uses the order as defined in the Taskfile.
```bash ```bash
task --list --sort alphanumeric task --list --sort alphanumeric
@@ -297,6 +331,8 @@ task build --watch --interval 1s
Automatically answer "yes" to all prompts. Automatically answer "yes" to all prompts.
- **Environment variable**: [`TASK_ASSUME_YES`](./environment.md#task-assume-yes)
```bash ```bash
task deploy --yes task deploy --yes
``` ```
@@ -306,9 +342,11 @@ task deploy --yes
Enable interactive prompts for missing required variables. When a required Enable interactive prompts for missing required variables. When a required
variable is not provided, Task will prompt for input instead of failing. variable is not provided, Task will prompt for input instead of failing.
Task automatically detects non-TTY environments (like CI pipelines) and Task automatically detects non-TTY environments (like CI pipelines) and skips
skips prompts. This flag can also be set in `.taskrc.yml` to enable prompts prompts. This flag can also be set in `.taskrc.yml` to enable prompts by
by default. default.
- **Environment variable**: [`TASK_INTERACTIVE`](./environment.md#task-interactive)
```bash ```bash
task deploy --interactive task deploy --interactive

View File

@@ -10,11 +10,11 @@ outline: deep
Task has multiple ways of being configured. These methods are parsed, in Task has multiple ways of being configured. These methods are parsed, in
sequence, in the following order with the highest priority last: sequence, in the following order with the highest priority last:
- [Environment variables](./environment.md)
- _Configuration files_ - _Configuration files_
- [Environment variables](./environment.md)
- [Command-line flags](./cli.md) - [Command-line flags](./cli.md)
In this document, we will look at the second of the three options, configuration In this document, we will look at the first of the three options, configuration
files. files.
## File Precedence ## File Precedence
@@ -86,17 +86,31 @@ experiments:
- **Default**: `false` - **Default**: `false`
- **Description**: Enable verbose output for all tasks - **Description**: Enable verbose output for all tasks
- **CLI equivalent**: [`-v, --verbose`](./cli.md#-v---verbose) - **CLI equivalent**: [`-v, --verbose`](./cli.md#-v---verbose)
- **Environment variable**: [`TASK_VERBOSE`](./environment.md#task-verbose)
```yaml ```yaml
verbose: true verbose: true
``` ```
### `silent`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Disables echoing of commands
- **CLI equivalent**: [`-s, --silent`](./cli.md#-s---silent)
- **Environment variable**: [`TASK_SILENT`](./environment.md#task-silent)
```yaml
silent: true
```
### `color` ### `color`
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `true` - **Default**: `true`
- **Description**: Enable colored output. Colors are automatically enabled in CI environments (`CI=true`). - **Description**: Enable colored output. Colors are automatically enabled in CI environments (`CI=true`).
- **CLI equivalent**: [`-c, --color`](./cli.md#-c---color) - **CLI equivalent**: [`-c, --color`](./cli.md#-c---color)
- **Environment variable**: [`TASK_COLOR`](./environment.md#task-color)
```yaml ```yaml
color: false color: false
@@ -108,6 +122,7 @@ color: false
- **Default**: `false` - **Default**: `false`
- **Description**: Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name. - **Description**: Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name.
- **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy) - **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy)
- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy)
```yaml ```yaml
disable-fuzzy: true disable-fuzzy: true
@@ -119,6 +134,7 @@ disable-fuzzy: true
- **Minimum**: `1` - **Minimum**: `1`
- **Description**: Number of concurrent tasks to run - **Description**: Number of concurrent tasks to run
- **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number) - **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number)
- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency)
```yaml ```yaml
concurrency: 4 concurrency: 4
@@ -129,7 +145,8 @@ concurrency: 4
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `false` - **Default**: `false`
- **Description**: Stop executing dependencies as soon as one of them fail - **Description**: Stop executing dependencies as soon as one of them fail
- **CLI equivalent**: [`-F, --failfast`](./cli.md#f-failfast) - **CLI equivalent**: [`-F, --failfast`](./cli.md#-f---failfast)
- **Environment variable**: [`TASK_FAILFAST`](./environment.md#task-failfast)
```yaml ```yaml
failfast: true failfast: true
@@ -156,6 +173,7 @@ Here's a complete example of a `.taskrc.yml` file with all available options:
```yaml ```yaml
# Global settings # Global settings
verbose: true verbose: true
silent: false
color: true color: true
disable-fuzzy: false disable-fuzzy: false
concurrency: 2 concurrency: 2

View File

@@ -9,16 +9,78 @@ outline: deep
Task has multiple ways of being configured. These methods are parsed, in Task has multiple ways of being configured. These methods are parsed, in
sequence, in the following order with the highest priority last: sequence, in the following order with the highest priority last:
- _Environment variables_
- [Configuration files](./config.md) - [Configuration files](./config.md)
- _Environment variables_
- [Command-line flags](./cli.md) - [Command-line flags](./cli.md)
In this document, we will look at the first of the three options, environment In this document, we will look at the second of the three options, environment
variables. All Task-specific variables are prefixed with `TASK_` and override variables. All Task-specific variables are prefixed with `TASK_` and override
their configuration file equivalents. their configuration file equivalents.
## Variables ## Variables
All [configuration file options](./config.md) can also be set via environment
variables. The priority order is: CLI flags > environment variables > config files > defaults.
### `TASK_VERBOSE`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Enable verbose output for all tasks
- **Config equivalent**: [`verbose`](./config.md#verbose)
### `TASK_SILENT`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Disables echoing of commands
- **Config equivalent**: [`silent`](./config.md#silent)
### `TASK_COLOR`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `true`
- **Description**: Enable colored output
- **Config equivalent**: [`color`](./config.md#color)
### `TASK_DISABLE_FUZZY`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Disable fuzzy matching for task names
- **Config equivalent**: [`disable-fuzzy`](./config.md#disable-fuzzy)
### `TASK_CONCURRENCY`
- **Type**: `integer`
- **Description**: Limit number of tasks to run concurrently
- **Config equivalent**: [`concurrency`](./config.md#concurrency)
### `TASK_FAILFAST`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: When running tasks in parallel, stop all tasks if one fails
- **Config equivalent**: [`failfast`](./config.md#failfast)
### `TASK_DRY`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Compiles and prints tasks in the order that they would be run, without executing them
### `TASK_ASSUME_YES`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Assume "yes" as answer to all prompts
### `TASK_INTERACTIVE`
- **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false`
- **Description**: Prompt for missing required variables
### `TASK_TEMP_DIR` ### `TASK_TEMP_DIR`
Defines the location of Task's temporary directory which is used for storing Defines the location of Task's temporary directory which is used for storing
@@ -34,18 +96,6 @@ Valid values are `true` (`1`) or `false` (`0`). By default, this is `true` on
Windows and `false` on other operating systems. We might consider making this Windows and `false` on other operating systems. We might consider making this
enabled by default on all platforms in the future. enabled by default on all platforms in the future.
### `TASK_REMOTE_DIR`
Defines the location of Task's remote temporary directory which is used for
caching remote files. Can be relative like `tmp/task` or absolute like
`/tmp/.task` or `~/.task`. Relative paths are relative to the root Taskfile, not
the working directory. Defaults to: `./.task`.
### `TASK_OFFLINE`
Set the `--offline` flag through the environment variable. Only for remote
experiment. CLI flag `--offline` takes precedence over the env variable.
### `FORCE_COLOR` ### `FORCE_COLOR`
Force color output usage. Force color output usage.

View File

@@ -543,6 +543,21 @@ tasks:
- go build ./... - go build ./...
``` ```
#### `method`
- **Type**: `string`
- **Default**: `checksum`
- **Options**: `checksum`, `timestamp`, `none`
- **Description**: Method for checking if the task is up-to-date. Refer to the `method` root property for details.
```yaml
tasks:
build:
sources:
- go.mod
method: timestamp
```
#### `sources` #### `sources`
- **Type**: `[]string` or `[]Glob` - **Type**: `[]string` or `[]Glob`
@@ -637,7 +652,7 @@ tasks:
- go build -ldflags="-s -w" ./... - go build -ldflags="-s -w" ./...
``` ```
### `dir` #### `dir`
- **Type**: `string` - **Type**: `string`
- **Description**: The directory in which this task should run - **Description**: The directory in which this task should run

View File

@@ -16,59 +16,32 @@ the Taskfile.
artifacts automatically when a new Git tag is pushed to `main` branch (raw artifacts automatically when a new Git tag is pushed to `main` branch (raw
executables and DEB and RPM packages). executables and DEB and RPM packages).
Since v3.15.0, raw executables can also be reproduced and verified locally by Raw executables can also be reproduced and verified locally by
checking out a specific tag and calling `goreleaser build`, using the Go version checking out a specific tag and calling `goreleaser build`, using the Go version
defined in the above GitHub Actions. defined in the above GitHub Actions.
## Homebrew ## Package managers
Goreleaser will automatically push a new commit to the GoReleaser will automatically publish the release to most package managers:
[Formula/go-task.rb][gotaskrb] file in the [Homebrew tap][homebrewtap]
repository to release the new version.
## npm * Cloudsmith (DEB and RPM repositories)
* Homebrew
* npm
* winget
To release to npm update the version in the [`package.json`][packagejson] file A single package manager still require manual steps:
and then run `task npm:publish` to push it.
## Snapcraft * Snapcraft:
* Update the `version:` field on [snapcraft.yaml][snapcraftyaml]
<!-- * Trigger a new build on [Snapcraft -> Builds][snapcraftbuilds] -->
* Once finished, move the new build to "stable" on [Snapcraft -> Releases][snapcraftreleases]
The [snap package][snappackage] requires to manual steps to release a new These package managers are updated automatically by the community:
version:
- Updating the current version on [snapcraft.yaml][snapcraftyaml]. * [Scoop](https://github.com/ScoopInstaller/Main/blob/master/bucket/task.json)
- Moving both `amd64`, `armhf` and `arm64` new artifacts to the stable channel * [Nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix)
on the [Snapcraft dashboard][snapcraftdashboard].
## winget
winget also requires manual steps to be completed. By running
`task goreleaser:test` locally, manifest files will be generated on
`dist/winget/manifests/t/Task/Task/v{version}`.
[Upload the manifest directory into this fork](https://github.com/go-task/winget-pkgs/tree/master/manifests/t/Task/Task)
and open a pull request into
[this repository](https://github.com/microsoft/winget-pkgs).
## Scoop
Scoop is a command-line package manager for the Windows operating system. Scoop
package manifests are maintained by the community. Scoop owners usually take
care of updating versions there by editing
[this file](https://github.com/ScoopInstaller/Main/blob/master/bucket/task.json).
If you think its Task version is outdated, open an issue to let us know.
## Nix
Nix is a community owned installation method. Nix package maintainers usually
take care of updating versions there by editing
[this file](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix).
If you think its Task version is outdated, open an issue to let us know.
[goreleaser]: https://goreleaser.com/ [goreleaser]: https://goreleaser.com/
[homebrewtap]: https://github.com/go-task/homebrew-tap [snapcraftyaml]: https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml#L2
[gotaskrb]: https://github.com/go-task/homebrew-tap/blob/main/Formula/go-task.rb [snapcraftbuilds]: https://snapcraft.io/task/builds
[packagejson]: https://github.com/go-task/task/blob/main/package.json#L3 [snapcraftreleases]: https://snapcraft.io/task/releases
[snappackage]: https://github.com/go-task/snap
[snapcraftyaml]:
https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml#L2
[snapcraftdashboard]: https://snapcraft.io/task/releases

View File

@@ -2,6 +2,7 @@
title: Donate title: Donate
layout: doc layout: doc
outline: false outline: false
editLink: false
--- ---
# :raised_hands: Support Task # :raised_hands: Support Task

View File

@@ -1,4 +1,5 @@
--- ---
title: "Task: The Modern Task Runner"
layout: home layout: home
hero: hero:
name: Task name: Task

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 809.71 363.16">
<defs>
<style>
.cls-1 {
fill: #4d4d4e;
}
.cls-2 {
fill-rule: evenodd;
}
.cls-2, .cls-3 {
fill: #0580c3;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<g id="International_logo" data-name="International logo">
<g id="International_logo-2" data-name="International logo">
<g>
<path class="cls-3" d="M79.14,271.86c-14.64,0-27.95-2.94-39.93-8.81-11.99-5.87-21.52-14.76-28.59-26.66-7.08-11.9-10.62-26.78-10.62-44.64,0-13.19,2.09-24.89,6.27-35.1,4.18-10.22,9.89-18.86,17.13-25.94,7.24-7.08,15.56-12.42,24.97-16.04,9.41-3.62,19.34-5.43,29.8-5.43,11.58,0,21.63,2.05,30.16,6.15,8.52,4.1,15.52,8.97,20.99,14.6l-21.72,26.54c-3.86-3.38-7.92-6.15-12.18-8.33-4.26-2.17-9.53-3.25-15.81-3.25-10.62,0-19.46,3.98-26.54,11.94-7.08,7.96-10.62,19.11-10.62,33.42s3.33,25.94,10.01,33.9c6.67,7.96,17.01,11.94,31,11.94,2.25,0,4.46-.24,6.64-.72,2.17-.48,3.98-1.21,5.43-2.17v-21.71h-23.16v-33.78h59.84v74.8c-5.47,5.31-12.91,9.85-22.32,13.63-9.41,3.78-19.66,5.67-30.76,5.67Z"/>
<path class="cls-3" d="M209.2,271.86c-10.3,0-19.99-2.5-29.08-7.48-9.09-4.98-16.49-12.19-22.2-21.6-5.71-9.41-8.56-20.79-8.56-34.14s2.85-24.73,8.56-34.14c5.71-9.41,13.11-16.61,22.2-21.6,9.09-4.98,18.78-7.48,29.08-7.48s19.99,2.5,29.07,7.48c9.09,4.99,16.49,12.19,22.2,21.6,5.71,9.41,8.57,20.79,8.57,34.14s-2.86,24.73-8.57,34.14c-5.71,9.41-13.11,16.61-22.2,21.6-9.09,4.98-18.78,7.48-29.07,7.48ZM209.2,238.56c6.27,0,10.73-2.69,13.39-8.08,2.65-5.39,3.98-12.67,3.98-21.83s-1.33-16.45-3.98-21.84c-2.65-5.39-7.12-8.08-13.39-8.08s-10.74,2.7-13.39,8.08c-2.65,5.39-3.98,12.67-3.98,21.84s1.33,16.45,3.98,21.83c2.65,5.39,7.12,8.08,13.39,8.08Z"/>
<path class="cls-3" d="M340.7,271.86c-10.3,0-19.99-2.5-29.08-7.48-9.09-4.98-16.49-12.19-22.2-21.6-5.71-9.41-8.56-20.79-8.56-34.14s2.85-24.73,8.56-34.14c5.71-9.41,13.11-16.61,22.2-21.6,9.09-4.98,18.78-7.48,29.08-7.48s19.99,2.5,29.07,7.48c9.09,4.99,16.49,12.19,22.2,21.6,5.71,9.41,8.57,20.79,8.57,34.14s-2.86,24.73-8.57,34.14c-5.71,9.41-13.11,16.61-22.2,21.6-9.09,4.98-18.78,7.48-29.07,7.48ZM340.7,238.56c6.27,0,10.73-2.69,13.39-8.08,2.65-5.39,3.98-12.67,3.98-21.83s-1.33-16.45-3.98-21.84c-2.65-5.39-7.12-8.08-13.39-8.08s-10.74,2.7-13.39,8.08c-2.65,5.39-3.98,12.67-3.98,21.84s1.33,16.45,3.98,21.83c2.65,5.39,7.12,8.08,13.39,8.08Z"/>
<path class="cls-3" d="M462.55,271.86c-14.96,0-26.91-5.67-35.83-17.01-8.92-11.34-13.39-26.74-13.39-46.2,0-13.19,2.37-24.49,7.12-33.9,4.74-9.41,10.9-16.65,18.46-21.71,7.56-5.07,15.44-7.6,23.65-7.6,6.59,0,12.02,1.09,16.29,3.26,4.26,2.17,8.16,5.11,11.7,8.81l-1.45-17.37v-39.09h41.5v167.93h-33.78l-2.9-11.1h-.96c-4.02,4.02-8.77,7.36-14.24,10.02-5.47,2.65-10.86,3.98-16.16,3.98ZM473.65,238.08c3.22,0,6.07-.61,8.56-1.81,2.49-1.21,4.78-3.5,6.88-6.87v-44.4c-2.41-2.25-5.07-3.78-7.96-4.58-2.89-.8-5.71-1.21-8.44-1.21-4.34,0-8.24,2.17-11.7,6.51-3.46,4.35-5.19,11.83-5.19,22.44s1.61,18.46,4.83,23.04c3.22,4.58,7.56,6.88,13.03,6.88Z"/>
<path class="cls-2" d="M584.19,32.22c-14.21,12.99-18.69,16.8-27.15,28.46.21,65.05,23.73,121.48,60.5,167.9-4.91,9.5-39.25,73.17-45.59,45.05-.7-5.94-3.63-21.69.55-42.73,3.85-19.37,7.26-25.27,5.59-26-1.8-.79-7.28,14.73-9.16,34.18-2.28,23.59-4.26,32.83-5.32,39.44-6.27,43.92-24.53,68.97-29.23,82.98-.37,1.11.33,1.51.8,1.61,1.09.23,2.36-.33,3.46-1.82,15.5-21.08,57.6-80.44,89.72-125.2,28.35,22.13,57.88,36.09,87.12,47.47,25.61,10.21,53.58,17.27,72.3,14.88,1.07-.14,1.98-2.67,1.24-2.92-79.16-26.76-140.62-88.41-140.62-88.24,51.5-72.07,94.01-128.26,110.82-139.89,14.2-11.59,27.97-22.19,30.12-30.91,4.8-15.45,5.94-34.81,3.29-36.2-3.48-1.83-12.74,5.78-20.27,14.63-38.35,59.87-88.42,122.73-133.25,183.69-.01.02-12.4-9.58-28.38-45.1-11.5-25.54-19.84-69.6-23.65-119.86-.14-1.88-2.03-2.6-2.88-1.42"/>
</g>
<g>
<path class="cls-1" d="M98.55,353.46c-3.64,0-7.02-.7-10.13-2.1-3.11-1.4-5.81-3.26-8.07-5.58l3.96-4.59c1.84,1.95,4.02,3.52,6.53,4.71,2.5,1.19,5.11,1.78,7.8,1.78,3.43,0,6.09-.78,7.99-2.33,1.9-1.56,2.85-3.6,2.85-6.13,0-1.79-.38-3.22-1.15-4.27-.76-1.05-1.79-1.95-3.09-2.69-1.29-.74-2.76-1.48-4.39-2.21l-7.44-3.24c-1.64-.69-3.26-1.58-4.87-2.69-1.61-1.11-2.95-2.53-4.04-4.27-1.08-1.74-1.62-3.88-1.62-6.41s.7-5,2.1-7.08c1.4-2.08,3.33-3.72,5.82-4.91,2.48-1.19,5.28-1.78,8.39-1.78s5.99.59,8.63,1.78c2.64,1.19,4.88,2.73,6.73,4.63l-3.56,4.27c-1.58-1.53-3.33-2.73-5.26-3.6-1.92-.87-4.1-1.31-6.53-1.31-2.9,0-5.24.69-7,2.06s-2.65,3.22-2.65,5.54c0,1.64.44,2.99,1.31,4.08.87,1.08,1.97,1.97,3.28,2.65,1.32.69,2.66,1.32,4.03,1.9l7.36,3.17c2.01.85,3.81,1.86,5.42,3.05,1.61,1.19,2.89,2.64,3.84,4.35.95,1.71,1.43,3.87,1.43,6.45,0,2.74-.71,5.24-2.14,7.48-1.42,2.24-3.45,4.02-6.09,5.34-2.64,1.32-5.77,1.98-9.42,1.98Z"/>
<path class="cls-1" d="M157.43,353.46c-4.33,0-8.16-1.11-11.51-3.32-3.35-2.21-5.96-5.35-7.83-9.42-1.87-4.06-2.81-8.86-2.81-14.4s.94-10.3,2.81-14.28c1.87-3.98,4.48-7.04,7.83-9.18,3.35-2.14,7.19-3.21,11.51-3.21s8.23,1.07,11.55,3.21c3.32,2.14,5.94,5.2,7.84,9.18,1.9,3.98,2.85,8.74,2.85,14.28s-.95,10.34-2.85,14.4c-1.9,4.06-4.51,7.2-7.84,9.42-3.32,2.22-7.17,3.32-11.55,3.32ZM157.43,347.68c3.11,0,5.82-.88,8.11-2.65,2.3-1.77,4.08-4.25,5.34-7.44,1.26-3.19,1.9-6.95,1.9-11.28,0-6.44-1.4-11.53-4.2-15.27-2.8-3.74-6.52-5.62-11.16-5.62s-8.36,1.87-11.16,5.62c-2.8,3.75-4.2,8.84-4.2,15.27,0,4.33.63,8.09,1.9,11.28,1.26,3.19,3.06,5.67,5.38,7.44,2.32,1.77,5.01,2.65,8.07,2.65Z"/>
<path class="cls-1" d="M202.69,352.51v-51.91h29.91v5.54h-23.34v17.57h19.79v5.54h-19.79v23.27h-6.57Z"/>
<path class="cls-1" d="M264.41,352.51v-46.37h-15.67v-5.54h37.98v5.54h-15.67v46.37h-6.65Z"/>
<path class="cls-1" d="M313.64,352.51l-11-51.91h6.8l5.46,28.25c.48,2.8.98,5.59,1.51,8.39.53,2.8,1.03,5.59,1.5,8.39h.32c.58-2.8,1.19-5.61,1.82-8.43.63-2.82,1.24-5.61,1.82-8.35l7.2-28.25h6.02l7.2,28.25c.63,2.74,1.26,5.53,1.9,8.35.63,2.82,1.27,5.63,1.9,8.43h.32c.48-2.8.95-5.61,1.43-8.43.47-2.82.98-5.61,1.5-8.35l5.46-28.25h6.33l-10.76,51.91h-7.91l-7.83-31.26c-.48-2-.91-3.97-1.31-5.9-.4-1.92-.8-3.89-1.23-5.9h-.32c-.37,2.01-.79,3.97-1.26,5.9-.48,1.93-.92,3.89-1.34,5.9l-7.68,31.26h-7.83Z"/>
<path class="cls-1" d="M375.12,352.51l17.57-51.91h7.44l17.57,51.91h-7.04l-4.91-15.83h-18.91l-4.98,15.83h-6.73ZM390.95,323.47l-2.45,7.91h15.59l-2.45-7.91c-.95-2.9-1.85-5.79-2.69-8.67-.85-2.88-1.69-5.82-2.54-8.82h-.32c-.79,3.01-1.61,5.95-2.45,8.82-.85,2.88-1.74,5.76-2.69,8.67Z"/>
<path class="cls-1" d="M436.93,352.51v-51.91h16.22c3.53,0,6.67.46,9.42,1.39,2.74.92,4.89,2.45,6.45,4.59,1.56,2.14,2.33,5,2.33,8.58,0,4.01-1.05,7.24-3.16,9.7-2.11,2.45-4.96,4.13-8.55,5.02l13.22,22.63h-7.44l-12.51-21.92h-9.42v21.92h-6.57ZM443.49,325.21h8.71c4.06,0,7.17-.83,9.34-2.49,2.16-1.66,3.25-4.18,3.25-7.56s-1.08-5.83-3.25-7.2c-2.16-1.37-5.28-2.06-9.34-2.06h-8.71v19.31Z"/>
<path class="cls-1" d="M493.82,352.51v-51.91h29.91v5.54h-23.34v16.3h19.71v5.62h-19.71v18.83h24.14v5.62h-30.7Z"/>
</g>
</g>
<g>
<path class="cls-3" d="M795.78,300.14v-8.62h-2.91v-1.03h7.06v1.03h-2.91v8.62h-1.24Z"/>
<path class="cls-3" d="M801.66,300.14v-9.66h1.47l1.85,5.15c.12.33.23.67.35,1.01.11.34.23.67.35,1.01h.06c.12-.33.23-.67.33-1.01.1-.34.21-.67.33-1.01l1.83-5.15h1.49v9.66h-1.15v-5.31c0-.43.02-.91.06-1.44.04-.52.07-1,.1-1.42h-.06l-.77,2.19-1.83,5h-.81l-1.83-5-.77-2.19h-.06c.03.42.06.9.1,1.42.03.53.05,1,.05,1.44v5.31h-1.1Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -61,6 +61,11 @@
"type": "boolean", "type": "boolean",
"description": "Enable verbose output" "description": "Enable verbose output"
}, },
"silent": {
"type": "boolean",
"description": "Disables echoing",
"default": false
},
"color": { "color": {
"type": "boolean", "type": "boolean",
"description": "Enable colored output" "description": "Enable colored output"