diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9ccafebf..5e93fed6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,19 +16,19 @@ jobs: name: Lint strategy: matrix: - go-version: [1.25.x, 1.26.x] + go-version: [1.25.10, 1.26.x] runs-on: ubuntu-latest steps: - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: ${{matrix.go-version}} - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: golangci-lint - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 + uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9.2.1 with: - version: v2.11.4 + version: v2.12.2 lint-jsonschema: runs-on: ubuntu-latest @@ -37,7 +37,7 @@ jobs: with: python-version: 3.14 - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: install check-jsonschema run: python -m pip install 'check-jsonschema==0.27.3' diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 81632315..ab9cbfa1 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -13,7 +13,7 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'needs-build') runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -21,7 +21,7 @@ jobs: with: go-version: "1.26.x" cache: true - - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7 + - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7 with: version: "~> v2" args: release --snapshot --clean --config .goreleaser-pr.yml diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 460e94f7..6b92e9dd 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 @@ -23,7 +23,7 @@ jobs: go-version: 1.26.x - name: Run GoReleaser - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7 + uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7 with: distribution: goreleaser-pro version: latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3062d06e..68f14401 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 @@ -23,7 +23,7 @@ jobs: with: go-version: 1.26.x - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" @@ -32,22 +32,23 @@ jobs: run: npm install -g npm@latest - name: Install Task - uses: go-task/setup-task@3be4020d41929789a01026e0e427a4321ce0ad44 # v2 + uses: go-task/setup-task@01a4adf9db2d14c1de7a560f09170b6e0df736aa # v2 - name: Install pnpm - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 with: package_json_file: "website/package.json" run_install: "true" - name: Run GoReleaser - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7 + uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7 with: distribution: goreleaser-pro version: latest args: release --clean --draft env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + GH_GORELEASER_TOKEN: ${{secrets.GH_GORELEASER_TOKEN}} GORELEASER_KEY: ${{secrets.GORELEASER_KEY}} CLOUDSMITH_TOKEN: ${{secrets.CLOUDSMITH_TOKEN}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c21b0874..4a9cf7ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,12 +17,12 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.25.x, 1.26.x] + go-version: [1.25.10, 1.26.x] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{matrix.platform}} steps: - name: Check out code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up Go ${{matrix.go-version}} uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 diff --git a/.golangci.yml b/.golangci.yml index ffe778c6..f8473757 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,33 +2,16 @@ version: "2" formatters: enable: - - gofmt - gofumpt - goimports - gci settings: - gofmt: - simplify: true - rewrite-rules: - - pattern: interface{} - replacement: any - gofumpt: - module-path: github.com/go-task/task/v3 - goimports: - local-prefixes: - - github.com/go-task gci: sections: - standard - default - prefix(github.com/go-task) - localmodule - exclusions: - generated: lax - paths: - - third_party$ - - builtin$ - - examples$ linters: enable: @@ -36,6 +19,7 @@ linters: - gosec - mirror - misspell + - modernize - noctx - paralleltest - thelper @@ -56,13 +40,8 @@ linters: - pkg: errors desc: Use github.com/go-task/task/v3/errors instead exclusions: - generated: lax presets: - comments - common-false-positives - legacy - std-error-handling - paths: - - third_party$ - - builtin$ - - examples$ diff --git a/.goreleaser.yml b/.goreleaser.yml index e2401b6e..8cfb3928 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -76,7 +76,7 @@ nfpms: - src: completion/bash/task.bash dst: /etc/bash_completion.d/task - src: completion/fish/task.fish - dst: /usr/share/fish/completions/task.fish + dst: /usr/share/fish/vendor_completions.d/task.fish - src: completion/zsh/_task dst: /usr/local/share/zsh/site-functions/_task @@ -89,7 +89,7 @@ brews: repository: owner: go-task name: homebrew-tap - token: "{{secrets.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user + token: "{{.Env.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user test: system "#{bin}/task", "--help" install: |- bin.install "task" @@ -131,7 +131,7 @@ winget: owner: go-task name: winget-pkgs branch: 'task-{{.Version}}' - token: "{{secrets.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user + token: "{{.Env.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user pull_request: enabled: true draft: false diff --git a/CHANGELOG.md b/CHANGELOG.md index b401c787..d0b03c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## Unreleased + +- Fixed --interactive prompts for required vars sometimes appearing in a random + order. Prompts now follow the order the vars are declared in the Taskfile. + (#2871 by @caproven) +- Fixed Fish completions not being picked up correctly by installing them to + Fish's `vendor_completions.d` directory instead of `completions` (#2850, #2859 + by @Legimity). +- PowerShell completions now work with aliases of the `task` command, not just + the `task` binary itself (#2852 by @kojiishi). +- Fixed task names containing certain characters (e.g. `\`, `_`, `^`) leaking + into checksum/timestamp filenames, breaking `sources:`/`generates:` + up-to-date detection (#2886 by @s3onghyun). +- Fixed `for: matrix:` loops using `ref:` rows producing wrong values when the + same task was run concurrently (e.g. by parallel `deps`) with different vars + (#2890, #2894 by @amitmishra11). + +## v3.51.1 - 2026-05-16 + +- A significant performance boost was achieved for large Taskfiles (monorepos) + by skipping templating altogether when the string is static (#2820 by @romnn). +- Added `absPath` template function that resolves a path to its absolute form, + cleaning `..` and `.` components (#2681, #2788 by @mateenanjum). +- Added `joinEnv` function to join paths based on your oprating system: `;` for + Windows and `:` elsewhere, and `joinUrl` to join URL paths. Also, added two + new special variables: `FILE_PATH_SEPARATOR` which returns `\` on Windows and + `/` elsewhere, and `PATH_LIST_SEPARATOR` which returns `;` on Windows and `:` + elsewhere (#2406, #2408 by @solvingj). +- Update the shell interpreter with a regression fix (#2812, #2832 by + @andreynering). +- Fix potential panic with the shell interpreter (#2810 by @trulede). + ## v3.50.0 - 2026-04-13 - Added `enum.ref` support in `requires`: enum constraints can now reference @@ -11,13 +43,13 @@ - Fixed watch mode ignoring SIGHUP signal, causing the watcher to exit instead of restarting (#2764, #2642). - Fixed a long time bug where the task wouldn't re-run as it should when using - `method: timestamp` and the files listed on `generates:` were deleted. - This makes `method: timestamp` behaves the same as `method: checksum` - (#1230, #2716 by @drichardson). + `method: timestamp` and the files listed on `generates:` were deleted. This + makes `method: timestamp` behaves the same as `method: checksum` (#1230, #2716 + by @drichardson). ## v3.49.1 - 2026-03-08 -* Reverted #2632 for now, which caused some regressions. That change will be +- Reverted #2632 for now, which caused some regressions. That change will be reworked (#2720, #2722, #2723). ## v3.49.0 - 2026-03-07 diff --git a/compiler.go b/compiler.go index 8920c818..f80e79af 100644 --- a/compiler.go +++ b/compiler.go @@ -202,11 +202,13 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, e // across platforms. This prevents issues with backslashes being interpreted // as escape sequences when paths are used in shell commands on Windows. allVars := map[string]string{ - "TASK_EXE": filepath.ToSlash(os.Args[0]), - "ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)), - "ROOT_DIR": filepath.ToSlash(c.Dir), - "USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir), - "TASK_VERSION": version.GetVersion(), + "TASK_EXE": filepath.ToSlash(os.Args[0]), + "ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)), + "ROOT_DIR": filepath.ToSlash(c.Dir), + "USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir), + "TASK_VERSION": version.GetVersion(), + "PATH_LIST_SEPARATOR": string(os.PathListSeparator), + "FILE_PATH_SEPARATOR": string(os.PathSeparator), } if t != nil { allVars["TASK"] = t.Task diff --git a/completion/ps/task.ps1 b/completion/ps/task.ps1 index 05cadb58..71b58b88 100644 --- a/completion/ps/task.ps1 +++ b/completion/ps/task.ps1 @@ -1,6 +1,8 @@ using namespace System.Management.Automation -Register-ArgumentCompleter -CommandName task -ScriptBlock { +$cmdNames = @('task') + (Get-Alias -Definition task,task.exe,*\task,*\task.exe -ErrorAction SilentlyContinue).Name | Select-Object -Unique + +Register-ArgumentCompleter -CommandName $cmdNames -ScriptBlock { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($commandName.StartsWith('-')) { diff --git a/go.mod b/go.mod index e776c769..16627cbb 100644 --- a/go.mod +++ b/go.mod @@ -1,37 +1,37 @@ module github.com/go-task/task/v3 -go 1.25.8 +go 1.25.10 require ( charm.land/bubbles/v2 v2.1.0 - charm.land/bubbletea/v2 v2.0.2 - charm.land/lipgloss/v2 v2.0.2 + charm.land/bubbletea/v2 v2.0.7 + charm.land/lipgloss/v2 v2.0.4 github.com/Ladicle/tabwriter v1.0.0 - github.com/Masterminds/semver/v3 v3.4.0 - github.com/alecthomas/chroma/v2 v2.23.1 + github.com/Masterminds/semver/v3 v3.5.0 + github.com/alecthomas/chroma/v2 v2.27.0 github.com/chainguard-dev/git-urls v1.0.2 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dominikbraun/graph v0.23.0 github.com/elliotchance/orderedmap/v3 v3.1.0 github.com/fatih/color v1.19.0 - github.com/fsnotify/fsnotify v1.9.0 + github.com/fsnotify/fsnotify v1.10.1 github.com/go-task/slim-sprig/v3 v3.0.0 github.com/go-task/template v0.2.0 github.com/google/uuid v1.6.0 github.com/hashicorp/go-getter v1.8.6 github.com/joho/godotenv v1.5.1 github.com/mitchellh/hashstructure/v2 v2.0.2 - github.com/puzpuzpuz/xsync/v4 v4.4.0 + github.com/puzpuzpuz/xsync/v4 v4.5.0 github.com/sajari/fuzzy v1.0.0 github.com/sebdah/goldie/v2 v2.8.0 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 github.com/zeebo/xxh3 v1.1.0 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/sync v0.20.0 - golang.org/x/term v0.42.0 + golang.org/x/sync v0.21.0 + golang.org/x/term v0.44.0 mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 - mvdan.cc/sh/v3 v3.13.1 + mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117 ) require ( @@ -68,16 +68,16 @@ require ( github.com/aws/smithy-go v1.24.2 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charmbracelet/colorprofile v0.4.2 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect - github.com/charmbracelet/x/ansi v0.11.6 // indirect + github.com/charmbracelet/colorprofile v0.4.3 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260525132238-948f4557a654 // indirect + github.com/charmbracelet/x/ansi v0.11.7 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/dlclark/regexp2/v2 v2.2.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect @@ -94,10 +94,10 @@ require ( github.com/klauspost/compress v1.18.5 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // 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.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.21 // indirect + github.com/mattn/go-runewidth v0.0.23 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect @@ -120,11 +120,11 @@ require ( go.opentelemetry.io/otel/sdk v1.43.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/net v0.52.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/text v0.35.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.37.0 // indirect golang.org/x/time v0.15.0 // indirect google.golang.org/api v0.271.0 // indirect google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect diff --git a/go.sum b/go.sum index 2abce36f..c17742d6 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,14 @@ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g= charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY= -charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0= -charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= -charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs= -charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM= +charm.land/bubbletea/v2 v2.0.6 h1:UHN/91OyuhaOFGSrBXQ/hMZD8IO1Uc4BvHlgHXL2WJo= +charm.land/bubbletea/v2 v2.0.6/go.mod h1:MH/D8ZLlN3op37vQvijKuU29g3rqTp+aQapURFonF9g= +charm.land/bubbletea/v2 v2.0.7 h1:7qw2tTAVar7m7klOPBYfTB0mniv/RuexsYwMRNxSeL0= +charm.land/bubbletea/v2 v2.0.7/go.mod h1:DGW2q8gvzHnOpMpZTORs0aySVHCox5C+2Svk0fci1qs= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= +charm.land/lipgloss/v2 v2.0.4 h1:lcPeVtcp23SNra7lHy8iYE4UC2aIipVQ47sbGyyxR5Q= +charm.land/lipgloss/v2 v2.0.4/go.mod h1:0653x8epbZSzdDfO/XPS1a/uYPOBeSsCssOpJOqDzik= 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/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= @@ -36,12 +40,14 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg= github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4= -github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= -github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.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/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.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/chroma/v2 v2.26.1 h1:2X21EdxGZNv5GF9mG5u+uzc02GCFyGxbcBm3Grd9A78= +github.com/alecthomas/chroma/v2 v2.26.1/go.mod h1:lxhRRa9H4hPmRLOOdYga4zkQIQjq3dtrrdwQeCfu78Y= +github.com/alecthomas/chroma/v2 v2.27.0 h1:FodwmyOBgJULFYmDqibcp9pvfDLWdtPRh9v/r5BXYZs= +github.com/alecthomas/chroma/v2 v2.27.0/go.mod h1:NjJ3ciIgrqBNeIkWZ4e46nseoLDslxU1LmfCoL+wcY8= 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/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= @@ -92,12 +98,14 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ= github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= -github.com/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-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.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= -github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= +github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= +github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= +github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468 h1:Q9fO0y1Zo5KB/5Vu8JZoLGm1N3RzF9bNj3Ao3xoR+Ac= +github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= +github.com/charmbracelet/ultraviolet v0.0.0-20260525132238-948f4557a654 h1:FpSYhY28ucg9ZRr+2wj67FAQ0Ey5yiK0072PmRDJNek= +github.com/charmbracelet/ultraviolet v0.0.0-20260525132238-948f4557a654/go.mod h1:hFpumms29Smx3LStRfku8vcCTBe1Kq8aCXtHUJa3mjY= +github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= +github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= 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/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -118,8 +126,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2/v2 v2.1.1 h1:LCUGyd9Wf+r+VVOl8Ny38JTpWJcAsdVnCIuhhtthmKw= +github.com/dlclark/regexp2/v2 v2.1.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= +github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0= +github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -138,8 +148,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -192,14 +202,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= -github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= +github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= -github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= +github.com/mattn/go-runewidth v0.0.23/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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= @@ -214,8 +224,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.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 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.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= +github.com/puzpuzpuz/xsync/v4 v4.5.0 h1:vOSWu6b57/emh+L/Cw0BeQfvxa/cogFywXHeGUxQxAg= +github.com/puzpuzpuz/xsync/v4 v4.5.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= @@ -272,27 +282,29 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09 go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= @@ -319,5 +331,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 h1:3bbJwtPFh98dJ6lxRdR3eLHTH1CmR3BcU6TriIMiXjE= mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997/go.mod h1:Qy/zdaMDxq9sT72Gi43K3gsV+TtTohyDO3f1cyBVwuo= -mvdan.cc/sh/v3 v3.13.1 h1:DP3TfgZhDkT7lerUdnp6PTGKyxxzz6T+cOlY/xEvfWk= -mvdan.cc/sh/v3 v3.13.1/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0= +mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117 h1:BfzdGSjcnJBb8sPNLudpzTml8zFUxS1N0N/v9IIS6tQ= +mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0= diff --git a/internal/deepcopy/deepcopy.go b/internal/deepcopy/deepcopy.go index 48329c13..9ce454b4 100644 --- a/internal/deepcopy/deepcopy.go +++ b/internal/deepcopy/deepcopy.go @@ -81,7 +81,7 @@ func TraverseStringsFunc[T any](v T, fn func(v string) (string, error)) (T, erro traverseFunc = func(copy, v reflect.Value) error { switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: // Unwrap the pointer originalValue := v.Elem() // If the pointer is nil, do nothing diff --git a/internal/execext/exec.go b/internal/execext/exec.go index 811e9442..a418a2aa 100644 --- a/internal/execext/exec.go +++ b/internal/execext/exec.go @@ -127,7 +127,10 @@ func ExpandFields(s string) ([]string, error) { s = escape(s) p := syntax.NewParser() var words []*syntax.Word - for w := range p.WordsSeq(strings.NewReader(s)) { + for w, err := range p.WordsSeq(strings.NewReader(s)) { + if err != nil { + return nil, err + } words = append(words, w) } cfg := &expand.Config{ diff --git a/internal/fingerprint/sources_checksum.go b/internal/fingerprint/sources_checksum.go index f1108e11..3afd7b0a 100644 --- a/internal/fingerprint/sources_checksum.go +++ b/internal/fingerprint/sources_checksum.go @@ -119,7 +119,7 @@ func (checker *ChecksumChecker) checksumFilePath(t *ast.Task) string { return filepath.Join(checker.tempDir, "checksum", normalizeFilename(t.Name())) } -var checksumFilenameRegexp = regexp.MustCompile("[^A-z0-9]") +var checksumFilenameRegexp = regexp.MustCompile("[^[:alnum:]]") // replaces invalid characters on filenames with "-" func normalizeFilename(f string) string { diff --git a/internal/fingerprint/sources_checksum_test.go b/internal/fingerprint/sources_checksum_test.go index a2b35cd3..a8e4b253 100644 --- a/internal/fingerprint/sources_checksum_test.go +++ b/internal/fingerprint/sources_checksum_test.go @@ -16,6 +16,10 @@ func TestNormalizeFilename(t *testing.T) { {"foo/bar/baz", "foo-bar-baz"}, {"foo@bar/baz", "foo-bar-baz"}, {"foo1bar2baz3", "foo1bar2baz3"}, + {"foo\\bar", "foo-bar"}, + {"foo_bar", "foo-bar"}, + {"foo[bar]baz", "foo-bar-baz"}, + {"foo^bar`baz", "foo-bar-baz"}, } for _, test := range tests { assert.Equal(t, test.Out, normalizeFilename(test.In)) diff --git a/internal/summary/summary.go b/internal/summary/summary.go index 3a63b41c..9edd9511 100644 --- a/internal/summary/summary.go +++ b/internal/summary/summary.go @@ -285,7 +285,9 @@ func isEnvVar(key string, envVars map[string]bool) bool { key == "TASKFILE_DIR" || key == "USER_WORKING_DIR" || key == "ALIAS" || - key == "MATCH" { + key == "MATCH" || + key == "PATH_LIST_SEPARATOR" || + key == "FILE_PATH_SEPARATOR" { return true } return envVars[key] diff --git a/internal/templater/funcs.go b/internal/templater/funcs.go index 7bffae31..2fe85b96 100644 --- a/internal/templater/funcs.go +++ b/internal/templater/funcs.go @@ -3,6 +3,8 @@ package templater import ( "maps" "math/rand/v2" + "os" + "path" "path/filepath" "runtime" "strings" @@ -21,8 +23,8 @@ var templateFuncs template.FuncMap func init() { taskFuncs := template.FuncMap{ - "OS": os, - "ARCH": arch, + "OS": goos, + "ARCH": goarch, "numCPU": runtime.NumCPU, "catLines": catLines, "splitLines": splitLines, @@ -33,7 +35,10 @@ func init() { "splitArgs": splitArgs, "IsSH": IsSH, // Deprecated "joinPath": filepath.Join, + "joinEnv": joinEnv, + "joinUrl": joinUrl, "relPath": filepath.Rel, + "absPath": filepath.Abs, "merge": merge, "spew": spew.Sdump, "fromYaml": fromYaml, @@ -56,11 +61,11 @@ func init() { maps.Copy(templateFuncs, taskFuncs) } -func os() string { +func goos() string { return runtime.GOOS } -func arch() string { +func goarch() string { return runtime.GOARCH } @@ -94,6 +99,14 @@ func IsSH() bool { return true } +func joinEnv(elem ...string) string { + return strings.Join(elem, string(os.PathListSeparator)) +} + +func joinUrl(elem ...string) string { + return path.Join(elem...) +} + func merge(base map[string]any, v ...map[string]any) map[string]any { cap := len(v) for _, m := range v { diff --git a/internal/templater/templater.go b/internal/templater/templater.go index 3de897b9..eb4579be 100644 --- a/internal/templater/templater.go +++ b/internal/templater/templater.go @@ -68,6 +68,13 @@ func ReplaceWithExtra[T any](v T, cache *Cache, extra map[string]any) T { return v } + // Optimization: skip if string is not a template + if s, ok := any(v).(string); ok { + if !strings.Contains(s, "{{") { + return v + } + } + // Initialize the cache map if it's not already initialized if cache.cacheMap == nil { cache.cacheMap = cache.Vars.ToCacheMap() @@ -82,6 +89,10 @@ func ReplaceWithExtra[T any](v T, cache *Cache, extra map[string]any) T { // Traverse the value and parse any template variables copy, err := deepcopy.TraverseStringsFunc(v, func(v string) (string, error) { + // Optimization: skip if string is not a template + if !strings.Contains(v, "{{") { + return v, nil + } tpl, err := template.New("").Funcs(templateFuncs).Parse(v) if err != nil { return v, err diff --git a/internal/version/version.txt b/internal/version/version.txt index ca25ff63..d1278a46 100644 --- a/internal/version/version.txt +++ b/internal/version/version.txt @@ -1 +1 @@ -3.50.0 +3.51.1 diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..63b1e379 --- /dev/null +++ b/mise.toml @@ -0,0 +1,12 @@ +[tools] +# Runtimes +go = "1.26.4" +node = "24" +pnpm = "11.8.0" + +# Dev tools +golangci-lint = "2.12.2" +mockery = "3.7.1" +gotestsum = "latest" +goreleaser = "2" +"go:golang.org/x/exp/cmd/gorelease" = "latest" diff --git a/requires.go b/requires.go index 41e9e5a4..f235a3d0 100644 --- a/requires.go +++ b/requires.go @@ -3,6 +3,8 @@ package task import ( "slices" + "github.com/elliotchance/orderedmap/v3" + "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/internal/input" "github.com/go-task/task/v3/internal/term" @@ -32,7 +34,7 @@ func (e *Executor) promptDepsVars(calls []*Call) error { // Collect all missing vars from the dependency tree visited := make(map[string]bool) - varsMap := make(map[string]*ast.VarsWithValidation) + varsMap := orderedmap.NewOrderedMap[string, *ast.VarsWithValidation]() var collect func(call *Call) error collect = func(call *Call) error { @@ -42,8 +44,8 @@ func (e *Executor) promptDepsVars(calls []*Call) error { } for _, v := range getMissingRequiredVars(compiledTask) { - if _, exists := varsMap[v.Name]; !exists { - varsMap[v.Name] = v + if !varsMap.Has(v.Name) { + varsMap.Set(v.Name, v) } } @@ -73,14 +75,14 @@ func (e *Executor) promptDepsVars(calls []*Call) error { } } - if len(varsMap) == 0 { + if varsMap.Len() == 0 { return nil } prompter := e.newPrompter() e.promptedVars = ast.NewVars() - for _, v := range varsMap { + for v := range varsMap.Values() { value, err := prompter.Prompt(v.Name, getEnumValues(v.Enum)) if err != nil { if errors.Is(err, input.ErrCancelled) { diff --git a/task_test.go b/task_test.go index 46729410..80915c2c 100644 --- a/task_test.go +++ b/task_test.go @@ -2601,6 +2601,27 @@ func TestSplitArgs(t *testing.T) { assert.Equal(t, "3\n", buff.String()) } +func TestAbsPath(t *testing.T) { + t.Parallel() + + var buff bytes.Buffer + e := task.NewExecutor( + task.WithDir("testdata/abs_path"), + task.WithStdout(&buff), + task.WithStderr(&buff), + task.WithSilent(true), + ) + require.NoError(t, e.Setup()) + + err := e.Run(t.Context(), &task.Call{Task: "default"}) + require.NoError(t, err) + + cwd, err := os.Getwd() + require.NoError(t, err) + expected := filepath.Join(cwd, "bar") + "\n" + assert.Equal(t, expected, buff.String()) +} + func TestSingleCmdDep(t *testing.T) { t.Parallel() diff --git a/taskfile/ast/matrix.go b/taskfile/ast/matrix.go index aab0687d..8421b77e 100644 --- a/taskfile/ast/matrix.go +++ b/taskfile/ast/matrix.go @@ -93,6 +93,21 @@ func (matrix *Matrix) DeepCopy() *Matrix { } } +// DeepCopy returns a copy of the MatrixRow. Without this, deepcopy.OrderedMap +// falls back to copying the *MatrixRow pointer as-is, so every "copy" of a +// Matrix would still share the same underlying rows - see #2890, where +// concurrent invocations of a task with a `ref:` matrix row raced on +// resolveMatrixRefs mutating that shared row. +func (row *MatrixRow) DeepCopy() *MatrixRow { + if row == nil { + return nil + } + return &MatrixRow{ + Ref: row.Ref, + Value: deepcopy.Slice(row.Value), + } +} + func (matrix *Matrix) UnmarshalYAML(node *yaml.Node) error { switch node.Kind { case yaml.MappingNode: diff --git a/taskfile/node.go b/taskfile/node.go index 9ae936d5..58055cd3 100644 --- a/taskfile/node.go +++ b/taskfile/node.go @@ -93,8 +93,8 @@ func getScheme(uri string) (string, error) { return "git", nil } - if i := strings.Index(uri, "://"); i != -1 { - return uri[:i], nil + if before, _, ok := strings.Cut(uri, "://"); ok { + return before, nil } return "", nil diff --git a/taskfile/reader.go b/taskfile/reader.go index dbcdad9c..1b8556c1 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "os" + "slices" "sync" "time" @@ -285,12 +286,7 @@ func (r *Reader) isTrusted(uri string) bool { host := parsedURL.Host // Check against each trusted pattern (exact match including port if provided) - for _, pattern := range r.trustedHosts { - if host == pattern { - return true - } - } - return false + return slices.Contains(r.trustedHosts, host) } func (r *Reader) include(ctx context.Context, node Node) error { diff --git a/testdata/abs_path/Taskfile.yml b/testdata/abs_path/Taskfile.yml new file mode 100644 index 00000000..ba09cbca --- /dev/null +++ b/testdata/abs_path/Taskfile.yml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + default: + cmds: + - cmd: echo '{{absPath "foo/../bar"}}' diff --git a/variables.go b/variables.go index e9560744..0f8fcb73 100644 --- a/variables.go +++ b/variables.go @@ -351,13 +351,14 @@ func itemsFromFor( var values []any // The list of values to loop over // Get the list from a matrix if f.Matrix.Len() != 0 { - if err := resolveMatrixRefs(f.Matrix, cache); err != nil { + resolvedMatrix, err := resolveMatrixRefs(f.Matrix, cache) + if err != nil { return nil, nil, errors.TaskfileInvalidError{ URI: location.Taskfile, Err: err, } } - return asAnySlice(product(f.Matrix)), nil, nil + return asAnySlice(product(resolvedMatrix)), nil, nil } // Get the list from the explicit for list if len(f.List) > 0 { @@ -429,22 +430,43 @@ func itemsFromFor( return values, keys, nil } -func resolveMatrixRefs(matrix *ast.Matrix, cache *templater.Cache) error { +// resolveMatrixRefs resolves any `ref:` rows in matrix and returns a new +// Matrix with those rows populated. It must not mutate the matrix passed in: +// that matrix is part of the shared, cached Task AST, and concurrent +// invocations of the same task (e.g. via parallel deps) call this with the +// same *ast.Matrix and would otherwise race on the row.Value assignment +// below, intermittently leaking a value resolved for one caller into another +// caller's expansion. See #2890. +func resolveMatrixRefs(matrix *ast.Matrix, cache *templater.Cache) (*ast.Matrix, error) { if matrix.Len() == 0 { - return nil + return matrix, nil } + hasRef := false for _, row := range matrix.All() { + if row.Ref != "" { + hasRef = true + break + } + } + if !hasRef { + return matrix, nil + } + resolved := matrix.DeepCopy() + for _, row := range resolved.All() { if row.Ref != "" { v := templater.ResolveRef(row.Ref, cache) + if cache.Err() != nil { + return nil, cache.Err() + } switch value := v.(type) { case []any: row.Value = value default: - return fmt.Errorf("matrix reference %q must resolve to a list", row.Ref) + return nil, fmt.Errorf("matrix reference %q must resolve to a list", row.Ref) } } } - return nil + return resolved, nil } func resolveEnumRefs(requires *ast.Requires, cache *templater.Cache) error { diff --git a/variables_test.go b/variables_test.go new file mode 100644 index 00000000..60a923da --- /dev/null +++ b/variables_test.go @@ -0,0 +1,45 @@ +package task + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/go-task/task/v3/internal/templater" + "github.com/go-task/task/v3/taskfile/ast" +) + +// TestResolveMatrixRefsDoesNotMutateInput is a regression test for #2890. The +// *ast.Matrix passed to resolveMatrixRefs is part of the shared, cached Task +// AST: the same *ast.Matrix is reused on every invocation of a task. If +// resolveMatrixRefs resolved `ref:` rows in place, concurrent invocations of +// the same task (e.g. via parallel deps) would race on that mutation and leak +// a value resolved for one caller into another caller's expansion. +// +// The invariant that prevents this is that resolveMatrixRefs must resolve into +// a copy and leave its input untouched, which this test asserts deterministically. +func TestResolveMatrixRefsDoesNotMutateInput(t *testing.T) { + t.Parallel() + + matrix := ast.NewMatrix( + &ast.MatrixElement{Key: "ARCH", Value: &ast.MatrixRow{Ref: ".ARCH_VAR"}}, + ) + + vars := ast.NewVars() + vars.Set("ARCH_VAR", ast.Var{Value: []any{"amd64"}}) + cache := &templater.Cache{Vars: vars} + + resolved, err := resolveMatrixRefs(matrix, cache) + require.NoError(t, err) + + // The returned matrix has the ref resolved... + row, ok := resolved.Get("ARCH") + require.True(t, ok, "ARCH row missing from resolved matrix") + require.Equal(t, []any{"amd64"}, row.Value) + + // ...but the shared input matrix must be left untouched. + orig, ok := matrix.Get("ARCH") + require.True(t, ok, "ARCH row missing from input matrix") + require.Nil(t, orig.Value, "input matrix was mutated: Ref rows must be resolved into a copy") + require.Equal(t, ".ARCH_VAR", orig.Ref, "input matrix Ref was altered") +} diff --git a/website/.vitepress/adopters.ts b/website/.vitepress/adopters.ts new file mode 100644 index 00000000..5bff42fd --- /dev/null +++ b/website/.vitepress/adopters.ts @@ -0,0 +1,138 @@ +export interface Adopter { + name: string; + url: string; + img: string; + description: string; +} + +export const adopters: Adopter[] = [ + // Big brand names (first three double as the "featured" showcase) + { + name: 'Docker', + url: 'https://github.com/docker/mcp-registry', + img: 'https://github.com/docker.png', + description: + 'The industry-standard container platform uses Task in mcp-registry, the official registry for Docker Model Context Protocol servers.' + }, + { + name: 'Vercel', + url: 'https://github.com/vercel/terraform-provider-vercel', + img: 'https://github.com/vercel.png', + description: + 'The team behind Next.js and the leading frontend cloud platform uses Task to run and release the official Vercel Terraform provider.' + }, + { + name: 'HashiCorp', + url: 'https://github.com/hashicorp/terraform-aws-terraform-enterprise-hvd', + img: 'https://github.com/hashicorp.png', + description: + 'HashiCorp ships Task across its Validated Design modules for Terraform, Vault, Consul, Nomad, and Boundary on AWS, Azure, and GCP.' + }, + // Other big brands + { + name: 'Microsoft', + url: 'https://github.com/Azure/Azure-Sentinel', + img: 'https://github.com/microsoft.png', + description: + 'Azure Sentinel, Microsoft’s cloud-native SIEM used by enterprises worldwide, relies on Task to orchestrate its repository automation.' + }, + { + name: 'Google Cloud', + url: 'https://github.com/GoogleCloudPlatform/deploystack', + img: 'https://github.com/GoogleCloudPlatform.png', + description: + 'DeployStack, Google Cloud’s one-click Terraform deployment tool, automates its workflows with Task.' + }, + { + name: 'AWS', + url: 'https://github.com/aws-samples/appmod-blueprints', + img: 'https://github.com/aws-samples.png', + description: + 'The AWS Samples AppMod Blueprints reference platform uses Task to orchestrate its demo environments.' + }, + { + name: 'Anthropic', + url: 'https://github.com/anthropics/buffa', + img: 'https://github.com/anthropics.png', + description: + 'Anthropic’s Rust protobuf implementation, buffa, uses Task for its build and release tooling.' + }, + { + name: 'MongoDB', + url: 'https://github.com/mongodb/mongo-go-driver', + img: 'https://github.com/mongodb.png', + description: + 'The official Go driver for MongoDB uses Task to orchestrate its build, lint, formatting, and full test suite across every commit.' + }, + { + name: 'Redpanda', + url: 'https://github.com/redpanda-data/connect', + img: 'https://github.com/redpanda-data.png', + description: + 'Redpanda Connect, the stream processor formerly known as Benthos, uses Task to orchestrate builds, Docker images, test suites, and its GitHub release pipeline.' + }, + // Notable open source projects + { + name: 'Flet', + url: 'https://github.com/flet-dev/flet', + img: 'https://github.com/flet-dev.png', + description: + 'Build realtime web, mobile and desktop apps in Python, with no frontend experience required.' + }, + { + name: 'GoReleaser', + url: 'https://github.com/goreleaser/goreleaser', + img: 'https://github.com/goreleaser.png', + description: + 'Release engineering, simplified. GoReleaser is the de-facto release automation tool for Go projects.' + }, + { + name: 'Arduino CLI', + url: 'https://github.com/arduino/arduino-cli', + img: 'https://github.com/arduino.png', + description: + 'The official Arduino command-line tool. Task powers the entire Arduino developer tooling stack across 70+ repositories.' + }, + { + name: 'FerretDB', + url: 'https://github.com/FerretDB/FerretDB', + img: 'https://github.com/FerretDB.png', + description: + 'A truly open-source MongoDB alternative built on PostgreSQL, with Task driving every build and release step.' + }, + { + name: 'Tyk', + url: 'https://github.com/TykTechnologies/tyk', + img: 'https://github.com/TykTechnologies.png', + description: + 'Open source API gateway supporting REST, GraphQL, TCP and gRPC, automated end-to-end with Task.' + }, + { + name: 'Charmbracelet', + url: 'https://github.com/charmbracelet/glamour', + img: 'https://github.com/charmbracelet.png', + description: + 'The team behind Bubble Tea uses Task to build Glamour, the stylesheet-based markdown renderer for CLI apps.' + }, + { + name: 'Outline', + url: 'https://github.com/OutlineFoundation/outline-server', + img: 'https://github.com/OutlineFoundation.png', + description: + 'Outline, the open-source proxy server originally built by Jigsaw (Google), uses Task for its build pipeline.' + }, + { + name: 'werf', + url: 'https://github.com/werf/werf', + img: 'https://github.com/werf.png', + description: + 'werf, the CNCF-hosted CI/CD tool for shipping software to Kubernetes, uses Task as its build and development entry point.' + }, + { + name: 'Gobuster', + url: 'https://github.com/OJ/gobuster', + img: 'https://github.com/OJ.png', + description: + 'The ubiquitous directory, DNS and virtual-host brute-forcing tool trusted by pen testers worldwide runs its entire build through Task.' + } +]; diff --git a/website/.vitepress/components/Adopters.vue b/website/.vitepress/components/Adopters.vue new file mode 100644 index 00000000..3e09cc8b --- /dev/null +++ b/website/.vitepress/components/Adopters.vue @@ -0,0 +1,629 @@ + + + + + diff --git a/website/.vitepress/components/AdoptersCarousel.vue b/website/.vitepress/components/AdoptersCarousel.vue new file mode 100644 index 00000000..073f95b3 --- /dev/null +++ b/website/.vitepress/components/AdoptersCarousel.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/website/.vitepress/components/HomePage.vue b/website/.vitepress/components/HomePage.vue index c61123c1..3c700ac8 100644 --- a/website/.vitepress/components/HomePage.vue +++ b/website/.vitepress/components/HomePage.vue @@ -1,12 +1,14 @@