diff --git a/.claude/worktrees/mask-include-urls b/.claude/worktrees/mask-include-urls new file mode 160000 index 00000000..13b5f7a8 --- /dev/null +++ b/.claude/worktrees/mask-include-urls @@ -0,0 +1 @@ +Subproject commit 13b5f7a891a22557ad413767d011176b115ea9c6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c7a81f1..c36d5e71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## v3.53.0 - 2026-08-18 - **Remote Taskfiles are now generally available!** This has been an experimental feature for 3 years, but is now enabled by default. Massive diff --git a/internal/version/version.txt b/internal/version/version.txt index 7ac0b0a6..c5c343b5 100644 --- a/internal/version/version.txt +++ b/internal/version/version.txt @@ -1 +1 @@ -3.52.0 +3.53.0 diff --git a/mise.lock b/mise.lock new file mode 100644 index 00000000..0fe0b1fb --- /dev/null +++ b/mise.lock @@ -0,0 +1,279 @@ +# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html + +[[tools.go]] +version = "1.26.6" +backend = "core:go" + +[tools.go."platforms.linux-arm64"] +checksum = "sha256:d0507e9e9d7fe012aae570108cbd76c15de879e17130ab8cb90d4d7445cb1f2e" +url = "https://dl.google.com/go/go1.26.6.linux-arm64.tar.gz" + +[tools.go."platforms.linux-arm64-musl"] +checksum = "sha256:d0507e9e9d7fe012aae570108cbd76c15de879e17130ab8cb90d4d7445cb1f2e" +url = "https://dl.google.com/go/go1.26.6.linux-arm64.tar.gz" + +[tools.go."platforms.linux-x64"] +checksum = "sha256:708effb774be8237570d0add163225abbdfaf4fca28b2611df167beba4feef89" +url = "https://dl.google.com/go/go1.26.6.linux-amd64.tar.gz" + +[tools.go."platforms.linux-x64-musl"] +checksum = "sha256:708effb774be8237570d0add163225abbdfaf4fca28b2611df167beba4feef89" +url = "https://dl.google.com/go/go1.26.6.linux-amd64.tar.gz" + +[tools.go."platforms.macos-arm64"] +checksum = "sha256:2dc95ce4675829f2df0e86b28bcef3283635902062a5f0580ca659bf570f3204" +url = "https://dl.google.com/go/go1.26.6.darwin-arm64.tar.gz" + +[tools.go."platforms.macos-x64"] +checksum = "sha256:08b65a63f244115121ced6c3b55ad38d801a7442acad5c949a17aad84ae6d684" +url = "https://dl.google.com/go/go1.26.6.darwin-amd64.tar.gz" + +[tools.go."platforms.windows-x64"] +checksum = "sha256:5b6c5b556525810463b5c897b50dc7a82d6a3dc0bfaf55d990a7e9f31d6b2318" +url = "https://dl.google.com/go/go1.26.6.windows-amd64.zip" + +[[tools."go:golang.org/x/exp/cmd/gorelease"]] +version = "0.0.0-20260603202125-055de637280b" +backend = "go:golang.org/x/exp/cmd/gorelease" + +[[tools.golangci-lint]] +version = "2.12.2" +backend = "aqua:golangci/golangci-lint" + +[tools.golangci-lint."platforms.linux-arm64"] +checksum = "sha256:44cd40a8c76c86755375adfeea52cfd3533cb43d7bd647771e0ae065e166df3a" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-linux-arm64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413470996" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.linux-arm64-musl"] +checksum = "sha256:44cd40a8c76c86755375adfeea52cfd3533cb43d7bd647771e0ae065e166df3a" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-linux-arm64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413470996" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.linux-x64"] +checksum = "sha256:8df580d2670fed8fa984aac0507099af8df275e665215f5c7a2ae3943893a553" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-linux-amd64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413471054" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.linux-x64-musl"] +checksum = "sha256:8df580d2670fed8fa984aac0507099af8df275e665215f5c7a2ae3943893a553" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-linux-amd64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413471054" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.macos-arm64"] +checksum = "sha256:a9c54498731b3128f79e090be6110f3e5fffccc617b08142ed244d4126c73f29" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-darwin-arm64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413470950" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.macos-x64"] +checksum = "sha256:f6f06d94b6241521c53d15450c5209b028270bf966f842afb11c030c79f5bc16" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-darwin-amd64.tar.gz" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413470980" +provenance = "github-attestations" + +[tools.golangci-lint."platforms.windows-x64"] +checksum = "sha256:bd42e3ebc8cb4ececb86941983baaf1dc221bbb04d838e94ce63b49cc91e02bb" +url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golangci-lint-2.12.2-windows-amd64.zip" +url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413471017" +provenance = "github-attestations" + +[[tools.goreleaser]] +version = "2.16.0" +backend = "aqua:goreleaser/goreleaser" + +[tools.goreleaser."platforms.linux-arm64"] +checksum = "sha256:0102d974373fcdeb77042d1f5897caffa193be36620fdc6c1da43a01ef8e10d3" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428676998" +provenance = "github-attestations" + +[tools.goreleaser."platforms.linux-arm64-musl"] +checksum = "sha256:0102d974373fcdeb77042d1f5897caffa193be36620fdc6c1da43a01ef8e10d3" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428676998" +provenance = "github-attestations" + +[tools.goreleaser."platforms.linux-x64"] +checksum = "sha256:eaae05b5eba07533bd0f06846b68c808399504784df00c62eb219541fc04e5e2" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Linux_x86_64.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428676974" +provenance = "github-attestations" + +[tools.goreleaser."platforms.linux-x64-musl"] +checksum = "sha256:eaae05b5eba07533bd0f06846b68c808399504784df00c62eb219541fc04e5e2" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Linux_x86_64.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428676974" +provenance = "github-attestations" + +[tools.goreleaser."platforms.macos-arm64"] +checksum = "sha256:6a102e4d588fd3553a9ac7321ca6023a9f205843f4861ca35bd337dfa9e72ece" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Darwin_all.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428677010" +provenance = "github-attestations" + +[tools.goreleaser."platforms.macos-x64"] +checksum = "sha256:6a102e4d588fd3553a9ac7321ca6023a9f205843f4861ca35bd337dfa9e72ece" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Darwin_all.tar.gz" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428677010" +provenance = "github-attestations" + +[tools.goreleaser."platforms.windows-x64"] +checksum = "sha256:6fe5eda11f0bcac8069aff3ef3dcb0b11816c9e95f89773595564697a5278bc9" +url = "https://github.com/goreleaser/goreleaser/releases/download/v2.16.0/goreleaser_Windows_x86_64.zip" +url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/428676991" +provenance = "github-attestations" + +[[tools.gotestsum]] +version = "1.13.0" +backend = "aqua:gotestyourself/gotestsum" + +[tools.gotestsum."platforms.linux-arm64"] +checksum = "sha256:7644a4c5cd1bb978d56245aeab25a586ac5ac62adebed20a399548867c13499d" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996834" + +[tools.gotestsum."platforms.linux-arm64-musl"] +checksum = "sha256:7644a4c5cd1bb978d56245aeab25a586ac5ac62adebed20a399548867c13499d" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996834" + +[tools.gotestsum."platforms.linux-x64"] +checksum = "sha256:11ccddeaf708ef228889f9fe2f68291a75b27013ddfc3b18156e094f5f40e8ee" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996833" + +[tools.gotestsum."platforms.linux-x64-musl"] +checksum = "sha256:11ccddeaf708ef228889f9fe2f68291a75b27013ddfc3b18156e094f5f40e8ee" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996833" + +[tools.gotestsum."platforms.macos-arm64"] +checksum = "sha256:509cb27aef747f48faf9bce424f59dcf79572c905204b990ee935bbfcc7fa0e9" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_darwin_arm64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996838" + +[tools.gotestsum."platforms.macos-x64"] +checksum = "sha256:99529350f4c7b780b1efc543ca0d9721b09f0a4228f0efa9281261f58fefa05a" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_darwin_amd64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996829" + +[tools.gotestsum."platforms.windows-x64"] +checksum = "sha256:fd5a6dc69e46a0970593e70d85a7e75f16714e9c61d6d72ccc324eb82df5bb8a" +url = "https://github.com/gotestyourself/gotestsum/releases/download/v1.13.0/gotestsum_1.13.0_windows_amd64.tar.gz" +url_api = "https://api.github.com/repos/gotestyourself/gotestsum/releases/assets/291996823" + +[[tools.mockery]] +version = "3.7.3" +backend = "aqua:vektra/mockery" + +[tools.mockery."platforms.linux-arm64"] +checksum = "sha256:01882151519384bf7877d0c63c0fc02a678ee5d9a2c6c8666675aa17a16744c4" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944620" + +[tools.mockery."platforms.linux-arm64-musl"] +checksum = "sha256:01882151519384bf7877d0c63c0fc02a678ee5d9a2c6c8666675aa17a16744c4" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944620" + +[tools.mockery."platforms.linux-x64"] +checksum = "sha256:150bbabc3c50ceb964b709fdfbc54e095e4f585a85ccfe2c8ee7f640d522f110" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Linux_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944625" + +[tools.mockery."platforms.linux-x64-musl"] +checksum = "sha256:150bbabc3c50ceb964b709fdfbc54e095e4f585a85ccfe2c8ee7f640d522f110" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Linux_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944625" + +[tools.mockery."platforms.macos-arm64"] +checksum = "sha256:4886bfd00f82dfb0ccd8112aaf4e85af142b4c3e051635120ac73c3394b59ff4" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Darwin_arm64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944639" + +[tools.mockery."platforms.macos-x64"] +checksum = "sha256:107abe6c7bbf1ecc3d5a2fa9f621ab8d12816367b8ce35d51fa1cbf556f9360b" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Darwin_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944643" + +[tools.mockery."platforms.windows-x64"] +checksum = "sha256:53c3592aae7652ff2b15f3a246d19b407c6fa958301ce042df6400b145425442" +url = "https://github.com/vektra/mockery/releases/download/v3.7.3/mockery_3.7.3_Windows_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/511944622" + +[[tools.node]] +version = "24.19.0" +backend = "core:node" + +[tools.node."platforms.linux-arm64"] +checksum = "sha256:d28c8a5bf0a808f0ed434a1dce8c54ae98f0371c0bd86ac58abc613f73e6643f" +url = "https://nodejs.org/dist/v24.19.0/node-v24.19.0-linux-arm64.tar.gz" + +[tools.node."platforms.linux-arm64-musl"] +checksum = "sha256:20824e4d35948fae5b337dccef47813b04d8995312f59df7386f2256d9f9ab7e" +url = "https://unofficial-builds.nodejs.org/download/release/v24.19.0/node-v24.19.0-linux-arm64-musl.tar.gz" + +[tools.node."platforms.linux-x64"] +checksum = "sha256:f625d97cd707df4ff96254916fbc5ff014f09c09effe5a1e0ca8f6d41a8789d4" +url = "https://nodejs.org/dist/v24.19.0/node-v24.19.0-linux-x64.tar.gz" + +[tools.node."platforms.linux-x64-musl"] +checksum = "sha256:c60223786df14a5d23e220ebb8e60318f5322640a62f90e6d9e54d3a18da532e" +url = "https://unofficial-builds.nodejs.org/download/release/v24.19.0/node-v24.19.0-linux-x64-musl.tar.gz" + +[tools.node."platforms.macos-arm64"] +checksum = "sha256:8294b7aa9b03997481c06babf1e8b270c859358f27da57a11509afe537ac381d" +url = "https://nodejs.org/dist/v24.19.0/node-v24.19.0-darwin-arm64.tar.gz" + +[tools.node."platforms.macos-x64"] +checksum = "sha256:d1b5e999db158c62fe8f7267a4476b035d8bd93b1a605bac24a3f0dd166e3316" +url = "https://nodejs.org/dist/v24.19.0/node-v24.19.0-darwin-x64.tar.gz" + +[tools.node."platforms.windows-x64"] +checksum = "sha256:57f71ab3652e797d84acddc79c81cc9ff1c6ddb2a1974cdb83f00fee9bff4c73" +url = "https://nodejs.org/dist/v24.19.0/node-v24.19.0-win-x64.zip" + +[[tools.pnpm]] +version = "11.22.0" +backend = "aqua:pnpm/pnpm" + +[tools.pnpm."platforms.linux-arm64"] +checksum = "sha256:f1426231f365bdfd46c15fa3d1211c3936ee2c4e557afd304f6c66dbf1b2a8bf" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-linux-arm64.tar.gz" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895951" +provenance = "github-attestations" + +[tools.pnpm."platforms.linux-arm64-musl"] +checksum = "sha256:6e53557024be48e59ab8760f9117c0e5c0e0a37ab420f71f302d86216970d28f" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-linux-arm64-musl.tar.gz" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895950" +provenance = "github-attestations" + +[tools.pnpm."platforms.linux-x64"] +checksum = "sha256:4c592fa410eb23b69691a9efb9bf21c87c15b3e9d88c6ec8acdd354a0eb8de71" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-linux-x64.tar.gz" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895948" +provenance = "github-attestations" + +[tools.pnpm."platforms.linux-x64-musl"] +checksum = "sha256:45425b06e747cbcaff4940d7b4a55e694645f15f9339dbf7f2601cfb21400545" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-linux-x64-musl.tar.gz" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895945" +provenance = "github-attestations" + +[tools.pnpm."platforms.macos-arm64"] +checksum = "sha256:2000dcc8f0718852c2806ba4dca1edaedf18a4a39264474d5a1c8fcee250adfd" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-darwin-arm64.tar.gz" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895947" +provenance = "github-attestations" + +[tools.pnpm."platforms.windows-x64"] +checksum = "sha256:1de83ad5100acfd2adb5c8bc6f8a428cee9ff4e365deff57c22bfc0cccaa4ddb" +url = "https://github.com/pnpm/pnpm/releases/download/v11.22.0/pnpm-win32-x64.zip" +url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/515895946" +provenance = "github-attestations" diff --git a/website/.vitepress/sidebar/latest.ts b/website/.vitepress/sidebar/latest.ts index 34cd8c3b..c7171547 100644 --- a/website/.vitepress/sidebar/latest.ts +++ b/website/.vitepress/sidebar/latest.ts @@ -16,6 +16,10 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ text: 'Guide', link: '/docs/guide' }, + { + text: 'Remote Taskfiles', + link: '/docs/remote-taskfiles' + }, { text: 'Reference', collapsed: true, diff --git a/website/src/latest/blog/any-variables.md b/website/src/latest/blog/any-variables.md index 66c51dde..3868fc63 100644 --- a/website/src/latest/blog/any-variables.md +++ b/website/src/latest/blog/any-variables.md @@ -5,7 +5,7 @@ description: and arrays! author: pd93 date: 2024-05-09 -tags: ['experiments', 'variables'] +tags: ['experiments', 'variables', 'new-features'] outline: deep editLink: false --- diff --git a/website/src/latest/blog/remote-taskfiles.md b/website/src/latest/blog/remote-taskfiles.md new file mode 100644 index 00000000..12c897e3 --- /dev/null +++ b/website/src/latest/blog/remote-taskfiles.md @@ -0,0 +1,139 @@ +--- +title: Remote Taskfiles +description: + Remote Taskfiles have been made generally available after nearly 3 years of + experimentation. +author: pd93 +date: 2026-08-18 +tags: ['experiments', 'remote', 'new-features'] +outline: deep +editLink: false +--- + +# Remote Taskfiles + + + +It's finally time! After nearly 3 years as an experiment, we're excited to +announce that today, [remote Taskfiles][remote-taskfiles] have been made +generally available. No more setting flags or config to enable it. It is enabled +by default and will continue to work seamlessly with your existing remote +taskfiles. + +[remote-taskfiles]: ../docs/remote-taskfiles.md + + + +## How did we get here? + +We'll be the first to admit that it's taken a long time to get this stable, but +there's good reason for it. Remote taskfiles was the most upvoted feature +request and we wanted to get it right. Experiments allowed us to iterate slowly +and implement feedback without having to worry about releasing something that we +couldn't take back later. + +We received a ton of feedback from you on the main issue thread and we're very +grateful for all the comments and suggestions as you've patiently waited for +something stable to land. + +No substantial changes have been made to the API recently and the stream of +feedback has now slowed, so we feel that the time is right to move forwards with +it. + +## How do I use it? + +We are aware that, despite the stability warnings, many of you are already using +remote taskfiles in production today. So, you'll be happy to hear that you do +not need to change anything going forwards! Once you've updated to the latest +version of Task (v3.53.0+), remote taskfiles will be enabled by default and you +can remove any config/flags that you previously used to enable it in your own +time. + +If you are still using an environment variable/flag/config to enable it, you may +see a small warning appear that lets you know that this is no longer necessary. + +For those that haven't used it before, here's a little taste of what you're now +able to do: + +### Using a remote Taskfile as an entrypoint + +By default, Task will look for one of the supported file names on your local +filesystem. If you want to use a remote file instead, you can pass its URI into +the `--taskfile`/`-t` flag just like you would to specify a different local +file. For example: + +::: code-group + +```shell [HTTP/HTTPS] +$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over HTTP] +$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over SSH] +$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +::: + +For testing purposes, we host an example Taskfile at +[taskfile.dev/Taskfile.yml](https://taskfile.dev/Taskfile.yml) that you can use +to try this out. This is useful to check that your installation of task is +working. + +```shell +$ task --taskfile https://taskfile.dev/Taskfile.yml +# Or for short +$ task -t https://taskfile.dev +``` + +### Including remote Taskfiles + +Including a remote file works exactly the same way that including a local file +does. You just need to replace the local path with a remote URI. Any tasks in +the remote Taskfile will be available to run from your main Taskfile. + +::: code-group + +```yaml [HTTP/HTTPS] +version: '3' + +includes: + my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +``` + +```yaml [Git over HTTP] +version: '3' + +includes: + my-remote-namespace: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +```yaml [Git over SSH] +version: '3' + +includes: + my-remote-namespace: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +::: + +```shell +$ task my-remote-namespace:hello +task: [hello] echo "Hello Task!" +Hello Task! +``` + +## Further reading + +To learn more, you can check out our +[brand new documentation for remote Taskfiles](../docs/remote-taskfiles.md). +Make sure you're running v3.53.0+ before you get started. diff --git a/website/src/latest/docs/changelog.md b/website/src/latest/docs/changelog.md index f7a0e280..c76438ce 100644 --- a/website/src/latest/docs/changelog.md +++ b/website/src/latest/docs/changelog.md @@ -8,6 +8,67 @@ editLink: false ::: v-pre +## v3.53.0 - 2026-08-18 + +- **Remote Taskfiles are now generally available!** This has been an + experimental feature for 3 years, but is now enabled by default. Massive + thanks to all those that contributed and gave feedback (too many to list + here). We've also given the + [Remote Taskfiles documentation](https://taskfile.dev/docs/remote-taskfiles) a + bit of a polish (#1317, #2906 by @pd93). +- Considerably improve performance of fingerprinting on large repositories + (monorepos). Fingerprinting is up to 86% faster and make up to 70% fewer + memory allocations on the more advanced scenarios. Benchmarks were added as + well. We're basically skipping work when not needed. (#2853, #2883 by + @Napolitain, #2884 by @Napolitain). +- Updated taskfile versions doc to mention when version checks were introduced + (#2184 by @jubr). +- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing + `http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin). +- Added support for `enum.ref` in `--interactive` prompts. Required vars using + `enum.ref` now show the selection list like static enums, instead of falling + back to free-form input (#2817 by @vmaerten). +- Further improved fingerprinting performance on large repositories: hashing + source files now reuses a single buffer, reducing memory allocations by ~98% + and wall-clock time by ~7% (#2925 by @vmaerten). +- Fixed the fingerprint variable (`{{.CHECKSUM}}`/`{{.TIMESTAMP}}`) ignoring a + `method:` set at the Taskfile level: the variable now follows the same method + resolution as the up-to-date check. Only the variable matching the effective + method is injected, so a task inheriting a Taskfile-level `method: timestamp` + gets `{{.TIMESTAMP}}` and no longer a `{{.CHECKSUM}}` (which now renders as an + empty string), and neither variable is injected when the effective method is + `none` (#2924 by @vmaerten). +- `includes.excludes` can now exclude a whole namespace: append `:*` to the + namespace name, e.g. `excludes: ['debug:*']`. Bare entries still match a + single task name exactly (#2300, #2959 by @xmxxc). +- Fixed `ref:` in `for: matrix:` and `enum:` only accepting literal lists. Refs + computed with template functions like `keys` or `splitList` no longer fail + with "must resolve to a list" (#2544, #2956 by @no-hup). +- Fixed the JSON schema rejecting `ignore_error` on a command inside a `for` + loop. Editors no longer flag a Taskfile that Task runs perfectly fine (#2044 + by @gokeefe-atb). +- Fixed the JSON schema rejecting more keys the Taskfile parser accepts: + `ignore_error` on a `task:` call, and `if`, `set` and `shopt` on a command + inside a `for` loop (#2967 by @vmaerten). +- Added a verbose log line for failed tasks. In `--verbose` mode, a task whose + command exits non-zero now reports `task: "" failed: ` instead of + stopping without a trace (#2240 by @Drino). +- Fixed pressing `Esc` at an interactive variable prompt not cancelling the run + (#2942 by @anilnatha). +- Added Nushell completions, available via `task --completion nu`. They complete + task names and aliases, every flag with its description, and the values of + `--completion`, `--output` and `--sort` (#2966 by @vmaerten). +- Added a per-command `timeout` that terminates a command once it exceeds the + given duration (Go duration syntax). It covers shell commands, task calls, + deferred commands, `deps` and the `if` condition, obeys `ignore_error`, and + reports exit code `124`. Callers that join a `run: once` or `when_changed` + task already running now honor their own `timeout`, and inherit that task's + failure instead of being told it succeeded (#1569, #2898 by @vmaerten). +- Fixed a pinned `checksum:` not being verified when a remote Taskfile came from + the cache (#2980 by @vmaerten). +- Load the sidebar data and titles/excerpts from the blog post markdown document + and its frontmatter on the website (#2981 by @pd93). + ## v3.52.0 - 2026-07-02 - Fixed --interactive prompts for required vars sometimes appearing in a random diff --git a/website/src/latest/docs/contributing.md b/website/src/latest/docs/contributing.md index 644706db..993f570b 100644 --- a/website/src/latest/docs/contributing.md +++ b/website/src/latest/docs/contributing.md @@ -160,16 +160,18 @@ Where you put a blog post decides when it goes out. A post that announces a feature belongs in `website/src/next/blog` alone: it ships with the release that carries the feature. A post that stands on its own - an announcement, a write-up about an already released feature - can be added to `website/src/latest/blog` as -well, and it goes live at the next deploy. Remember the sidebar entry in -`.vitepress/sidebar/`, which is split the same way. +well, and it goes live at the next deploy. Its sidebar entry comes from the +post's own frontmatter, so there is nothing else to update. Never edit an existing file under `website/src/latest`: `cmd/release` overwrites -that directory at every release, so the change would be silently lost. CI fails -a pull request that modifies one. Adding a file there is fine - that is how a -blog post gets published early - and so is editing the sidebars, which live -outside that directory. +that directory at every release, so the change would be silently lost. The same +goes for `.vitepress/sidebar/latest.ts`, which is promoted from `next.ts`. CI +fails a pull request that modifies either. Adding a file under +`website/src/latest` is fine - that is how a blog post gets published early. -To preview what taskfile.dev will look like, run `task website CHANNEL=latest`. +To preview what taskfile.dev will look like, run `task website:start:latest`. It +serves the `latest` channel on port 3002, so it can run next to `task website` +and the version selector switches between the two. ### Writing tests diff --git a/website/src/latest/docs/experiments/index.md b/website/src/latest/docs/experiments/index.md index 19da7a44..6ba48d89 100644 --- a/website/src/latest/docs/experiments/index.md +++ b/website/src/latest/docs/experiments/index.md @@ -93,11 +93,11 @@ Task. All experimental features start with a proposal in the form of a GitHub issue. If the maintainers decide that an issue has enough support and is a breaking change or is complex/controversial enough to require user feedback, then the -issue will be marked with the `status: proposal` label. At this point, the issue -becomes a proposal and a period of consultation begins. During this period, we -request that users provide feedback on the proposal and how it might effect -their use of Task. It is up to the discretion of the maintainers to decide how -long this period lasts. +issue's experiment status field will be set to `proposed`. At this point, the +issue becomes a proposal and a period of consultation begins. During this +period, we request that users provide feedback on the proposal and how it might +effect their use of Task. It is up to the discretion of the maintainers to +decide how long this period lasts. ### 2. Draft @@ -105,7 +105,7 @@ Once a proposal's consultation ends, a contributor may pick up the work and begin the initial implementation. Once a PR is opened, the maintainers will ensure that it meets the requirements for an experimental feature (i.e. flags are in the right format etc) and merge the feature. Once this code is released, -the status will be updated via the `status: draft` label. This indicates that an +the experiment status field will be updated to `draft`. This indicates that an implementation is now available for use in a release and the experiment is open for feedback. @@ -120,14 +120,14 @@ experimental features may be abandoned _at any time_. ### 3. Candidate Once an acceptable level of consensus has been reached by the community and -feedback/changes are less frequent/significant, the status may be updated via -the `status: candidate` label. This indicates that a proposal is _likely_ to +feedback/changes are less frequent/significant, the experiment status field will +be updated to `candidate`. This indicates that a proposal is _likely_ to accepted and will enter a period for final comments and minor changes. ### 4. Stable -Once a suitable amount of time has passed with no changes or feedback, an -experiment will be given the `status: stable` label. At this point, the +Once a suitable amount of time has passed with no changes or feedback, the +experiment status field will be updated to `stable`. At this point, the functionality will be treated like any other feature in Task and any changes _must_ be backward compatible. This allows users to migrate to the new functionality without having to worry about anything breaking in future @@ -136,13 +136,13 @@ version. ### 5. Released -When making a new major release of Task, all experiments marked as -`status: stable` will move to `status: released` and their behaviors will become -the new default in Task. Experiments in an earlier stage (i.e. not stable) -cannot be released and so will continue to be experiments in the new version. +When an experiment moves to a `released` status, it becomes the default behavior +and flags or config are no longer required to enable the feature. For +non-breaking changes, this will happen in a minor release. For breaking changes, +this will happen in a major release. ### Abandoned / Superseded -If an experiment is unsuccessful at any point then it will be given the -`status: abandoned` or `status: superseded` labels depending on which is more +If an experiment is unsuccessful at any point then the experiment status field +will be updated to `abandoned` or `superseded` depending on which is more suitable. These experiments will be removed from Task. diff --git a/website/src/latest/docs/experiments/remote-taskfiles.md b/website/src/latest/docs/experiments/remote-taskfiles.md index 9c031e1d..c242620b 100644 --- a/website/src/latest/docs/experiments/remote-taskfiles.md +++ b/website/src/latest/docs/experiments/remote-taskfiles.md @@ -1,505 +1,14 @@ --- -title: 'Remote Taskfiles (#1317)' description: Experimentation for using Taskfiles stored in remote locations outline: deep --- # Remote Taskfiles (#1317) -::: warning +The Remote Taskfiles experiment has now [been released][changelog] :tada:. To +learn more, you can read the [remote Taskfile docs][remote-taskfile-docs] or +check out our [blog post][blog-post]. -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. - -::: - -::: info - -To enable this experiment, set the environment variable: -`TASK_X_REMOTE_TASKFILES=1`. Check out -[our guide to enabling experiments](./index.md#enabling-experiments) for more -information. - -::: - -::: danger - -Never run remote Taskfiles from sources that you do not trust. - -::: - -This experiment allows you to use Taskfiles which are stored in remote -locations. This applies to both the root Taskfile (aka. Entrypoint) and also -when including Taskfiles. - -Task uses "nodes" to reference remote Taskfiles. There are a few different types -of node which you can use: - -::: code-group - -```text [HTTP/HTTPS] -https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml -``` - -```text [Git over HTTP] -https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -``` - -```text [Git over SSH] -git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -``` - -::: - -## Node Types - -### HTTP/HTTPS - -`https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml` - -This is the most basic type of remote node and works by downloading the file -from the specified URL. The file must be a valid Taskfile and can be of any -name. If a file is not found at the specified URL, Task will append each of the -supported file names in turn until it finds a valid file. If it still does not -find a valid Taskfile, an error is returned. - -### Git over HTTP - -`https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main` - -This type of node works by downloading the file from a Git repository over -HTTP/HTTPS. The first part of the URL is the base URL of the Git repository. -This is the same URL that you would use to clone the repo over HTTP. - -- You can optionally add the path to the Taskfile in the repository by appending - `//` to the URL. -- You can also optionally specify a branch or tag to use by appending - `?ref=` to the end of the URL. If you omit a reference, the default - branch will be used. - -### Git over SSH - -`git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main` - -This type of node works by downloading the file from a Git repository over SSH. -The first part of the URL is the user and base URL of the Git repository. This -is the same URL that you would use to clone the repo over SSH. - -To use Git over SSH, you need to make sure that your SSH agent has your private -SSH keys added so that they can be used during authentication. - -- You can optionally add the path to the Taskfile in the repository by appending - `//` to the URL. -- You can also optionally specify a branch or tag to use by appending - `?ref=` to the end of the URL. If you omit a reference, the default - branch will be used. - -Task has an example remote Taskfile in our repository that you can use for -testing and that we will use throughout this document: - -```yaml -version: '3' - -tasks: - default: - cmds: - - task: hello - - hello: - cmds: - - echo "Hello Task!" -``` - -## Specifying a remote entrypoint - -By default, Task will look for one of the supported file names on your local -filesystem. If you want to use a remote file instead, you can pass its URI into -the `--taskfile`/`-t` flag just like you would to specify a different local -file. For example: - -::: code-group - -```shell [HTTP/HTTPS] -$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml -task: [hello] echo "Hello Task!" -Hello Task! -``` - -```shell [Git over HTTP] -$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -task: [hello] echo "Hello Task!" -Hello Task! -``` - -```shell [Git over SSH] -$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -task: [hello] echo "Hello Task!" -Hello Task! -``` - -::: - -## Including remote Taskfiles - -Including a remote file works exactly the same way that including a local file -does. You just need to replace the local path with a remote URI. Any tasks in -the remote Taskfile will be available to run from your main Taskfile. - -::: code-group - -```yaml [HTTP/HTTPS] -version: '3' - -includes: - my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml -``` - -```yaml [Git over HTTP] -version: '3' - -includes: - my-remote-namespace: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -``` - -```yaml [Git over SSH] -version: '3' - -includes: - my-remote-namespace: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main -``` - -::: - -```shell -$ task my-remote-namespace:hello -task: [hello] echo "Hello Task!" -Hello Task! -``` - -### Authenticating using environment variables - -The Taskfile location is processed by the templating system, so you can -reference environment variables in your URL if you need to add authentication. -For example: - -```yaml -version: '3' - -includes: - my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml -``` - -## Special Variables - -The file-path [special variables](../reference/templating.md#file-paths) behave -differently when a Taskfile is loaded from a remote source, because there is no -local file or directory that corresponds 1:1 to the Taskfile: - -| Variable | Value when loaded remotely | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `TASKFILE` / `ROOT_TASKFILE` | The original URL, unchanged | -| `TASKFILE_DIR` / `ROOT_DIR` | Empty string — a directory variable cannot point to a URL | -| `TASK_DIR` | Resolved against `USER_WORKING_DIR` (relative `dir:` → joined with `USER_WORKING_DIR`, empty `dir:` → `USER_WORKING_DIR`, absolute `dir:` → kept as-is) | - -If a remote Taskfile includes a local Taskfile (or vice-versa), each variable -reflects the source of the Taskfile it refers to. - -## Security - -### Automatic checksums - -Running commands from sources that you do not control is always a potential -security risk. For this reason, we have added some automatic checks when using -remote Taskfiles: - -1. When running a task from a remote Taskfile for the first time, Task will - print a warning to the console asking you to check that you are sure that you - trust the source of the Taskfile. If you do not accept the prompt, then Task - will exit with code `104` (not trusted) and nothing will run. If you accept - the prompt, the remote Taskfile will run and further calls to the remote - Taskfile will not prompt you again. -2. Whenever you run a remote Taskfile, Task will create and store a checksum of - the file that you are running. If the checksum changes, then Task will print - another warning to the console to inform you that the contents of the remote - file has changed. If you do not accept the prompt, then Task will exit with - code `104` (not trusted) and nothing will run. If you accept the prompt, the - checksum will be updated and the remote Taskfile will run. - -Sometimes you need to run Task in an environment that does not have an -interactive terminal, so you are not able to accept a prompt. In these cases you -are able to tell task to accept these prompts automatically by using the `--yes` -flag or the `--trusted-hosts` flag. The `--trusted-hosts` flag allows you to -specify trusted -hosts for remote Taskfiles, while `--yes` applies to all prompts in Task. You -can also configure trusted hosts in your [taskrc configuration](#trusted-hosts) using -`remote.trusted-hosts`. Before enabling automatic trust, you should: - -1. Be sure that you trust the source and contents of the remote Taskfile. -2. Consider using a pinned version of the remote Taskfile (e.g. A link - containing a commit hash) to prevent Task from automatically accepting a - prompt that says a remote Taskfile has changed. - -### Manual checksum pinning - -Alternatively, if you expect the contents of your remote files to be a constant -value, you can pin the checksum of the included file instead: - -```yaml -version: '3' - -includes: - included: - taskfile: https://taskfile.dev - checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9 -``` - -This will disable the automatic checksum prompts discussed above. However, if -the checksums do not match, Task will exit immediately with an error. When -setting this up for the first time, you may not know the correct value of the -checksum. There are a couple of ways you can obtain this: - -1. Add the include normally without the `checksum` key. The first time you run - the included Taskfile, a `.task/remote` temporary directory is created. Find - the correct set of files for your included Taskfile and open the file that - ends with `.checksum`. You can copy the contents of this file and paste it - into the `checksum` key of your include. This method is safest as it allows - you to inspect the downloaded Taskfile before you pin it. -2. Alternatively, add the include with a temporary random value in the - `checksum` key. When you try to run the Taskfile, you will get an error that - will report the incorrect expected checksum and the actual checksum. You can - copy the actual checksum and replace your temporary random value. - -### TLS - -Task currently supports both `http` and `https` URLs. However, the `http` -requests will not execute by default unless you run the task with the -`--insecure` flag. This is to protect you from accidentally running a remote -Taskfile that is downloaded via an unencrypted connection. Sources that are not -protected by TLS are vulnerable to man-in-the-middle attacks and should be -avoided unless you know what you are doing. - -#### Custom Certificates - -If your remote Taskfiles are hosted on a server that uses a custom CA -certificate (e.g., a corporate internal server), you can specify the CA -certificate using the `--cacert` flag: - -```shell -task --taskfile https://internal.example.com/Taskfile.yml --cacert /path/to/ca.crt -``` - -For servers that require client certificate authentication (mTLS), you can -provide a client certificate and key: - -```shell -task --taskfile https://secure.example.com/Taskfile.yml \ - --cert /path/to/client.crt \ - --cert-key /path/to/client.key -``` - -::: warning - -Encrypted private keys are not currently supported. If your key is encrypted, -you must decrypt it first: - -```shell -openssl rsa -in encrypted.key -out decrypted.key -``` - -::: - -These options can also be configured in the [configuration file](#configuration). - -## Caching & Running Offline - -Whenever you run a remote Taskfile, the latest copy will be downloaded from the -internet and cached locally. This cached file will be used for all future -invocations of the Taskfile until the cache expires. Once it expires, Task will -download the latest copy of the file and update the cache. By default, the cache -is set to expire immediately. This means that Task will always fetch the latest -version. However, the cache expiry duration can be modified by setting the -`--expiry` flag. - -If for any reason you lose access to the internet or you are running Task in -offline mode (via the `--offline` flag or `TASK_OFFLINE` environment variable), -Task will run the any available cached files _even if they are expired_. This -means that you should never be stuck without the ability to run your tasks as -long as you have downloaded a remote Taskfile at least once. - -By default, Task will timeout requests to download remote files after 10 seconds -and look for a cached copy instead. This timeout can be configured by setting -the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will -set the timeout to 5 seconds. - -By default, the cache is stored in the Task temp directory (`.task`). You can -override the location of the cache by using the `--remote-cache-dir` flag, the -`remote.cache-dir` option in your [configuration file](#cache-dir), or the -`TASK_REMOTE_DIR` environment variable. This way, you can share the cache -between different projects. - -You can force Task to ignore the cache and download the latest version by using -the `--download` flag. - -You can use the `--clear-cache` flag to clear all cached remote files. - -## Configuration - -This experiment adds a new `remote` section to the -[configuration file](../reference/config.md). - -- **Type**: `object` -- **Description**: Remote configuration settings for handling remote Taskfiles - -```yaml -remote: - insecure: false - offline: false - timeout: "30s" - cache-expiry: "24h" - cache-dir: ~/.task - trusted-hosts: - - github.com - - gitlab.com - cacert: "" - cert: "" - cert-key: "" -``` - -#### `insecure` - -- **Type**: `boolean` -- **Default**: `false` -- **Description**: Allow insecure connections when fetching remote Taskfiles -- **CLI equivalent**: `--insecure` -- **Environment variable**: `TASK_REMOTE_INSECURE` - -```yaml -remote: - insecure: true -``` - -#### `offline` - -- **Type**: `boolean` -- **Default**: `false` -- **Description**: Work in offline mode, preventing remote Taskfile fetching -- **CLI equivalent**: `--offline` -- **Environment variable**: `TASK_REMOTE_OFFLINE` - -```yaml -remote: - offline: true -``` - -#### `timeout` - -- **Type**: `string` -- **Default**: 10s -- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` -- **Description**: Timeout duration for remote operations (e.g., '30s', '5m') -- **CLI equivalent**: `--timeout` -- **Environment variable**: `TASK_REMOTE_TIMEOUT` - -```yaml -remote: - timeout: "1m" -``` - -#### `cache-expiry` - -- **Type**: `string` -- **Default**: 0s (no cache) -- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` -- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h', - '24h') -- **CLI equivalent**: `--expiry` -- **Environment variable**: `TASK_REMOTE_CACHE_EXPIRY` - -```yaml -remote: - cache-expiry: "6h" -``` - -#### `cache-dir` - -- **Type**: `string` -- **Default**: `.task` -- **Description**: Directory where remote Taskfiles are cached. Can be an - absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory. -- **CLI equivalent**: `--remote-cache-dir` -- **Environment variable**: `TASK_REMOTE_CACHE_DIR` - -```yaml -remote: - cache-dir: ~/.task -``` - -#### `trusted-hosts` - -- **Type**: `array of strings` -- **Default**: `[]` (empty list) -- **Description**: List of trusted hosts for remote Taskfiles. Hosts in this - list will not prompt for confirmation when downloading Taskfiles -- **CLI equivalent**: `--trusted-hosts` -- **Environment variable**: `TASK_REMOTE_TRUSTED_HOSTS` (comma-separated) - -```yaml -remote: - trusted-hosts: - - github.com - - gitlab.com - - raw.githubusercontent.com - - example.com:8080 -``` - -Hosts in the trusted hosts list will automatically be trusted without prompting for -confirmation when they are first downloaded or when their checksums change. The -host matching includes the port if specified in the URL. Use with caution and -only add hosts you fully trust. - -You can also specify trusted hosts via the command line: - -```shell -# Trust specific host for this execution -task --trusted-hosts github.com -t https://github.com/user/repo.git//Taskfile.yml - -# Trust multiple hosts (comma-separated) -task --trusted-hosts github.com,gitlab.com -t https://github.com/user/repo.git//Taskfile.yml - -# Trust a host with a specific port -task --trusted-hosts example.com:8080 -t https://example.com:8080/Taskfile.yml -``` - -#### `cacert` - -- **Type**: `string` -- **Default**: `""` -- **Description**: Path to a custom CA certificate file for TLS verification - -```yaml -remote: - cacert: "/path/to/ca.crt" -``` - -#### `cert` - -- **Type**: `string` -- **Default**: `""` -- **Description**: Path to a client certificate file for mTLS authentication - -```yaml -remote: - cert: "/path/to/client.crt" -``` - -#### `cert-key` - -- **Type**: `string` -- **Default**: `""` -- **Description**: Path to the client certificate private key file - -```yaml -remote: - cert-key: "/path/to/client.key" -``` +[changelog]: ../changelog.md#v3511---2026-05-16 +[remote-taskfile-docs]: ../remote-taskfiles.md +[blog-post]: ../../blog/remote-taskfiles diff --git a/website/src/latest/docs/guide.md b/website/src/latest/docs/guide.md index d5ca4622..38e0caf7 100644 --- a/website/src/latest/docs/guide.md +++ b/website/src/latest/docs/guide.md @@ -91,7 +91,7 @@ tasks: ::: -### Reading a Taskfile from stdin +### Running a Taskfile from stdin Taskfile also supports reading from stdin. This is useful if you are generating Taskfiles dynamically and don't want write them to disk. To tell task to read @@ -104,6 +104,41 @@ task -t - < ./Taskfile.yml cat ./Taskfile.yml | task -t - ``` +### Running a remote Taskfile + +::: danger + +Never run remote Taskfiles from sources that you do not trust. + +::: + +It is possible to directly run a Taskfile from a remote source via HTTP(S) or +Git by using the `--taskfile`/`-t` flag. This is useful if you want to reuse a +set of tasks in multiple projects. For more information, take a look at our +[remote Taskfiles documentation](./remote-taskfiles.md). + +::: code-group + +```shell [HTTP/HTTPS] +$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over HTTP] +$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over SSH] +$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +::: + ## Environment variables ### Task @@ -248,6 +283,26 @@ the `DockerTasks.yml` file. Relative paths are resolved relative to the directory containing the including Taskfile. +### Remote Taskfiles + +::: danger + +Never run remote Taskfiles from sources that you do not trust. + +::: + +It is possible to include a Taskfile from a remote source via HTTP(S) or Git. +This is useful if you want to reuse a set of tasks in multiple projects. For +more information, take a look at our +[remote Taskfiles documentation](./remote-taskfiles.md). + +```yaml +version: '3' + +includes: + my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +``` + ### OS-specific Taskfiles You can include OS-specific Taskfiles by using a templating function: @@ -412,8 +467,10 @@ You can do this by using the ### Exclude tasks from being included -You can exclude tasks from being included by using the `excludes` option. This -option takes the list of tasks to be excluded from this include. +You can exclude tasks or entire namespaces from being included by using the +`excludes` option. This option takes the list of tasks or namespaces to be +excluded from this include. Task names are matched exactly. To exclude a +namespace, append `:*` to its name. ::: code-group @@ -423,7 +480,7 @@ version: '3' includes: included: taskfile: ./Included.yml - excludes: [foo] + excludes: [foo, 'internal:*', 'debug:*'] ``` ```yaml [Included.yml] @@ -432,11 +489,14 @@ version: '3' tasks: foo: echo "Foo" bar: echo "Bar" + internal:setup: echo "Internal setup" + debug:status: echo "Debug status" ``` ::: -`task included:foo` will throw an error because the `foo` task is excluded but +`task included:foo`, `task included:internal:setup`, and +`task included:debug:status` will throw errors because they are excluded, but `task included:bar` will work and display `Bar`. It's compatible with the `flatten` option. @@ -950,7 +1010,8 @@ You can use `--force` or `-f` if you want to force a task to run even when up-to-date. Also, `task --status [tasks]...` will exit with a non-zero -[exit code](/docs/reference/cli#exit-codes) if any of the tasks are not up-to-date. +[exit code](/docs/reference/cli#exit-codes) if any of the tasks are not +up-to-date. `status` can be combined with the [fingerprinting](#by-fingerprinting-locally-generated-files-and-their-sources) @@ -1034,8 +1095,8 @@ tasks: The `if` attribute allows you to conditionally skip tasks or commands based on a shell command's exit code. Unlike `preconditions` which fail and stop execution, -`if` simply skips the task or command when the condition is not met and continues -with the rest of the Taskfile. +`if` simply skips the task or command when the condition is not met and +continues with the rest of the Taskfile. #### Task-level `if` @@ -1071,9 +1132,9 @@ tasks: #### Using templates in `if` conditions -You can use Go template expressions in `if` conditions. Template expressions like -`{{eq .VAR "value"}}` evaluate to `true` or `false`, which are valid shell -commands (`true` exits with 0, `false` exits with 1): +You can use Go template expressions in `if` conditions. Template expressions +like `{{eq .VAR "value"}}` evaluate to `true` or `false`, +which are valid shell commands (`true` exits with 0, `false` exits with 1): ```yaml version: '3' @@ -1081,7 +1142,7 @@ version: '3' tasks: conditional: vars: - ENABLE_FEATURE: "true" + ENABLE_FEATURE: 'true' cmds: - cmd: echo "Feature is enabled" if: '{{eq .ENABLE_FEATURE "true"}}' @@ -1091,7 +1152,8 @@ tasks: #### Using `if` with `for` loops -When used inside a `for` loop, the `if` condition is evaluated for each iteration: +When used inside a `for` loop, the `if` condition is evaluated for each +iteration: ```yaml version: '3' @@ -1113,11 +1175,11 @@ processing c #### `if` vs `preconditions` -| Aspect | `if` | `preconditions` | -|--------|------|-----------------| -| On failure | Skips (continues) | Fails (stops) | -| Message | Only in verbose mode | Always shown | -| Use case | "Run if possible" | "Must be true" | +| Aspect | `if` | `preconditions` | +| ---------- | -------------------- | --------------- | +| On failure | Skips (continues) | Fails (stops) | +| Message | Only in verbose mode | Always shown | +| Use case | "Run if possible" | "Must be true" | Use `if` when you want optional conditional execution that shouldn't stop the workflow. Use `preconditions` when the condition must be met for the task to @@ -1347,8 +1409,8 @@ $ task deploy Deploying 1.0.0 to prod ``` -If the variable is already set (via CLI, environment, or Taskfile), no prompt -is shown: +If the variable is already set (via CLI, environment, or Taskfile), no prompt is +shown: ```shell $ task deploy ENVIRONMENT=prod VERSION=1.0.0 @@ -1648,8 +1710,8 @@ in logs, but is **not a substitute** for proper secret management practices. - ❌ Secrets in command output (stdout/stderr) - ❌ Secret values copied into derived (non-secret) variables -Always use proper secret management tools (HashiCorp Vault, AWS Secrets -Manager, etc.) for production environments. +Always use proper secret management tools (HashiCorp Vault, AWS Secrets Manager, +etc.) for production environments. ::: @@ -1777,7 +1839,7 @@ tasks: If you use dotenv files, add them to `.gitignore`: ```yaml - dotenv: ['.env.local'] # Load from .env.local (in .gitignore) + dotenv: ['.env.local'] # Load from .env.local (in .gitignore) ``` ::: @@ -1854,8 +1916,7 @@ tasks: matrix: OS: ['windows', 'linux', 'darwin'] ARCH: ['amd64', 'arm64'] - cmd: - echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" + cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" ``` This will output: @@ -1887,8 +1948,7 @@ tasks: ref: .OS_VAR ARCH: ref: .ARCH_VAR - cmd: - echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" + cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" ``` ### Looping over your task's sources or generated files @@ -1933,8 +1993,8 @@ files that match that glob. Paths will always be returned as paths relative to the task directory. If you need to convert this to an absolute path, you can use the built-in `joinPath` function. There are some -[special variables](/docs/reference/templating#special-variables) that you may find -useful for this. +[special variables](/docs/reference/templating#special-variables) that you may +find useful for this. ::: code-group @@ -2211,8 +2271,9 @@ $ task start:foo:3 Starting foo with 3 replicas ``` -Using wildcards with aliases -Wildcards also work with aliases. If a task has an alias, you can use the alias name with wildcards to capture arguments. For example: +Using wildcards with aliases Wildcards also work with aliases. If a task has an +alias, you can use the alias name with wildcards to capture arguments. For +example: ```yaml version: '3' @@ -2221,11 +2282,12 @@ tasks: start:*: aliases: [run:*] vars: - SERVICE: "{{index .MATCH 0}}" + SERVICE: '{{index .MATCH 0}}' cmds: - echo "Running {{.SERVICE}}" ``` -In this example, you can call the task using the alias run:*: + +In this example, you can call the task using the alias run:\*: ```shell $ task run:foo @@ -2276,8 +2338,8 @@ commands are executed in the reverse order if you schedule multiple of them. ::: A special variable `.EXIT_CODE` is exposed when a command exited with a non-zero -[exit code](/docs/reference/cli#exit-codes). You can check its presence to know if -the task completed successfully or not: +[exit code](/docs/reference/cli#exit-codes). You can check its presence to know +if the task completed successfully or not: ```yaml version: '3' @@ -2478,8 +2540,8 @@ tasks: ``` Warning prompts are called before executing a task. If a prompt is denied Task -will exit with [exit code](/docs/reference/cli#exit-codes) 205. If approved, Task -will continue as normal. +will exit with [exit code](/docs/reference/cli#exit-codes) 205. If approved, +Task will continue as normal. ```shell ❯ task example @@ -2873,8 +2935,8 @@ if called by another task, either directly or as a dependency. The watcher can misbehave in certain scenarios, in particular for long-running servers. There is a [known bug](https://github.com/go-task/task/issues/160) where child processes of the running might not be killed appropriately. It's -advised to avoid running commands as `go run` and prefer `go build [...] && -./binary` instead. +advised to avoid running commands as `go run` and prefer +`go build [...] && ./binary` instead. If you are having issues, you might want to try tools specifically designed for live-reloading, like [Air](https://github.com/air-verse/air/). Also, be sure to diff --git a/website/src/latest/docs/installation.md b/website/src/latest/docs/installation.md index a983dc0e..05658d04 100644 --- a/website/src/latest/docs/installation.md +++ b/website/src/latest/docs/installation.md @@ -75,7 +75,7 @@ apk add task ### [Homebrew](https://brew.sh) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) {#homebrew} Task is available via our official Homebrew tap -[[source](https://github.com/go-task/homebrew-tap/blob/main/Formula/go-task.rb)]: +[[source](https://github.com/go-task/homebrew-tap/blob/main/Casks/go-task.rb)]: ```shell brew install go-task/tap/go-task @@ -407,6 +407,16 @@ task --completion fish | source Invoke-Expression (&task --completion powershell | Out-String) ``` +```nu [nushell] +# ~/.config/nushell/config.nu +# +# Nushell cannot source a script from stdin, so the script is saved where +# Nushell auto-loads it at startup. Autoload directories are read after +# config.nu, so the completions become available in the next shell. +mkdir ($nu.data-dir | path join "vendor/autoload") +task --completion nu | save --force ($nu.data-dir | path join "vendor/autoload/task-completions.nu") +``` + ::: ### Option 2. Copy the script to your shell's completions directory @@ -428,6 +438,10 @@ task --completion zsh > /usr/local/share/zsh/site-functions/_task task --completion fish > ~/.config/fish/completions/task.fish ``` +```nu [nushell] +task --completion nu | save --force ($nu.data-dir | path join "vendor/autoload/task-completions.nu") +``` + ::: ### Zsh customization @@ -446,3 +460,29 @@ canonical task names, add the `show-aliases` zstyle: ```shell zstyle ':completion:*:*:task:*' show-aliases false ``` + +### Nushell caveats + +Nushell cannot source a script from stdin, so both options above write the script +to an autoload directory. Option 1 rewrites it at every startup, which keeps it +in sync with the installed version of Task — the refreshed completions are picked +up by the next shell. With option 2, re-run the command after upgrading Task. + +The completions are attached to an `extern "task"` declaration, which Nushell +requires to be static. Three consequences are worth knowing: + +- The experimental flags (`--force-all`, `--download`, `--offline`, …) are always + offered, even when the corresponding experiment is disabled. Their description + is prefixed with the experiment name, and `task --experiments` lists the ones + that are enabled. +- Passing a value to a boolean flag with `=` does not work: Nushell forwards + `--color=false` as two arguments, so Task reads `false` as a task name. Use + `NO_COLOR=1`, or bypass the declaration with `^task --color=false`. +- `TASK_EXE` selects the executable that is run, but not the command name the + completions are attached to, which is always `task`. For a renamed executable, + alias it instead: + +```nu +use ($nu.data-dir | path join "vendor/autoload/task-completions.nu") * +alias go-task = task +``` diff --git a/website/src/latest/docs/reference/cli.md b/website/src/latest/docs/reference/cli.md index 47b5c7d1..11a72bf6 100644 --- a/website/src/latest/docs/reference/cli.md +++ b/website/src/latest/docs/reference/cli.md @@ -128,7 +128,8 @@ Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name. - **Config equivalent**: [`disable-fuzzy`](./config.md#disable-fuzzy) -- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) +- **Environment variable**: + [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) ```bash task buidl --disable-fuzzy @@ -180,7 +181,8 @@ task test lint --parallel Limit the number of concurrent tasks. Zero means unlimited. - **Config equivalent**: [`concurrency`](./config.md#concurrency) -- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency) +- **Environment variable**: + [`TASK_CONCURRENCY`](./environment.md#task-concurrency) ```bash task test --concurrency 4 @@ -248,7 +250,8 @@ task test --output group Message template to print before grouped output. -- **Environment variable**: [`TASK_OUTPUT_GROUP_BEGIN`](./environment.md#task-output-group-begin) +- **Environment variable**: + [`TASK_OUTPUT_GROUP_BEGIN`](./environment.md#task-output-group-begin) ```bash task test --output group --output-group-begin "::group::{{.TASK}}" @@ -258,7 +261,8 @@ task test --output group --output-group-begin "::group::{{.TASK}}" Message template to print after grouped output. -- **Environment variable**: [`TASK_OUTPUT_GROUP_END`](./environment.md#task-output-group-end) +- **Environment variable**: + [`TASK_OUTPUT_GROUP_END`](./environment.md#task-output-group-end) ```bash task test --output group --output-group-end "::endgroup::" @@ -268,7 +272,8 @@ task test --output group --output-group-end "::endgroup::" Only show command output on non-zero exit codes. -- **Environment variable**: [`TASK_OUTPUT_GROUP_ERROR_ONLY`](./environment.md#task-output-group-error-only) +- **Environment variable**: + [`TASK_OUTPUT_GROUP_ERROR_ONLY`](./environment.md#task-output-group-error-only) ```bash task test --output group --output-group-error-only @@ -351,7 +356,8 @@ task build --watch --interval 1s Automatically answer "yes" to all prompts. -- **Environment variable**: [`TASK_ASSUME_YES`](./environment.md#task-assume-yes) +- **Environment variable**: + [`TASK_ASSUME_YES`](./environment.md#task-assume-yes) ```bash task deploy --yes @@ -366,12 +372,69 @@ Task automatically detects non-TTY environments (like CI pipelines) and skips prompts. This flag can also be set in `.taskrc.yml` to enable prompts by default. -- **Environment variable**: [`TASK_INTERACTIVE`](./environment.md#task-interactive) +- **Environment variable**: + [`TASK_INTERACTIVE`](./environment.md#task-interactive) ```bash task deploy --interactive ``` +### Remote + +The following flags are used to control the behavior of +[remote Taskfiles](../remote-taskfiles.md). + +#### `--insecure` + +Allow insecure connections when fetching remote Taskfiles. + +#### `--offline` + +Work in offline mode, preventing remote Taskfile fetching. + +#### `--download` + +Forces task to download remote Taskfiles and ignore any cached versions. + +#### `--timeout` + +Timeout duration for remote operations (e.g., '30s', '5m'). + +#### `--clear-cache` + +Wipe the cache of remote Taskfiles and checksums. + +#### `--expiry` + +Cache expiry duration for remote Taskfiles (e.g., '1h', '24h'). + +#### `--remote-cache-dir` + +Directory where remote Taskfiles are cached. Can be an absolute path (e.g., +`/var/cache/task`) or relative to the Taskfile directory. + +#### `--trusted-hosts` + +List of (comma-separated) trusted hosts for remote Taskfiles. Hosts in this list +will not prompt for confirmation when downloading Taskfiles. + +Hosts in the trusted hosts list will automatically be trusted without prompting +for confirmation when they are first downloaded or when their checksums change. +The host matching includes the port if specified in the URL. Use with caution +and only add hosts you fully trust. + +#### `--cacert` + +Path to a custom CA certificate file for TLS verification. + +#### `--cert` + +Path to a client certificate file for mTLS authentication. + +#### `--cert-key` + +Path to the client certificate private key file. + ## Exit Codes Task uses specific exit codes to indicate different types of errors: diff --git a/website/src/latest/docs/reference/config.md b/website/src/latest/docs/reference/config.md index cf58ae8f..ff694117 100644 --- a/website/src/latest/docs/reference/config.md +++ b/website/src/latest/docs/reference/config.md @@ -108,7 +108,8 @@ silent: true - **Type**: `boolean` - **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) - **Environment variable**: [`TASK_COLOR`](./environment.md#task-color) @@ -120,9 +121,11 @@ color: false - **Type**: `boolean` - **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) -- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) +- **Environment variable**: + [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) ```yaml disable-fuzzy: true @@ -134,7 +137,8 @@ disable-fuzzy: true - **Minimum**: `1` - **Description**: Number of concurrent tasks to run - **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number) -- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency) +- **Environment variable**: + [`TASK_CONCURRENCY`](./environment.md#task-concurrency) ```yaml concurrency: 4 @@ -158,8 +162,8 @@ failfast: true - **Default**: `false` - **Description**: Prompt for missing required variables instead of failing. When enabled, Task will display an interactive prompt for any missing required - variable. Requires a TTY. Task automatically detects non-TTY environments - (CI pipelines, etc.) and skips prompts. + variable. Requires a TTY. Task automatically detects non-TTY environments (CI + pipelines, etc.) and skips prompts. - **CLI equivalent**: [`--interactive`](./cli.md#--interactive) ```yaml @@ -178,6 +182,157 @@ interactive: true temp-dir: .task ``` +### `remote` + +- **Type**: `object` +- **Description**: Remote configuration settings for handling + [remote Taskfiles](../remote-taskfiles.md). + +#### `remote.insecure` + +- **Type**: `boolean` +- **Default**: `false` +- **Description**: Allow insecure connections when fetching remote Taskfiles +- **CLI equivalent**: `--insecure` +- **Environment variable**: + [`TASK_REMOTE_INSECURE`](./environment.md#task-remote-insecure) + +```yaml +remote: + insecure: true +``` + +#### `remote.offline` + +- **Type**: `boolean` +- **Default**: `false` +- **Description**: Work in offline mode, preventing remote Taskfile fetching +- **CLI equivalent**: `--offline` +- **Environment variable**: + [`TASK_REMOTE_OFFLINE`](./environment.md#task-remote-offline) + +```yaml +remote: + offline: true +``` + +#### `remote.timeout` + +- **Type**: `string` +- **Default**: 10s +- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` +- **Description**: Timeout duration for remote operations (e.g., '30s', '5m') +- **CLI equivalent**: `--timeout` +- **Environment variable**: + [`TASK_REMOTE_TIMEOUT`](./environment.md#task-remote-timeout) + +```yaml +remote: + timeout: '1m' +``` + +#### `remote.cache-expiry` + +- **Type**: `string` +- **Default**: 0s (no cache) +- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$` +- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h', + '24h') +- **CLI equivalent**: `--expiry` +- **Environment variable**: + [`TASK_REMOTE_CACHE_EXPIRY`](./environment.md#task-remote-cache-expiry) + +```yaml +remote: + cache-expiry: '6h' +``` + +#### `remote.cache-dir` + +- **Type**: `string` +- **Default**: `.task` +- **Description**: Directory where remote Taskfiles are cached. Can be an + absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory. +- **CLI equivalent**: `--remote-cache-dir` +- **Environment variable**: + [`TASK_REMOTE_CACHE_DIR`](./environment.md#task-remote-cache-dir) + +```yaml +remote: + cache-dir: ~/.task +``` + +#### `remote.trusted-hosts` + +- **Type**: `array of strings` +- **Default**: `[]` (empty list) +- **Description**: List of trusted hosts for remote Taskfiles. Hosts in this + list will not prompt for confirmation when downloading Taskfiles +- **CLI equivalent**: `--trusted-hosts` +- **Environment variable**: + [`TASK_REMOTE_TRUSTED_HOSTS`](./environment.md#task-remote-trusted-hosts) + (comma-separated) + +```yaml +remote: + trusted-hosts: + - github.com + - gitlab.com + - raw.githubusercontent.com + - example.com:8080 +``` + +Hosts in the trusted hosts list will automatically be trusted without prompting +for confirmation when they are first downloaded or when their checksums change. +The host matching includes the port if specified in the URL. Use with caution +and only add hosts you fully trust. + +You can also specify trusted hosts via the command line: + +```shell +# Trust specific host for this execution +task --trusted-hosts github.com -t https://github.com/user/repo.git//Taskfile.yml + +# Trust multiple hosts (comma-separated) +task --trusted-hosts github.com,gitlab.com -t https://github.com/user/repo.git//Taskfile.yml + +# Trust a host with a specific port +task --trusted-hosts example.com:8080 -t https://example.com:8080/Taskfile.yml +``` + +#### `remote.cacert` + +- **Type**: `string` +- **Default**: `""` +- **Description**: Path to a custom CA certificate file for TLS verification + +```yaml +remote: + cacert: '/path/to/ca.crt' +``` + +#### `remote.cert` + +- **Type**: `string` +- **Default**: `""` +- **Description**: Path to a client certificate file for mTLS authentication + +```yaml +remote: + cert: '/path/to/client.crt' +``` + +#### `remote.cert-key` + +- **Type**: `string` +- **Default**: `""` +- **Description**: Path to the client certificate private key file + +```yaml +remote: + cert-key: '/path/to/client.key' +``` + ## Example Configuration Here's a complete example of a `.taskrc.yml` file with all available options: @@ -190,8 +345,20 @@ color: true disable-fuzzy: false concurrency: 2 temp-dir: .task +remote: + insecure: false + offline: false + timeout: '30s' + cache-expiry: '24h' + cache-dir: ~/.task + trusted-hosts: + - github.com + - gitlab.com + cacert: '' + cert: '' + cert-key: '' # Enable experimental features experiments: - REMOTE_TASKFILES: 1 + GENTLE_FORCE: 1 ``` diff --git a/website/src/latest/docs/reference/environment.md b/website/src/latest/docs/reference/environment.md index e5fdf42a..87bc29c7 100644 --- a/website/src/latest/docs/reference/environment.md +++ b/website/src/latest/docs/reference/environment.md @@ -20,7 +20,8 @@ their configuration file equivalents. ## 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. +variables. The priority order is: CLI flags > environment variables > config +files > defaults. ### `TASK_VERBOSE` @@ -67,7 +68,8 @@ variables. The priority order is: CLI flags > environment variables > config fil - **Type**: `boolean` (`true`, `false`, `1`, `0`) - **Default**: `false` -- **Description**: Compiles and prints tasks in the order that they would be run, without executing them +- **Description**: Compiles and prints tasks in the order that they would be + run, without executing them ### `TASK_ASSUME_YES` @@ -92,14 +94,16 @@ variables. The priority order is: CLI flags > environment variables > config fil - **Type**: `string` - **Description**: Message template to print before a task's grouped output. Only applies when the output style is `group`. -- **CLI equivalent**: [`--output-group-begin`](./cli.md#--output-group-begin-template) +- **CLI equivalent**: + [`--output-group-begin`](./cli.md#--output-group-begin-template) ### `TASK_OUTPUT_GROUP_END` - **Type**: `string` -- **Description**: Message template to print after a task's grouped output. - Only applies when the output style is `group`. -- **CLI equivalent**: [`--output-group-end`](./cli.md#--output-group-end-template) +- **Description**: Message template to print after a task's grouped output. Only + applies when the output style is `group`. +- **CLI equivalent**: + [`--output-group-end`](./cli.md#--output-group-end-template) ### `TASK_OUTPUT_GROUP_ERROR_ONLY` @@ -107,7 +111,8 @@ variables. The priority order is: CLI flags > environment variables > config fil - **Default**: `false` - **Description**: Swallow output from successful tasks. Only applies when the output style is `group`. -- **CLI equivalent**: [`--output-group-error-only`](./cli.md#--output-group-error-only) +- **CLI equivalent**: + [`--output-group-error-only`](./cli.md#--output-group-error-only) ### `TASK_TEMP_DIR` @@ -118,16 +123,64 @@ Taskfile, not the working directory. Defaults to: `./.task`. ### `TASK_CORE_UTILS` -This env controls whether the Bash interpreter will use its own -core utilities implemented in Go, or the ones available in the system. -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 -enabled by default on all platforms in the future. +This env controls whether the Bash interpreter will use its own core utilities +implemented in Go, or the ones available in the system. 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 enabled by default on all +platforms in the future. ### `FORCE_COLOR` Force color output usage. +## Remote Taskfile Variables + +The following variables are used to control the behavior of +[remote Taskfiles](../remote-taskfiles.md). + +### `TASK_REMOTE_INSECURE` + +Allow insecure connections when fetching remote Taskfiles. + +### `TASK_REMOTE_OFFLINE` + +Work in offline mode, preventing remote Taskfile fetching. + +### `TASK_REMOTE_TIMEOUT` + +Timeout duration for remote operations (e.g., '30s', '5m'). + +### `TASK_REMOTE_CACHE_EXPIRY` + +Cache expiry duration for remote Taskfiles (e.g., '1h', '24h'). + +### `TASK_REMOTE_CACHE_DIR` + +Directory where remote Taskfiles are cached. Can be an absolute path (e.g., +`/var/cache/task`) or relative to the Taskfile directory. + +### `TASK_REMOTE_TRUSTED_HOSTS` + +List of (comma-separated) trusted hosts for remote Taskfiles. Hosts in this list +will not prompt for confirmation when downloading Taskfiles. + +Hosts in the trusted hosts list will automatically be trusted without prompting +for confirmation when they are first downloaded or when their checksums change. +The host matching includes the port if specified in the URL. Use with caution +and only add hosts you fully trust. + +### `TASK_REMOTE_CACERT` + +Path to a custom CA certificate file for TLS verification. + +### `TASK_REMOTE_CERT` + +Path to a client certificate file for mTLS authentication. + +### `TASK_REMOTE_CERT_KEY` + +Path to the client certificate private key file. + ### Custom Colors All color variables are [ANSI color codes][ansi]. You can specify multiple codes diff --git a/website/src/latest/docs/reference/schema.md b/website/src/latest/docs/reference/schema.md index 475c1964..471d9816 100644 --- a/website/src/latest/docs/reference/schema.md +++ b/website/src/latest/docs/reference/schema.md @@ -308,13 +308,14 @@ includes: ### `excludes` - **Type**: `[]string` -- **Description**: Tasks to exclude from inclusion +- **Description**: Task names or namespace patterns ending in `:*` to exclude + from inclusion ```yaml includes: shared: taskfile: ./shared.yml - excludes: [internal-setup, debug-only] + excludes: [internal-setup, 'debug:*', 'experimental:*'] ``` ### `vars` @@ -846,6 +847,7 @@ tasks: platforms: [linux, darwin] set: [errexit] shopt: [globstar] + timeout: 5m ``` ### Task References @@ -962,6 +964,58 @@ tasks: if: '[ "{{.ITEM}}" != "b" ]' ``` +### Command Timeouts + +Use `timeout` to limit how long a command may run. The value uses Go duration +syntax (e.g. `30s`, `5m`, `1h30m`) and must be greater than zero. + +```yaml +tasks: + deploy: + cmds: + - cmd: npm run build + timeout: 5m + - cmd: ./deploy.sh + timeout: 30m +``` + +When a command exceeds its timeout, it is terminated and the task fails with an +error, preventing commands from hanging indefinitely in a pipeline. The timeout +bounds the whole step, so an [`if`](#command) condition that hangs is cut short +too, and [`ignore_error`](#command) covers a timeout like any other failure. A +timed-out command reports [`EXIT_CODE`](/docs/reference/templating#exit_code) +`124`, following the convention of `timeout(1)`. + +A dependency takes the same key: + +```yaml +tasks: + build: + deps: + - task: fetch-assets + timeout: 2m +``` + +The key goes next to the command whatever form it takes, including a `defer`: + +```yaml +tasks: + deploy: + cmds: + - defer: + task: cleanup + timeout: 30s + - defer: ./cleanup.sh + timeout: 30s +``` + +A timed-out deferred command is logged and ignored, like other deferred errors. + +Calling a task that is already running under [`run: once`](#task) or +[`run: when_changed`](#task) joins that execution instead of starting a second +one. A `timeout` on such a call bounds how long you wait for it, not the shared +execution itself, which only the caller that started it can bound. + ## Shell Options ### Set Options diff --git a/website/src/latest/docs/reference/templating.md b/website/src/latest/docs/reference/templating.md index ccf968c0..37bdbe94 100644 --- a/website/src/latest/docs/reference/templating.md +++ b/website/src/latest/docs/reference/templating.md @@ -334,7 +334,8 @@ tasks: - **Type**: `int` - **Description**: Failed command exit code (only in `defer`, only when - non-zero) + non-zero). A command killed by its [`timeout`](/docs/reference/schema#command) + is reported as `124`, following the convention of `timeout(1)`. ```yaml tasks: diff --git a/website/src/latest/docs/remote-taskfiles.md b/website/src/latest/docs/remote-taskfiles.md new file mode 100644 index 00000000..4d54918e --- /dev/null +++ b/website/src/latest/docs/remote-taskfiles.md @@ -0,0 +1,338 @@ +--- +outline: deep +--- + +# Remote Taskfiles + +::: danger + +Never run remote Taskfiles from sources that you do not trust. + +::: + +Task allows you to use Taskfiles which are stored in remote locations. This +applies to both the root Taskfile (aka. Entrypoint) and also when including +Taskfiles. + +Task uses "nodes" to reference remote Taskfiles. There are a few different types +of node which you can use: + +::: code-group + +```text [HTTP/HTTPS] +https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +``` + +```text [Git over HTTP] +https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +```text [Git over SSH] +git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +::: + +## Node Types + +### HTTP/HTTPS + +`https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml` + +This is the most basic type of remote node and works by downloading the file +from the specified URL. The file must be a valid Taskfile and can be of any +name. If a file is not found at the specified URL, Task will append each of the +supported file names in turn until it finds a valid file. If it still does not +find a valid Taskfile, an error is returned. + +### Git over HTTP + +`https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main` + +This type of node works by downloading the file from a Git repository over +HTTP/HTTPS. The first part of the URL is the base URL of the Git repository. +This is the same URL that you would use to clone the repo over HTTP. + +- You can optionally add the path to the Taskfile in the repository by appending + `//` to the URL. +- You can also optionally specify a branch or tag to use by appending + `?ref=` to the end of the URL. If you omit a reference, the default + branch will be used. + +### Git over SSH + +`git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main` + +This type of node works by downloading the file from a Git repository over SSH. +The first part of the URL is the user and base URL of the Git repository. This +is the same URL that you would use to clone the repo over SSH. + +To use Git over SSH, you need to make sure that your SSH agent has your private +SSH keys added so that they can be used during authentication. + +- You can optionally add the path to the Taskfile in the repository by appending + `//` to the URL. +- You can also optionally specify a branch or tag to use by appending + `?ref=` to the end of the URL. If you omit a reference, the default + branch will be used. + +Task has an example remote Taskfile in our repository that you can use for +testing and that we will use throughout this document: + +```yaml +version: '3' + +tasks: + default: + cmds: + - task: hello + + hello: + cmds: + - echo "Hello Task!" +``` + +## Specifying a remote entrypoint + +By default, Task will look for one of the supported file names on your local +filesystem. If you want to use a remote file instead, you can pass its URI into +the `--taskfile`/`-t` flag just like you would to specify a different local +file. For example: + +::: code-group + +```shell [HTTP/HTTPS] +$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over HTTP] +$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +```shell [Git over SSH] +$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +task: [hello] echo "Hello Task!" +Hello Task! +``` + +::: + +## Including remote Taskfiles + +Including a remote file works exactly the same way that including a local file +does. You just need to replace the local path with a remote URI. Any tasks in +the remote Taskfile will be available to run from your main Taskfile. + +::: code-group + +```yaml [HTTP/HTTPS] +version: '3' + +includes: + my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +``` + +```yaml [Git over HTTP] +version: '3' + +includes: + my-remote-namespace: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +```yaml [Git over SSH] +version: '3' + +includes: + my-remote-namespace: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +::: + +```shell +$ task my-remote-namespace:hello +task: [hello] echo "Hello Task!" +Hello Task! +``` + +### Authenticating using environment variables + +The Taskfile location is processed by the templating system, so you can +reference environment variables in your URL if you need to add authentication. +For example: + +```yaml +version: '3' + +includes: + my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml +``` + +## Special Variables + +The file-path [special variables](../docs/reference/templating.md#file-paths) +behave differently when a Taskfile is loaded from a remote source, because there +is no local file or directory that corresponds 1:1 to the Taskfile: + +| Variable | Value when loaded remotely | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `TASKFILE` / `ROOT_TASKFILE` | The original URL, unchanged | +| `TASKFILE_DIR` / `ROOT_DIR` | Empty string — a directory variable cannot point to a URL | +| `TASK_DIR` | Resolved against `USER_WORKING_DIR` (relative `dir:` → joined with `USER_WORKING_DIR`, empty `dir:` → `USER_WORKING_DIR`, absolute `dir:` → kept as-is) | + +If a remote Taskfile includes a local Taskfile (or vice-versa), each variable +reflects the source of the Taskfile it refers to. + +## Security + +### Automatic checksums + +Running commands from sources that you do not control is always a potential +security risk. For this reason, we have added some automatic checks when using +remote Taskfiles: + +1. When running a task from a remote Taskfile for the first time, Task will + print a warning to the console asking you to check that you are sure that you + trust the source of the Taskfile. If you do not accept the prompt, then Task + will exit with code `104` (not trusted) and nothing will run. If you accept + the prompt, the remote Taskfile will run and further calls to the remote + Taskfile will not prompt you again. +2. Whenever you run a remote Taskfile, Task will create and store a checksum of + the file that you are running. If the checksum changes, then Task will print + another warning to the console to inform you that the contents of the remote + file has changed. If you do not accept the prompt, then Task will exit with + code `104` (not trusted) and nothing will run. If you accept the prompt, the + checksum will be updated and the remote Taskfile will run. + +Sometimes you need to run Task in an environment that does not have an +interactive terminal, so you are not able to accept a prompt. In these cases you +are able to tell task to accept these prompts automatically by using the `--yes` +flag or the `--trusted-hosts` flag. The `--trusted-hosts` flag allows you to +specify trusted hosts for remote Taskfiles, while `--yes` applies to all prompts +in Task. You can also configure trusted hosts in your +[taskrc configuration](./reference/config.md#remote-trusted-hosts) using +`remote.trusted-hosts`. Before enabling automatic trust, you should: + +1. Be sure that you trust the source and contents of the remote Taskfile. +2. Consider using a pinned version of the remote Taskfile (e.g. A link + containing a commit hash) to prevent Task from automatically accepting a + prompt that says a remote Taskfile has changed. + +### Manual checksum pinning + +Alternatively, if you expect the contents of your remote files to be a constant +value, you can pin the checksum of the included file instead: + +```yaml +version: '3' + +includes: + included: + taskfile: https://taskfile.dev + checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9 +``` + +This will disable the automatic checksum prompts discussed above. However, if +the checksums do not match, Task will exit immediately with an error. When +setting this up for the first time, you may not know the correct value of the +checksum. There are a couple of ways you can obtain this: + +1. Add the include normally without the `checksum` key. The first time you run + the included Taskfile, a `.task/remote` temporary directory is created. Find + the correct set of files for your included Taskfile and open the file that + ends with `.checksum`. You can copy the contents of this file and paste it + into the `checksum` key of your include. This method is safest as it allows + you to inspect the downloaded Taskfile before you pin it. +2. Alternatively, add the include with a temporary random value in the + `checksum` key. When you try to run the Taskfile, you will get an error that + will report the incorrect expected checksum and the actual checksum. You can + copy the actual checksum and replace your temporary random value. + +### TLS + +Task currently supports both `http` and `https` URLs. However, the `http` +requests will not execute by default unless you run the task with the +`--insecure` flag. This is to protect you from accidentally running a remote +Taskfile that is downloaded via an unencrypted connection. Sources that are not +protected by TLS are vulnerable to man-in-the-middle attacks and should be +avoided unless you know what you are doing. + +#### Custom Certificates + +If your remote Taskfiles are hosted on a server that uses a custom CA +certificate (e.g., a corporate internal server), you can specify the CA +certificate using the `--cacert` flag: + +```shell +task --taskfile https://internal.example.com/Taskfile.yml --cacert /path/to/ca.crt +``` + +For servers that require client certificate authentication (mTLS), you can +provide a client certificate and key: + +```shell +task --taskfile https://secure.example.com/Taskfile.yml \ + --cert /path/to/client.crt \ + --cert-key /path/to/client.key +``` + +::: warning + +Encrypted private keys are not currently supported. If your key is encrypted, +you must decrypt it first: + +```shell +openssl rsa -in encrypted.key -out decrypted.key +``` + +::: + +These options can also be configured in the +[configuration file](#configuration). + +## Caching & Running Offline + +Whenever you run a remote Taskfile, the latest copy will be downloaded from the +internet and cached locally. This cached file will be used for all future +invocations of the Taskfile until the cache expires. Once it expires, Task will +download the latest copy of the file and update the cache. By default, the cache +is set to expire immediately. This means that Task will always fetch the latest +version. However, the cache expiry duration can be modified by setting the +`--expiry` flag. + +If for any reason you lose access to the internet or you are running Task in +offline mode (via the `--offline` flag or `TASK_REMOTE_OFFLINE` environment +variable), Task will run any available cached files _even if they are expired_. +This means that you should never be stuck without the ability to run your tasks +as long as you have downloaded a remote Taskfile at least once. + +By default, Task will timeout requests to download remote files after 10 seconds +and look for a cached copy instead. This timeout can be configured by setting +the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will +set the timeout to 5 seconds. + +By default, the cache is stored in the Task temp directory (`.task`). You can +override the location of the cache by using the `--remote-cache-dir` flag, the +`remote.cache-dir` option in your +[configuration file](./reference/config.md#remote-cache-dir), or the +`TASK_REMOTE_CACHE_DIR` environment variable. This way, you can share the cache +between different projects. + +You can force Task to ignore the cache and download the latest version by using +the `--download` flag. + +You can use the `--clear-cache` flag to clear all cached remote files. + +## Configuration + +It is possible to configure the default behavior of remote Taskfiles using +configuration. Check out the following references for more information on how to +set up this configuration using flags, environment variables or a configuration +file: + +- [CLI flags](./reference/cli.md#remote) +- [Environment Variables](./reference/environment.md#remote-taskfile-variables) +- [Config File](./reference/config.md#remote) diff --git a/website/src/next/docs/changelog.md b/website/src/next/docs/changelog.md index f7a0e280..c76438ce 100644 --- a/website/src/next/docs/changelog.md +++ b/website/src/next/docs/changelog.md @@ -8,6 +8,67 @@ editLink: false ::: v-pre +## v3.53.0 - 2026-08-18 + +- **Remote Taskfiles are now generally available!** This has been an + experimental feature for 3 years, but is now enabled by default. Massive + thanks to all those that contributed and gave feedback (too many to list + here). We've also given the + [Remote Taskfiles documentation](https://taskfile.dev/docs/remote-taskfiles) a + bit of a polish (#1317, #2906 by @pd93). +- Considerably improve performance of fingerprinting on large repositories + (monorepos). Fingerprinting is up to 86% faster and make up to 70% fewer + memory allocations on the more advanced scenarios. Benchmarks were added as + well. We're basically skipping work when not needed. (#2853, #2883 by + @Napolitain, #2884 by @Napolitain). +- Updated taskfile versions doc to mention when version checks were introduced + (#2184 by @jubr). +- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing + `http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin). +- Added support for `enum.ref` in `--interactive` prompts. Required vars using + `enum.ref` now show the selection list like static enums, instead of falling + back to free-form input (#2817 by @vmaerten). +- Further improved fingerprinting performance on large repositories: hashing + source files now reuses a single buffer, reducing memory allocations by ~98% + and wall-clock time by ~7% (#2925 by @vmaerten). +- Fixed the fingerprint variable (`{{.CHECKSUM}}`/`{{.TIMESTAMP}}`) ignoring a + `method:` set at the Taskfile level: the variable now follows the same method + resolution as the up-to-date check. Only the variable matching the effective + method is injected, so a task inheriting a Taskfile-level `method: timestamp` + gets `{{.TIMESTAMP}}` and no longer a `{{.CHECKSUM}}` (which now renders as an + empty string), and neither variable is injected when the effective method is + `none` (#2924 by @vmaerten). +- `includes.excludes` can now exclude a whole namespace: append `:*` to the + namespace name, e.g. `excludes: ['debug:*']`. Bare entries still match a + single task name exactly (#2300, #2959 by @xmxxc). +- Fixed `ref:` in `for: matrix:` and `enum:` only accepting literal lists. Refs + computed with template functions like `keys` or `splitList` no longer fail + with "must resolve to a list" (#2544, #2956 by @no-hup). +- Fixed the JSON schema rejecting `ignore_error` on a command inside a `for` + loop. Editors no longer flag a Taskfile that Task runs perfectly fine (#2044 + by @gokeefe-atb). +- Fixed the JSON schema rejecting more keys the Taskfile parser accepts: + `ignore_error` on a `task:` call, and `if`, `set` and `shopt` on a command + inside a `for` loop (#2967 by @vmaerten). +- Added a verbose log line for failed tasks. In `--verbose` mode, a task whose + command exits non-zero now reports `task: "" failed: ` instead of + stopping without a trace (#2240 by @Drino). +- Fixed pressing `Esc` at an interactive variable prompt not cancelling the run + (#2942 by @anilnatha). +- Added Nushell completions, available via `task --completion nu`. They complete + task names and aliases, every flag with its description, and the values of + `--completion`, `--output` and `--sort` (#2966 by @vmaerten). +- Added a per-command `timeout` that terminates a command once it exceeds the + given duration (Go duration syntax). It covers shell commands, task calls, + deferred commands, `deps` and the `if` condition, obeys `ignore_error`, and + reports exit code `124`. Callers that join a `run: once` or `when_changed` + task already running now honor their own `timeout`, and inherit that task's + failure instead of being told it succeeded (#1569, #2898 by @vmaerten). +- Fixed a pinned `checksum:` not being verified when a remote Taskfile came from + the cache (#2980 by @vmaerten). +- Load the sidebar data and titles/excerpts from the blog post markdown document + and its frontmatter on the website (#2981 by @pd93). + ## v3.52.0 - 2026-07-02 - Fixed --interactive prompts for required vars sometimes appearing in a random diff --git a/website/src/public/schema-taskrc.json b/website/src/public/schema-taskrc.json index f25cb5dc..d12f4460 100644 --- a/website/src/public/schema-taskrc.json +++ b/website/src/public/schema-taskrc.json @@ -11,10 +11,6 @@ "type": "number", "enum": [0, 1] }, - "REMOTE_TASKFILES": { - "type": "number", - "enum": [0, 1] - }, "GENTLE_FORCE": { "type": "number", "enum": [0, 1] diff --git a/website/src/public/schema.json b/website/src/public/schema.json index df0637b7..74ebfe9d 100644 --- a/website/src/public/schema.json +++ b/website/src/public/schema.json @@ -349,9 +349,17 @@ "description": "Hides task name and command from output. The command's output will still be redirected to `STDOUT` and `STDERR`.", "type": "boolean" }, + "ignore_error": { + "description": "Prevent the command from aborting the execution of the task when it exits with a non-zero status code", + "type": "boolean" + }, "if": { "description": "A shell command to evaluate. If the exit code is non-zero, the command is skipped.", "type": "string" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -383,7 +391,7 @@ } }, "ignore_error": { - "description": "Prevent command from aborting the execution of task even after receiving a status code of 1", + "description": "Prevent the command from aborting the execution of the task when it exits with a non-zero status code", "type": "boolean" }, "platforms": { @@ -393,11 +401,38 @@ "if": { "description": "A shell command to evaluate. If the exit code is non-zero, the command is skipped.", "type": "string" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, "required": ["cmd"] }, + "deferred_task_call": { + "type": "object", + "properties": { + "task": { + "description": "Name of the task to run", + "type": "string" + }, + "vars": { + "description": "Values passed to the task called", + "$ref": "#/definitions/vars" + }, + "silent": { + "description": "Hides task name and command from output. The command's output will still be redirected to `STDOUT` and `STDERR`.", + "type": "boolean" + }, + "if": { + "description": "A shell command to evaluate. If the exit code is non-zero, the command is skipped.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["task"] + }, "defer_task_call": { "type": "object", "properties": { @@ -405,9 +440,13 @@ "description": "Run a command when the task completes. This command will run even when the task fails", "anyOf": [ { - "$ref": "#/definitions/task_call" + "$ref": "#/definitions/deferred_task_call" } ] + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -423,6 +462,10 @@ "silent": { "description": "Hides task name and command from output. The command's output will still be redirected to `STDOUT` and `STDERR`.", "type": "boolean" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -442,9 +485,35 @@ "description": "Silent mode disables echoing of command before Task runs it", "type": "boolean" }, + "set": { + "description": "Enables POSIX shell options for this command. See https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html", + "type": "array", + "items": { + "$ref": "#/definitions/set" + } + }, + "shopt": { + "description": "Enables Bash shell options for this command. See https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html", + "type": "array", + "items": { + "$ref": "#/definitions/shopt" + } + }, + "ignore_error": { + "description": "Prevent the command from aborting the execution of the task when it exits with a non-zero status code", + "type": "boolean" + }, "platforms": { "description": "Specifies which platforms the command should be run on.", "$ref": "#/definitions/platforms" + }, + "if": { + "description": "A shell command to evaluate. If the exit code is non-zero, the command is skipped.", + "type": "string" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -468,6 +537,10 @@ "description": "Silent mode disables echoing of command before Task runs it", "type": "boolean" }, + "ignore_error": { + "description": "Prevent the command from aborting the execution of the task when it exits with a non-zero status code", + "type": "boolean" + }, "platforms": { "description": "Specifies which platforms the command should be run on.", "$ref": "#/definitions/platforms" @@ -475,6 +548,10 @@ "if": { "description": "A shell command to evaluate. If the exit code is non-zero, the command is skipped.", "type": "string" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -497,6 +574,10 @@ "vars": { "description": "Values passed to the task called", "$ref": "#/definitions/vars" + }, + "timeout": { + "description": "Maximum duration the command is allowed to run before being terminated. Supports Go duration syntax (e.g., '5m', '30s', '1h').", + "type": "string" } }, "additionalProperties": false, @@ -746,7 +827,7 @@ } }, "excludes": { - "description": "A list of tasks to be excluded from inclusion.", + "description": "A list of task names or namespace patterns ending in `:*` to be excluded from inclusion.", "type": "array", "items": { "type": "string"