mirror of
https://github.com/go-task/task.git
synced 2026-06-26 06:06:07 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81fbca3420 | ||
|
|
7323fe8009 | ||
|
|
c8efbc2f4a | ||
|
|
17257a1c31 | ||
|
|
2810c267dd | ||
|
|
a57a16efca | ||
|
|
5ef7313e95 | ||
|
|
e05c9f7793 | ||
|
|
edee501b6b | ||
|
|
efaea39503 | ||
|
|
04b8b75525 | ||
|
|
0dbeaaf187 | ||
|
|
da927ad5fe | ||
|
|
9732f7e08b | ||
|
|
1b418409d1 |
@@ -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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GH_PAT}}
|
github-token: ${{secrets.GH_PAT}}
|
||||||
script: |
|
script: |
|
||||||
|
|||||||
2
.github/workflows/issue-closed.yml
vendored
2
.github/workflows/issue-closed.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
|||||||
issue-closed:
|
issue-closed:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GH_PAT}}
|
github-token: ${{secrets.GH_PAT}}
|
||||||
script: |
|
script: |
|
||||||
|
|||||||
14
.github/workflows/issue-experiment.yml
vendored
14
.github/workflows/issue-experiment.yml
vendored
@@ -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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GH_PAT}}
|
github-token: ${{secrets.GH_PAT}}
|
||||||
script: |
|
script: |
|
||||||
|
|||||||
2
.github/workflows/issue-needs-triage.yml
vendored
2
.github/workflows/issue-needs-triage.yml
vendored
@@ -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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
- uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GH_PAT}}
|
github-token: ${{secrets.GH_PAT}}
|
||||||
script: |
|
script: |
|
||||||
|
|||||||
12
.github/workflows/lint.yml
vendored
12
.github/workflows/lint.yml
vendored
@@ -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@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go-version}}
|
go-version: ${{matrix.go-version}}
|
||||||
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
uses: golangci/golangci-lint-action@v9
|
||||||
with:
|
with:
|
||||||
version: v2.11.1
|
version: v2.8.0
|
||||||
|
|
||||||
lint-jsonschema:
|
lint-jsonschema:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: 3.14
|
python-version: 3.14
|
||||||
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- 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'
|
||||||
|
|||||||
24
.github/workflows/pr-build.yml
vendored
24
.github/workflows/pr-build.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
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@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.26.x'
|
go-version: '1.25.x'
|
||||||
cache: true
|
cache: true
|
||||||
- uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
|
- uses: goreleaser/goreleaser-action@v6
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: checksums
|
name: checksums
|
||||||
path: dist/task_checksums.txt
|
path: dist/task_checksums.txt
|
||||||
- uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
|
- uses: peter-evans/find-comment@v3
|
||||||
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@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
|
- uses: peter-evans/create-or-update-comment@v4
|
||||||
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 }}
|
||||||
|
|||||||
8
.github/workflows/release-nightly.yml
vendored
8
.github/workflows/release-nightly.yml
vendored
@@ -9,17 +9,17 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: 1.26.x
|
go-version: 1.25.x
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser-pro
|
distribution: goreleaser-pro
|
||||||
version: latest
|
version: latest
|
||||||
|
|||||||
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -14,16 +14,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: 1.26.x
|
go-version: 1.25.x
|
||||||
|
|
||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
- uses: actions/setup-node@v6
|
||||||
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@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
|
uses: go-task/setup-task@v1
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
uses: pnpm/action-setup@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@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser-pro
|
distribution: goreleaser-pro
|
||||||
version: latest
|
version: latest
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -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@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
uses: actions/setup-go@v6
|
||||||
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Download Go modules
|
- name: Download Go modules
|
||||||
run: go mod download
|
run: go mod download
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ 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:
|
||||||
@@ -62,7 +60,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: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
|
description: Simple task runner written in Go
|
||||||
section: golang
|
section: golang
|
||||||
license: MIT
|
license: MIT
|
||||||
conflicts:
|
conflicts:
|
||||||
@@ -82,7 +80,7 @@ nfpms:
|
|||||||
|
|
||||||
brews:
|
brews:
|
||||||
- name: go-task
|
- name: go-task
|
||||||
description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
|
description: Task runner / simpler Make alternative written in Go
|
||||||
license: MIT
|
license: MIT
|
||||||
homepage: https://taskfile.dev
|
homepage: https://taskfile.dev
|
||||||
directory: Formula
|
directory: Formula
|
||||||
@@ -102,8 +100,8 @@ brews:
|
|||||||
winget:
|
winget:
|
||||||
- name: Task
|
- name: Task
|
||||||
publisher: Task
|
publisher: Task
|
||||||
short_description: The modern task runner.
|
short_description: A task runner / simpler Make alternative written in Go
|
||||||
description: A fast, cross-platform build tool inspired by Make, designed for modern workflows.
|
description: Task is a task runner / build tool that aims to be simpler and easier to use than, for example, GNU Make.
|
||||||
license: MIT
|
license: MIT
|
||||||
homepage: https://taskfile.dev/
|
homepage: https://taskfile.dev/
|
||||||
publisher_url: https://taskfile.dev/
|
publisher_url: https://taskfile.dev/
|
||||||
@@ -146,7 +144,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 fast, cross-platform build tool inspired by Make, designed for modern workflows.
|
description: A task runner / simpler Make alternative written in Go
|
||||||
homepage: https://taskfile.dev
|
homepage: https://taskfile.dev
|
||||||
license: MIT
|
license: MIT
|
||||||
author: "The Task authors"
|
author: "The Task authors"
|
||||||
@@ -157,6 +155,7 @@ 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}}"
|
||||||
|
|||||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,25 +1,7 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v3.49.0 - 2026-03-07
|
## Unreleased
|
||||||
|
|
||||||
- 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).
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -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: The Modern Task Runner</h1>
|
<h1>Task</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A fast, cross-platform build tool inspired by Make, designed for modern workflows.
|
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>.
|
||||||
</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> | <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>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1>Gold Sponsors</h1>
|
<h1>Gold Sponsors</h1>
|
||||||
@@ -22,11 +22,6 @@
|
|||||||
<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" />
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ func run() error {
|
|||||||
|
|
||||||
// Merge CLI variables first (e.g. FOO=bar) so they take priority over Taskfile defaults
|
// Merge CLI variables first (e.g. FOO=bar) so they take priority over Taskfile defaults
|
||||||
e.Taskfile.Vars.Merge(globals, nil)
|
e.Taskfile.Vars.Merge(globals, nil)
|
||||||
|
// Store CLI vars for scoped mode where they need highest priority
|
||||||
|
e.Compiler.CLIVars = globals
|
||||||
|
|
||||||
// Then ReverseMerge special variables so they're available for templating
|
// Then ReverseMerge special variables so they're available for templating
|
||||||
cliArgsPostDashQuoted, err := args.ToQuotedString(cliArgsPostDash)
|
cliArgsPostDashQuoted, err := args.ToQuotedString(cliArgsPostDash)
|
||||||
|
|||||||
246
compiler.go
246
compiler.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/go-task/task/v3/experiments"
|
||||||
"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"
|
||||||
@@ -25,6 +26,8 @@ type Compiler struct {
|
|||||||
|
|
||||||
TaskfileEnv *ast.Vars
|
TaskfileEnv *ast.Vars
|
||||||
TaskfileVars *ast.Vars
|
TaskfileVars *ast.Vars
|
||||||
|
CLIVars *ast.Vars // CLI vars passed via command line (e.g., task foo VAR=value)
|
||||||
|
Graph *ast.TaskfileGraph
|
||||||
|
|
||||||
Logger *logger.Logger
|
Logger *logger.Logger
|
||||||
|
|
||||||
@@ -44,8 +47,236 @@ func (c *Compiler) FastGetVariables(t *ast.Task, call *Call) (*ast.Vars, error)
|
|||||||
return c.getVariables(t, call, false)
|
return c.getVariables(t, call, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isScopedMode returns true if scoped variable resolution should be used.
|
||||||
|
// Scoped mode requires the experiment to be enabled, a task with location info, and a graph.
|
||||||
|
func (c *Compiler) isScopedMode(t *ast.Task) bool {
|
||||||
|
return experiments.ScopedTaskfiles.Enabled() &&
|
||||||
|
t != nil &&
|
||||||
|
t.Location != nil &&
|
||||||
|
c.Graph != nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*ast.Vars, error) {
|
func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*ast.Vars, error) {
|
||||||
result := env.GetEnviron()
|
if c.isScopedMode(t) {
|
||||||
|
return c.getScopedVariables(t, call, evaluateShVars)
|
||||||
|
}
|
||||||
|
return c.getLegacyVariables(t, call, evaluateShVars)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getScopedVariables resolves variables in scoped mode.
|
||||||
|
// In scoped mode:
|
||||||
|
// - OS env vars are in {{.env.XXX}} namespace, not at root
|
||||||
|
// - Variables from sibling includes are isolated
|
||||||
|
//
|
||||||
|
// Variable resolution order (lowest to highest priority):
|
||||||
|
// 1. Root Taskfile vars
|
||||||
|
// 2. Include Taskfile vars
|
||||||
|
// 3. Include passthrough vars (includes: name: vars:)
|
||||||
|
// 4. Task vars
|
||||||
|
// 5. Call vars
|
||||||
|
// 6. CLI vars
|
||||||
|
func (c *Compiler) getScopedVariables(t *ast.Task, call *Call, evaluateShVars bool) (*ast.Vars, error) {
|
||||||
|
result := ast.NewVars()
|
||||||
|
|
||||||
|
specialVars, err := c.getSpecialVars(t, call)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range specialVars {
|
||||||
|
result.Set(k, ast.Var{Value: v})
|
||||||
|
}
|
||||||
|
|
||||||
|
getRangeFunc := func(dir string) func(k string, v ast.Var) error {
|
||||||
|
return func(k string, v ast.Var) error {
|
||||||
|
cache := &templater.Cache{Vars: result}
|
||||||
|
newVar := templater.ReplaceVar(v, cache)
|
||||||
|
if !evaluateShVars && newVar.Value == nil {
|
||||||
|
result.Set(k, ast.Var{Value: "", Sh: newVar.Sh})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !evaluateShVars {
|
||||||
|
result.Set(k, ast.Var{Value: newVar.Value, Sh: newVar.Sh})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := cache.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if newVar.Value != nil || newVar.Sh == nil {
|
||||||
|
result.Set(k, ast.Var{Value: newVar.Value})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
static, err := c.HandleDynamicVar(newVar, dir, env.GetFromVars(result))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result.Set(k, ast.Var{Value: static})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rangeFunc := getRangeFunc(c.Dir)
|
||||||
|
|
||||||
|
var taskRangeFunc func(k string, v ast.Var) error
|
||||||
|
if t != nil {
|
||||||
|
cache := &templater.Cache{Vars: result}
|
||||||
|
dir := templater.Replace(t.Dir, cache)
|
||||||
|
if err := cache.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dir = filepathext.SmartJoin(c.Dir, dir)
|
||||||
|
taskRangeFunc = getRangeFunc(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootVertex, err := c.Graph.Root()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
envMap := make(map[string]any)
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
k, v, _ := strings.Cut(e, "=")
|
||||||
|
envMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveEnvToMap := func(k string, v ast.Var, dir string) error {
|
||||||
|
cache := &templater.Cache{Vars: result}
|
||||||
|
newVar := templater.ReplaceVar(v, cache)
|
||||||
|
if err := cache.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if newVar.Value != nil || newVar.Sh == nil {
|
||||||
|
if newVar.Value != nil {
|
||||||
|
envMap[k] = newVar.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if evaluateShVars {
|
||||||
|
envSlice := os.Environ()
|
||||||
|
for ek, ev := range envMap {
|
||||||
|
if s, ok := ev.(string); ok {
|
||||||
|
envSlice = append(envSlice, fmt.Sprintf("%s=%s", ek, s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static, err := c.HandleDynamicVar(newVar, dir, envSlice)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
envMap[k] = static
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range rootVertex.Taskfile.Env.All() {
|
||||||
|
if err := resolveEnvToMap(k, v, c.Dir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range rootVertex.Taskfile.Vars.All() {
|
||||||
|
if err := rangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Location.Taskfile != rootVertex.URI {
|
||||||
|
predecessorMap, err := c.Graph.PredecessorMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentChain []*ast.TaskfileVertex
|
||||||
|
currentURI := t.Location.Taskfile
|
||||||
|
for {
|
||||||
|
edges := predecessorMap[currentURI]
|
||||||
|
if len(edges) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var parentURI string
|
||||||
|
for _, edge := range edges {
|
||||||
|
parentURI = edge.Source
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if parentURI == rootVertex.URI {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
parentVertex, err := c.Graph.Vertex(parentURI)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parentChain = append([]*ast.TaskfileVertex{parentVertex}, parentChain...)
|
||||||
|
currentURI = parentURI
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, parent := range parentChain {
|
||||||
|
parentDir := filepath.Dir(parent.URI)
|
||||||
|
for k, v := range parent.Taskfile.Env.All() {
|
||||||
|
if err := resolveEnvToMap(k, v, parentDir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Vars use the parent's directory too
|
||||||
|
parentRangeFunc := getRangeFunc(parentDir)
|
||||||
|
for k, v := range parent.Taskfile.Vars.All() {
|
||||||
|
if err := parentRangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
includeVertex, err := c.Graph.Vertex(t.Location.Taskfile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
includeDir := filepath.Dir(includeVertex.URI)
|
||||||
|
for k, v := range includeVertex.Taskfile.Env.All() {
|
||||||
|
if err := resolveEnvToMap(k, v, includeDir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
includeRangeFunc := getRangeFunc(includeDir)
|
||||||
|
for k, v := range includeVertex.Taskfile.Vars.All() {
|
||||||
|
if err := includeRangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.IncludeVars != nil {
|
||||||
|
for k, v := range t.IncludeVars.All() {
|
||||||
|
if err := rangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if call != nil {
|
||||||
|
for k, v := range t.Vars.All() {
|
||||||
|
if err := taskRangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range call.Vars.All() {
|
||||||
|
if err := taskRangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range c.CLIVars.All() {
|
||||||
|
if err := rangeFunc(k, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set("env", ast.Var{Value: envMap})
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLegacyVariables resolves variables in legacy mode.
|
||||||
|
// In legacy mode, all variables (including OS env) are merged at root level.
|
||||||
|
func (c *Compiler) getLegacyVariables(t *ast.Task, call *Call, evaluateShVars bool) (*ast.Vars, error) {
|
||||||
|
result := env.GetEnviron()
|
||||||
|
|
||||||
specialVars, err := c.getSpecialVars(t, call)
|
specialVars, err := c.getSpecialVars(t, call)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -57,30 +288,22 @@ func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*
|
|||||||
getRangeFunc := func(dir string) func(k string, v ast.Var) error {
|
getRangeFunc := func(dir string) func(k string, v ast.Var) error {
|
||||||
return func(k string, v ast.Var) error {
|
return func(k string, v ast.Var) error {
|
||||||
cache := &templater.Cache{Vars: result}
|
cache := &templater.Cache{Vars: result}
|
||||||
// Replace values
|
|
||||||
newVar := templater.ReplaceVar(v, cache)
|
newVar := templater.ReplaceVar(v, cache)
|
||||||
// If the variable should not be evaluated, but is nil, set it to an empty string
|
|
||||||
// This stops empty interface errors when using the templater to replace values later
|
|
||||||
// Preserve the Sh field so it can be displayed in summary
|
|
||||||
if !evaluateShVars && newVar.Value == nil {
|
if !evaluateShVars && newVar.Value == nil {
|
||||||
result.Set(k, ast.Var{Value: "", Sh: newVar.Sh})
|
result.Set(k, ast.Var{Value: "", Sh: newVar.Sh})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// If the variable should not be evaluated and it is set, we can set it and return
|
|
||||||
if !evaluateShVars {
|
if !evaluateShVars {
|
||||||
result.Set(k, ast.Var{Value: newVar.Value, Sh: newVar.Sh})
|
result.Set(k, ast.Var{Value: newVar.Value, Sh: newVar.Sh})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Now we can check for errors since we've handled all the cases when we don't want to evaluate
|
|
||||||
if err := cache.Err(); err != nil {
|
if err := cache.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// If the variable is already set, we can set it and return
|
|
||||||
if newVar.Value != nil || newVar.Sh == nil {
|
if newVar.Value != nil || newVar.Sh == nil {
|
||||||
result.Set(k, ast.Var{Value: newVar.Value})
|
result.Set(k, ast.Var{Value: newVar.Value})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// If the variable is dynamic, we need to resolve it first
|
|
||||||
static, err := c.HandleDynamicVar(newVar, dir, env.GetFromVars(result))
|
static, err := c.HandleDynamicVar(newVar, dir, env.GetFromVars(result))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -93,8 +316,6 @@ func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*
|
|||||||
|
|
||||||
var taskRangeFunc func(k string, v ast.Var) error
|
var taskRangeFunc func(k string, v ast.Var) error
|
||||||
if t != nil {
|
if t != nil {
|
||||||
// NOTE(@andreynering): We're manually joining these paths here because
|
|
||||||
// this is the raw task, not the compiled one.
|
|
||||||
cache := &templater.Cache{Vars: result}
|
cache := &templater.Cache{Vars: result}
|
||||||
dir := templater.Replace(t.Dir, cache)
|
dir := templater.Replace(t.Dir, cache)
|
||||||
if err := cache.Err(); err != nil {
|
if err := cache.Err(); err != nil {
|
||||||
@@ -114,8 +335,6 @@ func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Resolve any outstanding 'Ref' values in global vars (esp. globals from imported Taskfiles).
|
|
||||||
c.TaskfileVars = templater.ReplaceVars(c.TaskfileVars, &templater.Cache{Vars: result})
|
|
||||||
|
|
||||||
if t != nil {
|
if t != nil {
|
||||||
for k, v := range t.IncludeVars.All() {
|
for k, v := range t.IncludeVars.All() {
|
||||||
@@ -152,7 +371,6 @@ func (c *Compiler) HandleDynamicVar(v ast.Var, dir string, e []string) (string,
|
|||||||
c.muDynamicCache.Lock()
|
c.muDynamicCache.Lock()
|
||||||
defer c.muDynamicCache.Unlock()
|
defer c.muDynamicCache.Unlock()
|
||||||
|
|
||||||
// If the variable is not dynamic or it is empty, return an empty string
|
|
||||||
if v.Sh == nil || *v.Sh == "" {
|
if v.Sh == nil || *v.Sh == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
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))
|
fmt.Fprintln(buf, color.RedString("- %s", message.Err.Error()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(buf, color.RedString("err: %s", te.Errors[0]))
|
fmt.Fprintln(buf, color.RedString("err: %s", te.Errors[0].Err.Error()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise print the error message normally
|
// Otherwise print the error message normally
|
||||||
|
|||||||
@@ -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)) //nolint:staticcheck
|
builder.WriteString(fmt.Sprintf("task: Task %q cancelled because it is missing required variables:\n", err.TaskName))
|
||||||
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)) //nolint:staticcheck
|
builder.WriteString(fmt.Sprintf(" - %s has an invalid value : '%s' (allowed values : %v)\n", s.Name, s.Value, s.Enum))
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.String()
|
return builder.String()
|
||||||
|
|||||||
@@ -11,17 +11,14 @@ 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.OwnerChange {
|
if err.Walk {
|
||||||
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 {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ type (
|
|||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
Taskfile *ast.Taskfile
|
Taskfile *ast.Taskfile
|
||||||
|
Graph *ast.TaskfileGraph
|
||||||
Logger *logger.Logger
|
Logger *logger.Logger
|
||||||
Compiler *Compiler
|
Compiler *Compiler
|
||||||
Output output.Output
|
Output output.Output
|
||||||
|
|||||||
119
executor_test.go
119
executor_test.go
@@ -927,10 +927,6 @@ func TestReference(t *testing.T) {
|
|||||||
name: "reference using templating resolver and dynamic var",
|
name: "reference using templating resolver and dynamic var",
|
||||||
call: "ref-resolver-sh",
|
call: "ref-resolver-sh",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "reference using templating resolver and global var",
|
|
||||||
call: "ref-global",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@@ -1164,10 +1160,6 @@ 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 {
|
||||||
@@ -1188,3 +1180,114 @@ func TestIf(t *testing.T) {
|
|||||||
NewExecutorTest(t, opts...)
|
NewExecutorTest(t, opts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:paralleltest // enableExperimentForTest modifies global state
|
||||||
|
func TestScopedTaskfiles(t *testing.T) {
|
||||||
|
// Legacy tests (without experiment) - vars should be merged globally
|
||||||
|
t.Run("legacy", func(t *testing.T) {
|
||||||
|
// Test with scoped taskfiles disabled (legacy) - vars should be merged globally
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("default"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// In legacy mode, UNIQUE_B should be accessible (merged globally)
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("cross-include"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("a:try-access-b"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Scoped tests (with experiment enabled) - vars should be isolated
|
||||||
|
t.Run("scoped", func(t *testing.T) {
|
||||||
|
enableExperimentForTest(t, &experiments.ScopedTaskfiles, 1)
|
||||||
|
|
||||||
|
// Test with scoped taskfiles enabled - vars should be isolated
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("default"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// Test inheritance: include can access root vars
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("inheritance-a"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("a:print"),
|
||||||
|
)
|
||||||
|
// Test isolation: each include sees its own vars
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("isolation-b"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("b:print"),
|
||||||
|
)
|
||||||
|
// In scoped mode, UNIQUE_B should be empty (isolated)
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("cross-include"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("a:try-access-b"),
|
||||||
|
)
|
||||||
|
// Test env namespace: {{.env.XXX}} should access env vars
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("env-namespace"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("print-env"),
|
||||||
|
)
|
||||||
|
// Test env separation: {{.ROOT_ENV}} at root should be empty (env not at root level)
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("env-separation"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("test-env-separation"),
|
||||||
|
)
|
||||||
|
// Test include env: include's env is accessible via {{.env.XXX}}
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("include-env"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("a:print-env"),
|
||||||
|
)
|
||||||
|
// Test call vars: vars passed when calling a task override task vars
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("call-vars"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("call-with-vars"),
|
||||||
|
)
|
||||||
|
// Test nested includes (3 levels: root → a → nested)
|
||||||
|
// Verifies that nested includes inherit vars from their parent chain
|
||||||
|
NewExecutorTest(t,
|
||||||
|
WithName("nested"),
|
||||||
|
WithExecutorOptions(
|
||||||
|
task.WithDir("testdata/scoped_taskfiles"),
|
||||||
|
task.WithSilent(true),
|
||||||
|
),
|
||||||
|
WithTask("a:nested:print"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ var (
|
|||||||
GentleForce Experiment
|
GentleForce Experiment
|
||||||
RemoteTaskfiles Experiment
|
RemoteTaskfiles Experiment
|
||||||
EnvPrecedence Experiment
|
EnvPrecedence Experiment
|
||||||
|
ScopedTaskfiles Experiment
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inactive experiments. These are experiments that cannot be enabled, but are
|
// Inactive experiments. These are experiments that cannot be enabled, but are
|
||||||
@@ -43,6 +44,7 @@ func ParseWithConfig(dir string, config *ast.TaskRC) {
|
|||||||
GentleForce = New("GENTLE_FORCE", config, 1)
|
GentleForce = New("GENTLE_FORCE", config, 1)
|
||||||
RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1)
|
RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1)
|
||||||
EnvPrecedence = New("ENV_PRECEDENCE", config, 1)
|
EnvPrecedence = New("ENV_PRECEDENCE", config, 1)
|
||||||
|
ScopedTaskfiles = New("SCOPED_TASKFILES", config, 1)
|
||||||
AnyVariables = New("ANY_VARIABLES", config)
|
AnyVariables = New("ANY_VARIABLES", config)
|
||||||
MapVariables = New("MAP_VARIABLES", config)
|
MapVariables = New("MAP_VARIABLES", config)
|
||||||
}
|
}
|
||||||
|
|||||||
44
go.mod
44
go.mod
@@ -2,15 +2,15 @@ module github.com/go-task/task/v3
|
|||||||
|
|
||||||
go 1.24.6
|
go 1.24.6
|
||||||
|
|
||||||
toolchain go1.26.1
|
toolchain go1.25.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
charm.land/bubbles/v2 v2.0.0
|
charm.land/bubbles/v2 v2.0.0-rc.1
|
||||||
charm.land/bubbletea/v2 v2.0.1
|
charm.land/bubbletea/v2 v2.0.0-rc.2
|
||||||
charm.land/lipgloss/v2 v2.0.0
|
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7
|
||||||
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.1
|
github.com/alecthomas/chroma/v2 v2.23.0
|
||||||
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.4.0
|
github.com/puzpuzpuz/xsync/v4 v4.3.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.1.0
|
github.com/zeebo/xxh3 v1.0.2
|
||||||
go.yaml.in/yaml/v3 v3.0.4
|
go.yaml.in/yaml/v4 v4.0.0-rc.3
|
||||||
golang.org/x/sync v0.19.0
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/term v0.40.0
|
golang.org/x/term v0.39.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.4.2 // indirect
|
github.com/charmbracelet/colorprofile v0.3.3 // indirect
|
||||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
|
github.com/charmbracelet/ultraviolet v0.0.0-20251116181749-377898bcce38 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.11.6 // indirect
|
github.com/charmbracelet/x/ansi v0.11.1 // 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.11.0 // indirect
|
github.com/clipperhouse/displaywidth v0.5.0 // indirect
|
||||||
github.com/clipperhouse/stringish v0.1.1 // indirect
|
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
github.com/clipperhouse/uax29/v2 v2.3.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.10 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // 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.20 // indirect
|
github.com/mattn/go-runewidth v0.0.19 // 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.40.0 // indirect
|
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
go.opentelemetry.io/otel/trace v1.39.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.41.0 // indirect
|
golang.org/x/sys v0.40.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
67
go.sum
@@ -2,16 +2,10 @@ 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=
|
||||||
@@ -46,8 +40,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.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
github.com/alecthomas/chroma/v2 v2.23.0 h1:u/Orux1J0eLuZDeQ44froV8smumheieI0EofhbyKhhk=
|
||||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
github.com/alecthomas/chroma/v2 v2.23.0/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=
|
||||||
@@ -100,16 +94,10 @@ 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=
|
||||||
@@ -120,14 +108,10 @@ 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=
|
||||||
@@ -199,8 +183,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.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
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=
|
||||||
@@ -218,8 +202,6 @@ 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=
|
||||||
@@ -234,8 +216,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.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo=
|
github.com/puzpuzpuz/xsync/v4 v4.3.0 h1:w/bWkEJdYuRNYhHn5eXnIT8LzDM1O629X1I9MJSkD7Q=
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
github.com/puzpuzpuz/xsync/v4 v4.3.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=
|
||||||
@@ -270,8 +252,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.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||||
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||||
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=
|
||||||
@@ -280,20 +262,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.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
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.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||||
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=
|
||||||
@@ -304,11 +286,12 @@ 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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||||
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
62
internal/env/env.go
vendored
@@ -3,9 +3,7 @@ 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"
|
||||||
@@ -63,63 +61,3 @@ 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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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, "REMOTE_INSECURE", func() *bool { return config.Remote.Insecure }, false), "Forces Task to download Taskfiles over insecure connections.")
|
pflag.BoolVar(&Insecure, "insecure", getConfig(config, 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, "VERBOSE", func() *bool { return config.Verbose }, false), "Enables verbose mode.")
|
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, func() *bool { return config.Verbose }, false), "Enables verbose mode.")
|
||||||
pflag.BoolVarP(&Silent, "silent", "s", getConfig(config, "SILENT", func() *bool { return config.Silent }, false), "Disables echoing.")
|
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
|
||||||
pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, "DISABLE_FUZZY", func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.")
|
pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.")
|
||||||
pflag.BoolVarP(&AssumeYes, "yes", "y", getConfig(config, "ASSUME_YES", func() *bool { return nil }, false), "Assume \"yes\" as answer to all prompts.")
|
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
|
||||||
pflag.BoolVar(&Interactive, "interactive", getConfig(config, "INTERACTIVE", func() *bool { return config.Interactive }, false), "Prompt for missing required variables.")
|
pflag.BoolVar(&Interactive, "interactive", getConfig(config, 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", getConfig(config, "DRY", func() *bool { return nil }, false), "Compiles and prints tasks in the order that they would be run, without executing them.")
|
pflag.BoolVarP(&Dry, "dry", "n", 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, "COLOR", 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, 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, "CONCURRENCY", func() *int { return config.Concurrency }, 0), "Limit number of tasks to run concurrently.")
|
pflag.IntVarP(&Concurrency, "concurrency", "C", getConfig(config, func() *int { return config.Concurrency }, 0), "Limit number of tasks to run concurrently.")
|
||||||
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
|
pflag.DurationVarP(&Interval, "interval", "I", 0, "Interval to watch for changes.")
|
||||||
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(&Failfast, "failfast", "F", getConfig(config, 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, "REMOTE_OFFLINE", func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.")
|
pflag.BoolVar(&Offline, "offline", getConfig(config, func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.")
|
||||||
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, "REMOTE_TRUSTED_HOSTS", func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).")
|
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).")
|
||||||
pflag.DurationVar(&Timeout, "timeout", getConfig(config, "REMOTE_TIMEOUT", func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.")
|
pflag.DurationVar(&Timeout, "timeout", getConfig(config, func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.")
|
||||||
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
|
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
|
||||||
pflag.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, "REMOTE_CACHE_EXPIRY", func() *time.Duration { return config.Remote.CacheExpiry }, 0), "Expiry duration for cached remote Taskfiles.")
|
pflag.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, func() *time.Duration { return config.Remote.CacheExpiry }, 0), "Expiry duration for cached remote Taskfiles.")
|
||||||
pflag.StringVar(&RemoteCacheDir, "remote-cache-dir", getConfig(config, "REMOTE_CACHE_DIR", func() *string { return config.Remote.CacheDir }, env.GetTaskEnv("REMOTE_DIR")), "Directory to cache 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(&CACert, "cacert", getConfig(config, "REMOTE_CACERT", func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.")
|
pflag.StringVar(&CACert, "cacert", getConfig(config, func() *string { return config.Remote.CACert }, ""), "Path to a custom CA 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(&Cert, "cert", getConfig(config, func() *string { return config.Remote.Cert }, ""), "Path to a client certificate 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.StringVar(&CertKey, "cert-key", getConfig(config, 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 > TASK_COLOR env > taskrc config > NO_COLOR > FORCE_COLOR/CI > default
|
// Priority: CLI flag > taskrc config > NO_COLOR > FORCE_COLOR/CI > default
|
||||||
colorExplicitlySet := pflag.Lookup("color").Changed || env.GetTaskEnv("COLOR") != "" || (config != nil && config.Color != nil)
|
colorExplicitlySet := pflag.Lookup("color").Changed || (config != nil && config.Color != nil)
|
||||||
if !colorExplicitlySet {
|
if !colorExplicitlySet {
|
||||||
if os.Getenv("NO_COLOR") != "" {
|
if os.Getenv("NO_COLOR") != "" {
|
||||||
Color = false
|
Color = false
|
||||||
@@ -311,45 +311,15 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getConfig extracts a config value with priority: env var > taskrc config > fallback
|
// getConfig extracts a config value directly from a pointer field with a fallback default
|
||||||
func getConfig[T any](config *taskrcast.TaskRC, envKey string, fieldFunc func() *T, fallback T) T {
|
func getConfig[T any](config *taskrcast.TaskRC, fieldFunc func() *T, fallback T) T {
|
||||||
if envKey != "" {
|
if config == nil {
|
||||||
if val, ok := getEnvAs[T](envKey); ok {
|
return fallback
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if config != nil {
|
|
||||||
if field := fieldFunc(); field != nil {
|
field := fieldFunc()
|
||||||
return *field
|
if field != nil {
|
||||||
}
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
// The call to SearchNPathRecursively is ambiguous and may return
|
if err != nil {
|
||||||
// os.ErrPermission if its search ends, however it may have still
|
return nil, err
|
||||||
// returned valid paths. Caller may choose to ignore that error.
|
}
|
||||||
return append(entrypoints, paths...), err
|
return append(entrypoints, paths...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,16 +153,13 @@ 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 len(paths) > 0 {
|
if err != nil {
|
||||||
// Regardless of the error, return the first possible filename.
|
return "", err
|
||||||
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
|
||||||
@@ -191,13 +188,10 @@ func SearchNPathRecursively(path string, possibleFilenames []string, n int) ([]s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user id of the directory changes indicate a permission error, otherwise
|
// Error if we reached the root directory and still haven't found a file
|
||||||
// the calling code will infer an error condition based on the accumulated
|
// OR if the user id of the directory changes
|
||||||
// contents of paths.
|
if path == parentPath || (parentOwner != owner) {
|
||||||
if path == parentPath {
|
|
||||||
return paths, nil
|
return paths, nil
|
||||||
} else if parentOwner != owner {
|
|
||||||
return paths, os.ErrPermission
|
|
||||||
}
|
}
|
||||||
|
|
||||||
owner = parentOwner
|
owner = parentOwner
|
||||||
|
|||||||
@@ -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)) //nolint:staticcheck
|
result.WriteString(fmt.Sprintf("%s%s: %v\n", spaces, k, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.String()
|
return result.String()
|
||||||
|
|||||||
@@ -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/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
"mvdan.cc/sh/v3/shell"
|
"mvdan.cc/sh/v3/shell"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.49.0
|
3.47.0
|
||||||
|
|||||||
16
setup.go
16
setup.go
@@ -13,9 +13,11 @@ import (
|
|||||||
"github.com/sajari/fuzzy"
|
"github.com/sajari/fuzzy"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
|
"github.com/go-task/task/v3/experiments"
|
||||||
"github.com/go-task/task/v3/internal/env"
|
"github.com/go-task/task/v3/internal/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"
|
||||||
@@ -59,10 +61,12 @@ func (e *Executor) getRootNode() (taskfile.Node, error) {
|
|||||||
taskfile.WithCert(e.Cert),
|
taskfile.WithCert(e.Cert),
|
||||||
taskfile.WithCertKey(e.CertKey),
|
taskfile.WithCertKey(e.CertKey),
|
||||||
)
|
)
|
||||||
var taskNotFoundError errors.TaskfileNotFoundError
|
if os.IsNotExist(err) {
|
||||||
if errors.As(err, &taskNotFoundError) {
|
return nil, errors.TaskfileNotFoundError{
|
||||||
taskNotFoundError.AskInit = true
|
URI: fsext.DefaultDir(e.Entrypoint, e.Dir),
|
||||||
return nil, taskNotFoundError
|
Walk: true,
|
||||||
|
AskInit: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -101,7 +105,8 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if e.Taskfile, err = graph.Merge(); err != nil {
|
e.Graph = graph
|
||||||
|
if e.Taskfile, err = graph.Merge(experiments.ScopedTaskfiles.Enabled()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -223,6 +228,7 @@ func (e *Executor) setupCompiler() error {
|
|||||||
UserWorkingDir: e.UserWorkingDir,
|
UserWorkingDir: e.UserWorkingDir,
|
||||||
TaskfileEnv: e.Taskfile.Env,
|
TaskfileEnv: e.Taskfile.Env,
|
||||||
TaskfileVars: e.Taskfile.Vars,
|
TaskfileVars: e.Taskfile.Vars,
|
||||||
|
Graph: e.Graph,
|
||||||
Logger: e.Logger,
|
Logger: e.Logger,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
21
task.go
21
task.go
@@ -148,20 +148,6 @@ 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,
|
||||||
@@ -173,7 +159,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prompt for missing required vars after if check (avoid prompting if task won't run)
|
// Prompt for missing required vars (just-in-time for sequential task calls)
|
||||||
prompted, err := e.promptTaskVars(t, call)
|
prompted, err := e.promptTaskVars(t, call)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -190,6 +176,11 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,21 @@ func (tfg *TaskfileGraph) Visualize(filename string) error {
|
|||||||
return draw.DOT(tfg.Graph, f)
|
return draw.DOT(tfg.Graph, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tfg *TaskfileGraph) Merge() (*Taskfile, error) {
|
// Root returns the root vertex of the graph (the entrypoint Taskfile).
|
||||||
|
func (tfg *TaskfileGraph) Root() (*TaskfileVertex, error) {
|
||||||
|
hashes, err := graph.TopologicalSort(tfg.Graph)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(hashes) == 0 {
|
||||||
|
return nil, fmt.Errorf("task: graph has no vertices")
|
||||||
|
}
|
||||||
|
return tfg.Vertex(hashes[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges all included Taskfiles into the root Taskfile.
|
||||||
|
// If skipVarsMerge is true, variables are not merged (used for scoped includes).
|
||||||
|
func (tfg *TaskfileGraph) Merge(skipVarsMerge bool) (*Taskfile, error) {
|
||||||
hashes, err := graph.TopologicalSort(tfg.Graph)
|
hashes, err := graph.TopologicalSort(tfg.Graph)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -92,6 +106,7 @@ func (tfg *TaskfileGraph) Merge() (*Taskfile, error) {
|
|||||||
if err := vertex.Taskfile.Merge(
|
if err := vertex.Taskfile.Merge(
|
||||||
includedVertex.Taskfile,
|
includedVertex.Taskfile,
|
||||||
include,
|
include,
|
||||||
|
skipVarsMerge,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v3"
|
"github.com/elliotchance/orderedmap/v3"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"iter"
|
"iter"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v3"
|
"github.com/elliotchance/orderedmap/v3"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package ast
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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,7 +242,6 @@ 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
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
@@ -36,8 +36,9 @@ type Taskfile struct {
|
|||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge merges the second Taskfile into the first
|
// Merge merges the second Taskfile into the first.
|
||||||
func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
|
// If skipVarsMerge is true, variables are not merged (used for scoped includes).
|
||||||
|
func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include, skipVarsMerge bool) error {
|
||||||
if !t1.Version.Equal(t2.Version) {
|
if !t1.Version.Equal(t2.Version) {
|
||||||
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
|
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
|
||||||
}
|
}
|
||||||
@@ -67,8 +68,11 @@ func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t1.Vars.Merge(t2.Vars, include)
|
// Only merge vars if not using scoped includes, or if flattening
|
||||||
t1.Env.Merge(t2.Env, include)
|
if !skipVarsMerge || include.Flatten {
|
||||||
|
t1.Vars.Merge(t2.Vars, include)
|
||||||
|
t1.Env.Merge(t2.Env, include)
|
||||||
|
}
|
||||||
return t1.Tasks.Merge(t2.Tasks, include, t1.Vars)
|
return t1.Tasks.Merge(t2.Tasks, include, t1.Vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v3"
|
"github.com/elliotchance/orderedmap/v3"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v3"
|
"github.com/elliotchance/orderedmap/v3"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"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"
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ 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) {
|
||||||
if entrypoint == "" {
|
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: false}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -128,19 +127,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 cache FIRST - if already cloned, no network needed, timeout irrelevant
|
// check if repo is already cached (under the lock)
|
||||||
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{
|
||||||
@@ -192,8 +191,8 @@ func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
|||||||
return entrypoint, nil
|
return entrypoint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, _ := path.Split(node.path)
|
dir, _ := filepath.Split(node.path)
|
||||||
resolvedEntrypoint := fmt.Sprintf("%s//%s", node.url, path.Join(dir, entrypoint))
|
resolvedEntrypoint := fmt.Sprintf("%s//%s", node.url, filepath.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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dominikbraun/graph"
|
"github.com/dominikbraun/graph"
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ 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"`
|
||||||
@@ -64,7 +63,6 @@ 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)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package taskrc
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v4"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/taskrc/ast"
|
"github.com/go-task/task/v3/taskrc/ast"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ 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"
|
||||||
)
|
)
|
||||||
@@ -63,9 +62,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
18
testdata/if/Taskfile.yml
vendored
18
testdata/if/Taskfile.yml
vendored
@@ -158,21 +158,3 @@ 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"
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
task: dynamic variable: "echo \"false\"" result: "false"
|
|
||||||
task: if condition not met - skipped: "task-if-dynamic-false"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
dynamic feature enabled
|
|
||||||
57
testdata/scoped_taskfiles/Taskfile.yml
vendored
Normal file
57
testdata/scoped_taskfiles/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
env:
|
||||||
|
ROOT_ENV: env_from_root
|
||||||
|
SHARED_ENV: shared_from_root
|
||||||
|
|
||||||
|
vars:
|
||||||
|
ROOT_VAR: from_root
|
||||||
|
|
||||||
|
includes:
|
||||||
|
a: ./inc_a
|
||||||
|
b: ./inc_b
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
desc: Test scoped includes - vars should be isolated
|
||||||
|
cmds:
|
||||||
|
- task: a:print
|
||||||
|
- task: b:print
|
||||||
|
|
||||||
|
print-root-var:
|
||||||
|
desc: Print ROOT_VAR from root
|
||||||
|
cmds:
|
||||||
|
- echo "ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
|
||||||
|
print-env:
|
||||||
|
desc: Print env vars using {{.env.XXX}} syntax
|
||||||
|
cmds:
|
||||||
|
- echo "ROOT_ENV={{.env.ROOT_ENV}}"
|
||||||
|
- echo "SHARED_ENV={{.env.SHARED_ENV}}"
|
||||||
|
- echo "PATH_EXISTS={{if .env.PATH}}yes{{else}}no{{end}}"
|
||||||
|
|
||||||
|
test-env-separation:
|
||||||
|
desc: Test that env is NOT at root level in scoped mode
|
||||||
|
cmds:
|
||||||
|
# In scoped mode, {{.ROOT_ENV}} should be empty (env not at root)
|
||||||
|
# In legacy mode, {{.ROOT_ENV}} would have the value
|
||||||
|
- echo "ROOT_ENV_AT_ROOT={{.ROOT_ENV}}"
|
||||||
|
|
||||||
|
prout:
|
||||||
|
vars:
|
||||||
|
LOL: prout_from_root
|
||||||
|
cmds:
|
||||||
|
- echo "{{.LOL}}"
|
||||||
|
|
||||||
|
call-with-vars:
|
||||||
|
desc: Test calling a task with vars override
|
||||||
|
cmds:
|
||||||
|
- task: print-name
|
||||||
|
vars:
|
||||||
|
NAME: from_caller
|
||||||
|
|
||||||
|
print-name:
|
||||||
|
vars:
|
||||||
|
NAME: default_name
|
||||||
|
cmds:
|
||||||
|
- echo "NAME={{.NAME}}"
|
||||||
38
testdata/scoped_taskfiles/inc_a/Taskfile.yml
vendored
Normal file
38
testdata/scoped_taskfiles/inc_a/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
env:
|
||||||
|
INC_A_ENV: env_from_a
|
||||||
|
SHARED_ENV: shared_from_a
|
||||||
|
|
||||||
|
vars:
|
||||||
|
VAR: value_from_a
|
||||||
|
UNIQUE_A: only_in_a
|
||||||
|
|
||||||
|
includes:
|
||||||
|
nested: ./nested
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print:
|
||||||
|
desc: Print vars from include A
|
||||||
|
cmds:
|
||||||
|
- echo "A:UNIQUE_A={{.UNIQUE_A}}"
|
||||||
|
- echo "A:ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
|
||||||
|
try-access-b:
|
||||||
|
desc: Try to access B's unique var (should fail in scoped mode)
|
||||||
|
cmds:
|
||||||
|
- echo "A:UNIQUE_B={{.UNIQUE_B}}"
|
||||||
|
|
||||||
|
print-env:
|
||||||
|
desc: Print env vars from include A
|
||||||
|
cmds:
|
||||||
|
- echo "A:INC_A_ENV={{.env.INC_A_ENV}}"
|
||||||
|
- echo "A:ROOT_ENV={{.env.ROOT_ENV}}"
|
||||||
|
- echo "A:SHARED_ENV={{.env.SHARED_ENV}}"
|
||||||
|
|
||||||
|
test-env-in-var:
|
||||||
|
desc: Test using env in a var template
|
||||||
|
vars:
|
||||||
|
COMPOSED: "env={{.env.ROOT_ENV}}"
|
||||||
|
cmds:
|
||||||
|
- echo "{{.COMPOSED}}"
|
||||||
22
testdata/scoped_taskfiles/inc_a/nested/Taskfile.yml
vendored
Normal file
22
testdata/scoped_taskfiles/inc_a/nested/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
env:
|
||||||
|
NESTED_ENV: env_from_nested
|
||||||
|
|
||||||
|
vars:
|
||||||
|
NESTED_VAR: from_nested
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print:
|
||||||
|
desc: Print vars from nested include (3 levels deep)
|
||||||
|
cmds:
|
||||||
|
- echo "NESTED:ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
- echo "NESTED:UNIQUE_A={{.UNIQUE_A}}"
|
||||||
|
- echo "NESTED:NESTED_VAR={{.NESTED_VAR}}"
|
||||||
|
- echo "NESTED:NESTED_ENV={{.env.NESTED_ENV}}"
|
||||||
|
- echo "NESTED:ROOT_ENV={{.env.ROOT_ENV}}"
|
||||||
|
|
||||||
|
try-access-b:
|
||||||
|
desc: Try to access B's unique var (should fail - sibling isolation)
|
||||||
|
cmds:
|
||||||
|
- echo "NESTED:UNIQUE_B={{.UNIQUE_B}}"
|
||||||
23
testdata/scoped_taskfiles/inc_b/Taskfile.yml
vendored
Normal file
23
testdata/scoped_taskfiles/inc_b/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
env:
|
||||||
|
INC_B_ENV: env_from_b
|
||||||
|
SHARED_ENV: shared_from_b
|
||||||
|
|
||||||
|
vars:
|
||||||
|
VAR: value_from_b
|
||||||
|
UNIQUE_B: only_in_b
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
print:
|
||||||
|
desc: Print vars from include B
|
||||||
|
cmds:
|
||||||
|
- echo "B:UNIQUE_B={{.UNIQUE_B}}"
|
||||||
|
- echo "B:ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
|
||||||
|
print-env:
|
||||||
|
desc: Print env vars from include B
|
||||||
|
cmds:
|
||||||
|
- echo "B:INC_B_ENV={{.env.INC_B_ENV}}"
|
||||||
|
- echo "B:ROOT_ENV={{.env.ROOT_ENV}}"
|
||||||
|
- echo "B:SHARED_ENV={{.env.SHARED_ENV}}"
|
||||||
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-legacy-cross-include.golden
vendored
Normal file
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-legacy-cross-include.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A:UNIQUE_B=only_in_b
|
||||||
4
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-legacy-default.golden
vendored
Normal file
4
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-legacy-default.golden
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
A:UNIQUE_A=only_in_a
|
||||||
|
A:ROOT_VAR=from_root
|
||||||
|
B:UNIQUE_B=only_in_b
|
||||||
|
B:ROOT_VAR=from_root
|
||||||
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-call-vars.golden
vendored
Normal file
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-call-vars.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
NAME=from_caller
|
||||||
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-cross-include.golden
vendored
Normal file
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-cross-include.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A:UNIQUE_B=
|
||||||
4
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-default.golden
vendored
Normal file
4
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-default.golden
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
A:UNIQUE_A=only_in_a
|
||||||
|
A:ROOT_VAR=from_root
|
||||||
|
B:UNIQUE_B=only_in_b
|
||||||
|
B:ROOT_VAR=from_root
|
||||||
3
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-env-namespace.golden
vendored
Normal file
3
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-env-namespace.golden
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ROOT_ENV=env_from_root
|
||||||
|
SHARED_ENV=shared_from_root
|
||||||
|
PATH_EXISTS=yes
|
||||||
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-env-separation.golden
vendored
Normal file
1
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-env-separation.golden
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ROOT_ENV_AT_ROOT=
|
||||||
3
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-include-env.golden
vendored
Normal file
3
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-include-env.golden
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
A:INC_A_ENV=env_from_a
|
||||||
|
A:ROOT_ENV=env_from_root
|
||||||
|
A:SHARED_ENV=shared_from_a
|
||||||
2
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-inheritance-a.golden
vendored
Normal file
2
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-inheritance-a.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
A:UNIQUE_A=only_in_a
|
||||||
|
A:ROOT_VAR=from_root
|
||||||
2
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-isolation-b.golden
vendored
Normal file
2
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-isolation-b.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
B:UNIQUE_B=only_in_b
|
||||||
|
B:ROOT_VAR=from_root
|
||||||
5
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-nested.golden
vendored
Normal file
5
testdata/scoped_taskfiles/testdata/TestScopedTaskfiles-scoped-nested.golden
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
NESTED:ROOT_VAR=from_root
|
||||||
|
NESTED:UNIQUE_A=only_in_a
|
||||||
|
NESTED:NESTED_VAR=from_nested
|
||||||
|
NESTED:NESTED_ENV=env_from_nested
|
||||||
|
NESTED:ROOT_ENV=env_from_root
|
||||||
14
testdata/var_references/Taskfile.yml
vendored
14
testdata/var_references/Taskfile.yml
vendored
@@ -2,9 +2,6 @@ version: '3'
|
|||||||
|
|
||||||
vars:
|
vars:
|
||||||
GLOBAL_VAR: [1, 2, 2, 2, 3, 3, 4, 5]
|
GLOBAL_VAR: [1, 2, 2, 2, 3, 3, 4, 5]
|
||||||
GLOBAL_FOO:
|
|
||||||
ref: .GLOBAL_BAR
|
|
||||||
GLOBAL_BAR: bar
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
default:
|
default:
|
||||||
@@ -12,7 +9,6 @@ tasks:
|
|||||||
- task: ref-dep
|
- task: ref-dep
|
||||||
- task: ref-resolver
|
- task: ref-resolver
|
||||||
- task: ref-resolver-sh
|
- task: ref-resolver-sh
|
||||||
- task: ref-global
|
|
||||||
|
|
||||||
ref-cmd:
|
ref-cmd:
|
||||||
vars:
|
vars:
|
||||||
@@ -76,13 +72,3 @@ tasks:
|
|||||||
{{- else}} and {{$child.name -}}
|
{{- else}} and {{$child.name -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}"
|
{{- end -}}"
|
||||||
|
|
||||||
ref-global:
|
|
||||||
vars:
|
|
||||||
TASK_FUBAR:
|
|
||||||
ref: .GLOBAL_FOO
|
|
||||||
cmds:
|
|
||||||
- echo "GLOBAL_FOO={{.GLOBAL_FOO}}"
|
|
||||||
- echo "GLOBAL_BAR={{.GLOBAL_BAR}}"
|
|
||||||
- echo "TASK_FUBAR={{.TASK_FUBAR}}"
|
|
||||||
silent: true
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
GLOBAL_FOO=bar
|
|
||||||
GLOBAL_BAR=bar
|
|
||||||
TASK_FUBAR=bar
|
|
||||||
@@ -90,16 +90,12 @@ 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 isHome = pageData.relativePath === 'index.md';
|
const pageTitle = pageData.frontmatter.title || pageData.title || taskName
|
||||||
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 }])
|
head.push(['meta', { property: 'og:title', content: `${pageTitle} | Task` }])
|
||||||
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 }])
|
head.push(['meta', { name: 'twitter:title', content: `${pageTitle} | Task` }])
|
||||||
head.push(['meta', { name: 'twitter:description', content: pageDescription }])
|
head.push(['meta', { name: 'twitter:description', content: pageDescription }])
|
||||||
|
|
||||||
// Noindex pour 404
|
// Noindex pour 404
|
||||||
@@ -306,6 +302,10 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
text: 'Remote Taskfiles (#1317)',
|
text: 'Remote Taskfiles (#1317)',
|
||||||
link: '/docs/experiments/remote-taskfiles'
|
link: '/docs/experiments/remote-taskfiles'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Scoped Taskfiles',
|
||||||
|
link: '/docs/experiments/scoped-taskfiles'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -374,11 +374,6 @@ 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>'
|
||||||
|
|||||||
@@ -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/og_image.png';
|
export const ogImage = 'https://taskfile.dev/img/logo.png';
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ 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/',
|
||||||
|
|||||||
@@ -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.8.0",
|
"vitepress-plugin-tabs": "^0.7.1",
|
||||||
"vitepress-plugin-llms": "^1.9.1",
|
"vitepress-plugin-llms": "^1.9.1",
|
||||||
"vue": "^3.5.18"
|
"vue": "^3.5.18"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017"
|
"packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316"
|
||||||
}
|
}
|
||||||
|
|||||||
2501
website/pnpm-lock.yaml
generated
2501
website/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@ 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
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ 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 Variable Prompt
|
# New `if:` control and interactivity support
|
||||||
|
|
||||||
<AuthorCard :author="$frontmatter.author" />
|
<AuthorCard :author="$frontmatter.author" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
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
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ description:
|
|||||||
author: pd93
|
author: pd93
|
||||||
date: 2024-05-09
|
date: 2024-05-09
|
||||||
outline: deep
|
outline: deep
|
||||||
editLink: false
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Introducing Experiments
|
# Introducing Experiments
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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
|
||||||
|
|||||||
@@ -1,43 +1,12 @@
|
|||||||
---
|
---
|
||||||
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
|
||||||
|
|||||||
@@ -355,8 +355,6 @@ 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:
|
||||||
@@ -368,8 +366,6 @@ 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:
|
||||||
@@ -382,8 +378,6 @@ 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:
|
||||||
@@ -397,8 +391,6 @@ 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:
|
||||||
@@ -412,7 +404,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_CACHE_DIR`
|
- **Environment variable**: `TASK_REMOTE_DIR` (lowest priority)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
remote:
|
remote:
|
||||||
@@ -426,7 +418,6 @@ 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:
|
||||||
|
|||||||
281
website/src/docs/experiments/scoped-taskfiles.md
Normal file
281
website/src/docs/experiments/scoped-taskfiles.md
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
---
|
||||||
|
title: 'Scoped Taskfiles (#2035)'
|
||||||
|
description:
|
||||||
|
Experiment for variable isolation and env namespace in included Taskfiles
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# Scoped Taskfiles (#2035)
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
|
||||||
|
All experimental features are subject to breaking changes and/or removal _at any
|
||||||
|
time_. We strongly recommend that you do not use these features in a production
|
||||||
|
environment. They are intended for testing and feedback only.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger
|
||||||
|
|
||||||
|
This experiment breaks the following functionality:
|
||||||
|
|
||||||
|
- **Environment variables are no longer available at root level in templates**
|
||||||
|
- Before: <span v-pre>`{{.PATH}}`</span>, <span v-pre>`{{.MY_ENV}}`</span>
|
||||||
|
- After: <span v-pre>`{{.env.PATH}}`</span>,
|
||||||
|
<span v-pre>`{{.env.MY_ENV}}`</span>
|
||||||
|
- **Variables from sibling includes are no longer visible**
|
||||||
|
- Include A cannot access variables defined in Include B
|
||||||
|
- Each include only sees: root vars + its own vars + parent vars
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: info
|
||||||
|
|
||||||
|
To enable this experiment, set the environment variable:
|
||||||
|
`TASK_X_SCOPED_TASKFILES=1`. Check out
|
||||||
|
[our guide to enabling experiments](./index.md#enabling-experiments) for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
This experiment introduces two major changes to how variables work in Task:
|
||||||
|
|
||||||
|
1. **Environment namespace**: Environment variables (both OS and Taskfile `env:`
|
||||||
|
sections) are moved to a dedicated <span v-pre>`{{.env.XXX}}`</span>
|
||||||
|
namespace, separating them from regular variables
|
||||||
|
2. **Variable scoping**: Variables defined in included Taskfiles are isolated -
|
||||||
|
sibling includes cannot see each other's variables
|
||||||
|
|
||||||
|
## Environment Namespace
|
||||||
|
|
||||||
|
With this experiment enabled, environment variables are no longer mixed with
|
||||||
|
regular variables at the template root level. Instead, they are accessible
|
||||||
|
through the <span v-pre>`{{.env.XXX}}`</span> namespace.
|
||||||
|
|
||||||
|
### Comparison Table
|
||||||
|
|
||||||
|
| Template | Legacy | SCOPED_TASKFILES |
|
||||||
|
| ----------------------------------------------- | ------ | ------------------------- |
|
||||||
|
| <span v-pre>`{{.MY_VAR}}`</span> (from `vars:`) | Works | Works |
|
||||||
|
| <span v-pre>`{{.MY_ENV}}`</span> (from `env:`) | Works | `<no value>` |
|
||||||
|
| <span v-pre>`{{.env.MY_ENV}}`</span> | - | Works |
|
||||||
|
| <span v-pre>`{{.PATH}}`</span> (OS) | Works | `<no value>` |
|
||||||
|
| <span v-pre>`{{.env.PATH}}`</span> (OS) | - | Works |
|
||||||
|
| <span v-pre>`{{.TASK}}`</span> (special) | Works | Works (stays at root) |
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
env:
|
||||||
|
DB_HOST: localhost
|
||||||
|
|
||||||
|
vars:
|
||||||
|
DB_NAME: mydb
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
show:
|
||||||
|
cmds:
|
||||||
|
# Access Taskfile env: section
|
||||||
|
- echo "Host: {{.env.DB_HOST}}"
|
||||||
|
|
||||||
|
# Access regular vars (unchanged)
|
||||||
|
- echo "Name: {{.DB_NAME}}"
|
||||||
|
|
||||||
|
# Access OS environment variables
|
||||||
|
- echo "Path: {{.env.PATH}}"
|
||||||
|
|
||||||
|
# Special variables stay at root level
|
||||||
|
- echo "Task: {{.TASK}}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Variable Scoping
|
||||||
|
|
||||||
|
Variables defined in included Taskfiles are now isolated from each other.
|
||||||
|
Sibling includes cannot access each other's variables, but child includes can
|
||||||
|
still inherit variables from their parent.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```yaml [Taskfile.yml]
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
ROOT_VAR: from_root
|
||||||
|
|
||||||
|
includes:
|
||||||
|
api: ./api
|
||||||
|
web: ./web
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml [api/Taskfile.yml]
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
API_VAR: from_api
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
show:
|
||||||
|
cmds:
|
||||||
|
# Inherited from root - works
|
||||||
|
- echo "ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
|
||||||
|
# Own variable - works
|
||||||
|
- echo "API_VAR={{.API_VAR}}"
|
||||||
|
|
||||||
|
# From sibling include - NOT visible
|
||||||
|
- echo "WEB_VAR={{.WEB_VAR}}"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml [web/Taskfile.yml]
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
WEB_VAR: from_web
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
show:
|
||||||
|
cmds:
|
||||||
|
# Inherited from root - works
|
||||||
|
- echo "ROOT_VAR={{.ROOT_VAR}}"
|
||||||
|
|
||||||
|
# Own variable - works
|
||||||
|
- echo "WEB_VAR={{.WEB_VAR}}"
|
||||||
|
|
||||||
|
# From sibling include - NOT visible
|
||||||
|
- echo "API_VAR={{.API_VAR}}"
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Variable Priority
|
||||||
|
|
||||||
|
With this experiment, variables follow a clear priority order (lowest to
|
||||||
|
highest):
|
||||||
|
|
||||||
|
| Priority | Source | Description |
|
||||||
|
| -------- | ------------------------ | ---------------------------------------- |
|
||||||
|
| 1 | Root Taskfile vars | `vars:` in the root Taskfile |
|
||||||
|
| 2 | Include Taskfile vars | `vars:` in the included Taskfile |
|
||||||
|
| 3 | Include passthrough vars | `includes: name: vars:` from parent |
|
||||||
|
| 4 | Task vars | `tasks: name: vars:` in the task |
|
||||||
|
| 5 | Call vars | `task: name` with `vars:` when calling |
|
||||||
|
| 6 | CLI vars | `task foo VAR=value` on command line |
|
||||||
|
|
||||||
|
### Example: Call vars override task vars
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
greet:
|
||||||
|
vars:
|
||||||
|
NAME: default
|
||||||
|
cmds:
|
||||||
|
- echo "Hello {{.NAME}}"
|
||||||
|
|
||||||
|
caller:
|
||||||
|
cmds:
|
||||||
|
- task: greet
|
||||||
|
vars:
|
||||||
|
NAME: from_caller
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Direct call uses task default
|
||||||
|
task greet
|
||||||
|
# Output: Hello default
|
||||||
|
|
||||||
|
# Call vars override task vars
|
||||||
|
task caller
|
||||||
|
# Output: Hello from_caller
|
||||||
|
|
||||||
|
# CLI vars override everything
|
||||||
|
task greet NAME=cli
|
||||||
|
# Output: Hello cli
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
To migrate your Taskfiles to use this experiment:
|
||||||
|
|
||||||
|
1. **Update environment variable references** in your templates:
|
||||||
|
|
||||||
|
- <span v-pre>`{{.PATH}}`</span> becomes
|
||||||
|
<span v-pre>`{{.env.PATH}}`</span>
|
||||||
|
- <span v-pre>`{{.HOME}}`</span> becomes
|
||||||
|
<span v-pre>`{{.env.HOME}}`</span>
|
||||||
|
- <span v-pre>`{{.MY_TASKFILE_ENV}}`</span> becomes
|
||||||
|
<span v-pre>`{{.env.MY_TASKFILE_ENV}}`</span>
|
||||||
|
|
||||||
|
2. **Variables in `vars:` sections remain unchanged**:
|
||||||
|
|
||||||
|
- <span v-pre>`{{.MY_VAR}}`</span> still works the same way
|
||||||
|
|
||||||
|
3. **Special variables stay at root level**:
|
||||||
|
|
||||||
|
- <span v-pre>`{{.TASK}}`</span>, <span v-pre>`{{.ROOT_DIR}}`</span>,
|
||||||
|
<span v-pre>`{{.TASKFILE}}`</span>, <span v-pre>`{{.TASKFILE_DIR}}`</span>,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
4. **Review cross-include variable dependencies**:
|
||||||
|
- If your included Taskfiles rely on variables from sibling includes, you'll
|
||||||
|
need to either move those variables to the root Taskfile or pass them
|
||||||
|
explicitly via the `vars:` attribute in the `includes:` section.
|
||||||
|
|
||||||
|
5. **Use `flatten: true` for gradual migration**:
|
||||||
|
- If an include needs the legacy behavior (access to sibling variables), you
|
||||||
|
can use `flatten: true` on that include as an escape hatch.
|
||||||
|
|
||||||
|
## Using `flatten: true`
|
||||||
|
|
||||||
|
The `flatten: true` option on includes bypasses scoping for that specific
|
||||||
|
include. When an include has `flatten: true`:
|
||||||
|
|
||||||
|
- Its variables are merged globally (legacy behavior)
|
||||||
|
- It can access variables from sibling includes
|
||||||
|
- Sibling includes can access its variables
|
||||||
|
|
||||||
|
This is useful for gradual migration or when you have includes that genuinely
|
||||||
|
need to share variables.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
ROOT_VAR: from_root
|
||||||
|
|
||||||
|
includes:
|
||||||
|
# Scoped include - isolated from siblings
|
||||||
|
api:
|
||||||
|
taskfile: ./api
|
||||||
|
|
||||||
|
# Flattened include - uses legacy merge behavior
|
||||||
|
shared:
|
||||||
|
taskfile: ./shared
|
||||||
|
flatten: true
|
||||||
|
|
||||||
|
# Another scoped include
|
||||||
|
web:
|
||||||
|
taskfile: ./web
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example:
|
||||||
|
|
||||||
|
- `api` and `web` are isolated from each other (cannot see each other's vars)
|
||||||
|
- `shared` uses legacy behavior: its vars are merged globally
|
||||||
|
- Both `api` and `web` can access variables from `shared`
|
||||||
|
- `shared` can access variables from `api` and `web`
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
|
||||||
|
Use `flatten: true` sparingly. The goal of scoped taskfiles is to improve
|
||||||
|
isolation and predictability. Flattening should be a temporary measure during
|
||||||
|
migration or for utility includes that genuinely need global scope.
|
||||||
|
|
||||||
|
:::
|
||||||
@@ -45,17 +45,6 @@ Then you can install Task with:
|
|||||||
apt install task
|
apt install task
|
||||||
```
|
```
|
||||||
|
|
||||||
:::info Package Repository Hosting
|
|
||||||
|
|
||||||
[](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)   {#homebrew}
|
### [Homebrew](https://brew.sh)   {#homebrew}
|
||||||
|
|
||||||
Task is available via our official Homebrew tap
|
Task is available via our official Homebrew tap
|
||||||
|
|||||||
@@ -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 in
|
The code for this project can be found
|
||||||
[our GitHub repository](https://github.com/go-task/vscode-task). To use this
|
[here](https://github.com/go-task/vscode-task). To use this extension, you must
|
||||||
extension, you must have Task v3.45.3+ installed on your system.
|
have Task v3.23.0+ installed on your system.
|
||||||
|
|
||||||
This extension provides the following features (and more):
|
This extension provides the following features (and more):
|
||||||
|
|
||||||
@@ -30,19 +30,6 @@ To get autocompletion and validation for your Taskfile, see the
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 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).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
If you receive a warning like the one above, you will need to update your
|
|
||||||
settings to use the new `taskfile` namespace instead:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Schema
|
## Schema
|
||||||
|
|
||||||
This was initially created by @KROSF in
|
This was initially created by @KROSF in
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
- [Configuration files](./config.md)
|
|
||||||
- [Environment variables](./environment.md)
|
- [Environment variables](./environment.md)
|
||||||
|
- [Configuration files](./config.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,14 +72,6 @@ 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
|
||||||
@@ -104,9 +96,6 @@ 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
|
||||||
```
|
```
|
||||||
@@ -115,20 +104,13 @@ 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
|
Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name.
|
||||||
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
|
||||||
@@ -142,9 +124,6 @@ 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
|
||||||
```
|
```
|
||||||
@@ -161,8 +140,6 @@ 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
|
||||||
```
|
```
|
||||||
@@ -179,9 +156,6 @@ 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
|
||||||
```
|
```
|
||||||
@@ -258,9 +232,6 @@ 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
|
||||||
@@ -295,12 +266,7 @@ task --list --json
|
|||||||
|
|
||||||
#### `--sort <mode>`
|
#### `--sort <mode>`
|
||||||
|
|
||||||
Change task listing order. Available modes:
|
Change task listing order. Available modes: `default`, `alphanumeric`, `none`.
|
||||||
|
|
||||||
- `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
|
||||||
@@ -331,8 +297,6 @@ 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
|
||||||
```
|
```
|
||||||
@@ -342,11 +306,9 @@ 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 skips
|
Task automatically detects non-TTY environments (like CI pipelines) and
|
||||||
prompts. This flag can also be set in `.taskrc.yml` to enable prompts by
|
skips prompts. This flag can also be set in `.taskrc.yml` to enable prompts
|
||||||
default.
|
by default.
|
||||||
|
|
||||||
- **Environment variable**: [`TASK_INTERACTIVE`](./environment.md#task-interactive)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
task deploy --interactive
|
task deploy --interactive
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
- _Configuration files_
|
|
||||||
- [Environment variables](./environment.md)
|
- [Environment variables](./environment.md)
|
||||||
|
- _Configuration files_
|
||||||
- [Command-line flags](./cli.md)
|
- [Command-line flags](./cli.md)
|
||||||
|
|
||||||
In this document, we will look at the first of the three options, configuration
|
In this document, we will look at the second of the three options, configuration
|
||||||
files.
|
files.
|
||||||
|
|
||||||
## File Precedence
|
## File Precedence
|
||||||
@@ -86,31 +86,17 @@ 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
|
||||||
@@ -122,7 +108,6 @@ 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
|
||||||
@@ -134,7 +119,6 @@ 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
|
||||||
@@ -145,8 +129,7 @@ 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
|
||||||
@@ -173,7 +156,6 @@ 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
|
||||||
|
|||||||
@@ -9,78 +9,16 @@ 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:
|
||||||
|
|
||||||
- [Configuration files](./config.md)
|
|
||||||
- _Environment variables_
|
- _Environment variables_
|
||||||
|
- [Configuration files](./config.md)
|
||||||
- [Command-line flags](./cli.md)
|
- [Command-line flags](./cli.md)
|
||||||
|
|
||||||
In this document, we will look at the second of the three options, environment
|
In this document, we will look at the first 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
|
||||||
@@ -96,6 +34,18 @@ 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.
|
||||||
|
|||||||
@@ -637,7 +637,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
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
title: Donate
|
title: Donate
|
||||||
layout: doc
|
layout: doc
|
||||||
outline: false
|
outline: false
|
||||||
editLink: false
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# :raised_hands: Support Task
|
# :raised_hands: Support Task
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
title: "Task: The Modern Task Runner"
|
|
||||||
layout: home
|
layout: home
|
||||||
hero:
|
hero:
|
||||||
name: Task
|
name: Task
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB |
@@ -1,45 +0,0 @@
|
|||||||
<?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>
|
|
||||||
|
Before Width: | Height: | Size: 7.4 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user