From b5aef1c287a9be8038347a17646bdf4bc7185bce Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Thu, 1 Oct 2026 22:21:39 +0200 Subject: [PATCH] v3.54.0 --- CHANGELOG.md | 2 +- internal/version/version.txt | 2 +- website/.vitepress/sidebar/latest.ts | 245 +- website/src/latest/agents.md | 77 + website/src/latest/blog/any-variables.md | 2 + website/src/latest/blog/completion-engine.md | 225 ++ website/src/latest/blog/windows-core-utils.md | 2 +- website/src/latest/docs/changelog.md | 116 +- website/src/latest/docs/community.md | 2 + website/src/latest/docs/contributing.md | 34 +- .../docs/deprecations/completion-scripts.md | 4 +- website/src/latest/docs/deprecations/index.md | 2 + .../docs/deprecations/template-functions.md | 2 + .../docs/deprecations/version-2-schema.md | 2 + .../latest/docs/experiments/env-precedence.md | 2 + .../latest/docs/experiments/gentle-force.md | 2 + website/src/latest/docs/experiments/index.md | 2 + .../docs/experiments/remote-taskfiles.md | 7 +- .../src/latest/docs/experiments/template.md | 3 +- website/src/latest/docs/faq.md | 4 +- website/src/latest/docs/getting-started.md | 20 +- website/src/latest/docs/guide.md | 2950 ----------------- website/src/latest/docs/guide/arguments.md | 140 + .../docs/guide/conditional-execution.md | 186 ++ .../src/latest/docs/guide/defining-tasks.md | 229 ++ website/src/latest/docs/guide/dependencies.md | 266 ++ website/src/latest/docs/guide/environment.md | 142 + .../latest/docs/guide/errors-and-cleanup.md | 97 + website/src/latest/docs/guide/includes.md | 247 ++ website/src/latest/docs/guide/index.md | 68 + website/src/latest/docs/guide/loops.md | 275 ++ website/src/latest/docs/guide/output.md | 214 ++ website/src/latest/docs/guide/platforms.md | 129 + .../latest/docs/guide/required-variables.md | 170 + .../src/latest/docs/guide/running-tasks.md | 150 + .../src/latest/docs/guide/secret-variables.md | 104 + website/src/latest/docs/guide/up-to-date.md | 236 ++ website/src/latest/docs/guide/variables.md | 343 ++ website/src/latest/docs/guide/watch.md | 80 + website/src/latest/docs/index.md | 69 + website/src/latest/docs/installation.md | 624 ++-- website/src/latest/docs/integrations.md | 2 + website/src/latest/docs/reference/cli.md | 7 + website/src/latest/docs/reference/config.md | 95 +- .../src/latest/docs/reference/environment.md | 10 +- website/src/latest/docs/reference/package.md | 2 + website/src/latest/docs/reference/schema.md | 9 +- .../src/latest/docs/reference/templating.md | 4 +- website/src/latest/docs/releasing.md | 59 +- website/src/latest/docs/remote-taskfiles.md | 265 +- .../docs/security/incident-response-plan.md | 7 +- website/src/latest/docs/security/index.md | 9 +- .../src/latest/docs/security/threat-model.md | 15 +- website/src/latest/docs/styleguide.md | 2 + website/src/latest/docs/taskfile-versions.md | 2 + website/src/next/blog/completion-engine.md | 2 +- website/src/next/docs/changelog.md | 113 +- website/src/public/schema-taskrc.json | 22 + 58 files changed, 4611 insertions(+), 3490 deletions(-) create mode 100644 website/src/latest/agents.md create mode 100644 website/src/latest/blog/completion-engine.md delete mode 100644 website/src/latest/docs/guide.md create mode 100644 website/src/latest/docs/guide/arguments.md create mode 100644 website/src/latest/docs/guide/conditional-execution.md create mode 100644 website/src/latest/docs/guide/defining-tasks.md create mode 100644 website/src/latest/docs/guide/dependencies.md create mode 100644 website/src/latest/docs/guide/environment.md create mode 100644 website/src/latest/docs/guide/errors-and-cleanup.md create mode 100644 website/src/latest/docs/guide/includes.md create mode 100644 website/src/latest/docs/guide/index.md create mode 100644 website/src/latest/docs/guide/loops.md create mode 100644 website/src/latest/docs/guide/output.md create mode 100644 website/src/latest/docs/guide/platforms.md create mode 100644 website/src/latest/docs/guide/required-variables.md create mode 100644 website/src/latest/docs/guide/running-tasks.md create mode 100644 website/src/latest/docs/guide/secret-variables.md create mode 100644 website/src/latest/docs/guide/up-to-date.md create mode 100644 website/src/latest/docs/guide/variables.md create mode 100644 website/src/latest/docs/guide/watch.md create mode 100644 website/src/latest/docs/index.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 990609a5..5b0ecef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## v3.54.0 - 2026-10-01 ### 🚀 Features diff --git a/internal/version/version.txt b/internal/version/version.txt index 0d767a08..738c1a72 100644 --- a/internal/version/version.txt +++ b/internal/version/version.txt @@ -1 +1 @@ -3.53.1 +3.54.0 diff --git a/website/.vitepress/sidebar/latest.ts b/website/.vitepress/sidebar/latest.ts index c7171547..49d547be 100644 --- a/website/.vitepress/sidebar/latest.ts +++ b/website/.vitepress/sidebar/latest.ts @@ -3,39 +3,106 @@ import type { DefaultTheme } from 'vitepress'; // Navigation for the `/docs` section. next.ts is the source of both sidebars; // cmd/release copies it over latest.ts alongside the content it describes. See // the "Documentation channels" section of website/src/next/docs/contributing.md. +// +// Grouped by what the reader is trying to do: get going, learn Task, look +// something up, follow the project. The DocSearch crawler puts the active +// sidebar section into hierarchy.lvl0, so these labels are also the breadcrumbs +// on every search result. export const sidebar: DefaultTheme.SidebarItem[] = [ { - text: 'Installation', - link: '/docs/installation' + text: 'Overview', + link: '/docs/' }, { text: 'Getting Started', - link: '/docs/getting-started' + items: [ + { + text: 'Installation', + link: '/docs/installation' + }, + { + text: 'Quick Start', + link: '/docs/getting-started' + }, + { + text: 'Editors and Integrations', + link: '/docs/integrations' + } + ] }, { text: 'Guide', - link: '/docs/guide' - }, - { - text: 'Remote Taskfiles', - link: '/docs/remote-taskfiles' + link: '/docs/guide/', + items: [ + { + text: 'Writing and running tasks', + collapsed: false, + items: [ + { text: 'Defining tasks', link: '/docs/guide/defining-tasks' }, + { text: 'Running tasks', link: '/docs/guide/running-tasks' } + ] + }, + { + text: 'Variables and arguments', + collapsed: false, + items: [ + { text: 'Variables', link: '/docs/guide/variables' }, + { text: 'Command-line arguments', link: '/docs/guide/arguments' }, + { + text: 'Validation and prompts', + link: '/docs/guide/required-variables' + }, + { text: 'Secret variables', link: '/docs/guide/secret-variables' } + ] + }, + { + text: 'Task execution', + collapsed: false, + items: [ + { + text: 'Dependencies and task calls', + link: '/docs/guide/dependencies' + }, + { text: 'Loops', link: '/docs/guide/loops' }, + { + text: 'Conditional execution', + link: '/docs/guide/conditional-execution' + }, + { + text: 'Errors and cleanup', + link: '/docs/guide/errors-and-cleanup' + }, + { text: 'Up-to-date checks', link: '/docs/guide/up-to-date' }, + { text: 'Watch mode', link: '/docs/guide/watch' } + ] + }, + { + text: 'Environment and output', + collapsed: false, + items: [ + { text: 'Environment variables', link: '/docs/guide/environment' }, + { text: 'Platforms and shells', link: '/docs/guide/platforms' }, + { text: 'Output and logging', link: '/docs/guide/output' } + ] + }, + { + text: 'Including Taskfiles', + collapsed: false, + items: [ + { text: 'Including Taskfiles', link: '/docs/guide/includes' }, + { text: 'Remote Taskfiles', link: '/docs/remote-taskfiles' } + ] + } + ] }, { text: 'Reference', - collapsed: true, + collapsed: false, items: [ { text: 'Taskfile Schema', link: '/docs/reference/schema' }, - { - text: 'Environment', - link: '/docs/reference/environment' - }, - { - text: 'Configuration', - link: '/docs/reference/config' - }, { text: 'CLI', link: '/docs/reference/cli' @@ -44,6 +111,14 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ text: 'Templating', link: '/docs/reference/templating' }, + { + text: 'Environment', + link: '/docs/reference/environment' + }, + { + text: 'Configuration', + link: '/docs/reference/config' + }, { text: 'Package API', link: '/docs/reference/package' @@ -51,88 +126,96 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ ] }, { - text: 'Experiments', + text: 'Project', collapsed: true, - link: '/docs/experiments/', items: [ { - text: 'Env Precedence (#1038)', - link: '/docs/experiments/env-precedence' + text: 'Changelog', + link: '/docs/changelog' }, { - text: 'Gentle Force (#1200)', - link: '/docs/experiments/gentle-force' + text: 'FAQ', + link: '/docs/faq' }, { - text: 'Remote Taskfiles (#1317)', - link: '/docs/experiments/remote-taskfiles' + text: 'Taskfile Versions', + link: '/docs/taskfile-versions' + }, + { + text: 'Community', + link: '/docs/community' + }, + { + text: 'Experiments', + collapsed: true, + link: '/docs/experiments/', + items: [ + { + text: 'Env Precedence (#1038)', + link: '/docs/experiments/env-precedence' + }, + { + text: 'Gentle Force (#1200)', + link: '/docs/experiments/gentle-force' + }, + { + text: 'Remote Taskfiles (#1317)', + link: '/docs/experiments/remote-taskfiles' + } + ] + }, + { + text: 'Deprecations', + collapsed: true, + link: '/docs/deprecations/', + items: [ + { + text: 'Completion Scripts', + link: '/docs/deprecations/completion-scripts' + }, + { + text: 'Template Functions', + link: '/docs/deprecations/template-functions' + }, + { + text: 'Version 2 Schema (#1197)', + link: '/docs/deprecations/version-2-schema' + } + ] + }, + { + text: 'Security', + collapsed: true, + link: '/docs/security/', + items: [ + { + text: 'Incident Response Plan', + link: '/docs/security/incident-response-plan' + }, + { + text: 'Threat Model', + link: '/docs/security/threat-model' + } + ] } ] }, - { - text: 'Deprecations', - collapsed: true, - link: '/docs/deprecations/', - items: [ - { - text: 'Completion Scripts', - link: '/docs/deprecations/completion-scripts' - }, - { - text: 'Template Functions', - link: '/docs/deprecations/template-functions' - }, - { - text: 'Version 2 Schema (#1197)', - link: '/docs/deprecations/version-2-schema' - } - ] - }, - { - text: 'Taskfile Versions', - link: '/docs/taskfile-versions' - }, - { - text: 'Integrations', - link: '/docs/integrations' - }, - { - text: 'Community', - link: '/docs/community' - }, - { - text: 'Style Guide', - link: '/docs/styleguide' - }, { text: 'Contributing', - link: '/docs/contributing' - }, - { - text: 'Releasing', - link: '/docs/releasing' - }, - { - text: 'Security', collapsed: true, - link: '/docs/security/', items: [ { - text: 'Incident Response Plan', - link: '/docs/security/incident-response-plan' + text: 'Contributing', + link: '/docs/contributing' }, { - text: 'Threat Model', - link: '/docs/security/threat-model' + text: 'Style Guide', + link: '/docs/styleguide' + }, + { + text: 'Releasing', + link: '/docs/releasing' } ] - }, - { - text: 'Changelog', - link: '/docs/changelog' - }, - { - text: 'FAQ', - link: '/docs/faq' } ]; diff --git a/website/src/latest/agents.md b/website/src/latest/agents.md new file mode 100644 index 00000000..bce46fca --- /dev/null +++ b/website/src/latest/agents.md @@ -0,0 +1,77 @@ +--- +title: Task documentation for coding agents +description: + A compact map of Task's documentation, plus the execution semantics that are + easiest to get wrong when generating a Taskfile. +outline: deep +--- + +# Task documentation for coding agents + +Task is a cross-platform task runner and build tool. Its configuration file is +normally named `Taskfile.yml`, and new files should use schema version `3`. + +Every page linked below is also available as raw Markdown: append `.md` to its +URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at +[/llms-full.txt](/llms-full.txt). + +## Where to look + +- [Quick Start](./docs/getting-started.md): the shape of a Taskfile. +- [Taskfile Schema](./docs/reference/schema.md): the source of truth for keys, + types and accepted values. Check here before assuming a field exists. +- [CLI](./docs/reference/cli.md): commands, flags and exit codes. +- [Templating](./docs/reference/templating.md): every template function and + special variable. Check here before inventing one. +- [Guide](./docs/guide/): task definitions, inputs, execution and shared + Taskfiles. +- [Errors and cleanup](./docs/guide/errors-and-cleanup.md): failure handling and + `defer`. +- [Secret variables](./docs/guide/secret-variables.md): masking and its limits. +- [Resolution order](./docs/guide/variables.md#resolution-order) and + [Task dependencies](./docs/guide/dependencies.md#task-dependencies): for when + the behaviour matters more than the procedure. + +## Semantics that are easy to get wrong + +1. `vars` are not exported to `cmds`: use templates to read them there. Dynamic + variables (`sh:`) also receive previously resolved scalar variables in their + shell environment. `env` is exported to commands. Root-level `env` also + participates in templates; task-level `env` does not. A template keeps any + value resolved from other sources, or renders empty if none exists. +2. A constant in a task's own `vars:` overrides the command line. Put the + default in global `vars:`, or use a template such as + `NAME: '{{.NAME | default "World"}}'` to preserve caller + input. +3. The included Taskfile's own `vars:` are applied after `includes.vars`. A + constant overrides the include's value; a self-referencing template with + `default` can preserve it. +4. Everything in `deps` may run concurrently and in any order. A `task:` + reference inside `cmds` runs at its position and blocks the next command. If + order matters, use `cmds`. +5. Each command runs in its own shell. Nothing carries over between them, not + `cd` and not an exported variable. Use Task's `dir:` and `env:` instead. +6. A template renders text. Use `ref:` to pass an array or a map without + flattening it to a string. +7. A passing `status:` means the task is already up to date and is skipped. A + failing `preconditions:` means the task must not run at all. They are not + interchangeable. +8. `defer:` commands run in reverse order of declaration, and run whether the + task succeeded or failed. +9. Remote Taskfiles execute code from wherever they are fetched. See + [Remote Taskfiles](./docs/remote-taskfiles.md) for the trust and checksum + rules. +10. Portability is about every command inside a task, not just Task itself. A + task is only cross-platform if its commands are. + +## Before writing a Taskfile + +- Confirm the feature exists in the schema for the version in use. +- Prefer plain, readable tasks over dense templating. +- Use `deps` only where concurrent execution is actually correct. +- Never embed credentials. Read them from the environment or a secret manager. + `secret: true` masks a value in Task's own logs, but it only works on `vars:`, + not on `env:`, and it never masks what a command itself prints. Treat it as + one less place a secret is echoed, not as protection. +- Give tasks a `desc:` so they show up in `task --list`, and validate inputs + with `requires:` or `preconditions:`. diff --git a/website/src/latest/blog/any-variables.md b/website/src/latest/blog/any-variables.md index 3868fc63..c1121df7 100644 --- a/website/src/latest/blog/any-variables.md +++ b/website/src/latest/blog/any-variables.md @@ -150,6 +150,8 @@ experiment. We're looking for feedback on a couple of different proposals, so please give them a go and let us know what you think. :pray: +[map-variables]: + ../docs/guide/variables.md#parsing-json-yaml-into-map-variables [v3.37.0]: https://github.com/go-task/task/releases/tag/v3.37.0 [slim-sprig-math]: https://sprig.taskfile.dev/math.html [slim-sprig-list]: https://sprig.taskfile.dev/lists.html diff --git a/website/src/latest/blog/completion-engine.md b/website/src/latest/blog/completion-engine.md new file mode 100644 index 00000000..1481282c --- /dev/null +++ b/website/src/latest/blog/completion-engine.md @@ -0,0 +1,225 @@ +--- +title: One Completion Engine for Every Shell +description: + A new completion engine that gives every shell the same suggestions, and that + can finally complete your required variables. +author: vmaerten +date: 2026-10-01 +tags: ['new-features', 'completion'] +outline: deep +editLink: false +--- + +# One Completion Engine for Every Shell + + + +Task has shipped shell completions for a long time. They were written as one +script per shell: a Bash script, a Zsh script, a Fish script, one for PowerShell +and one for Nushell. Each of them had to work out on its own what your Taskfile +contains and what flags Task accepts. Over the years, they drifted. + + + +[Task v3.54.0][release] brings a shared completion engine to Bash, Zsh, Fish, +PowerShell and Nushell. It is the default behind `task --completion `. +Let me show you what it fixes. + +## The same TAB, five different answers + +With the old scripts, asking Task to complete the value of `--output` could +produce different answers depending on the shell: + +```shell +# bash, zsh, fish +$ task --output +interleaved group prefixed + +# powershell +PS> task --output +build deploy +``` + +PowerShell had no idea `--output` takes a value, so it fell back to listing task +names where a value was expected. + +The differences also affected which Taskfile was read: + +```shell +$ task --dir ./sub +``` + +The old Zsh, Fish and PowerShell scripts suggested tasks from the _current_ +directory, since none of them passed `--dir` along when asking Task for a task +list. Bash and Nushell handled it correctly. + +Behind these symptoms was one structural problem: the logic lived in the +scripts. Several scripts maintained their own lists of flags and descriptions, +so adding a flag meant updating each of them. Some also parsed the +human-readable output of `--list-all` to learn about your tasks. Here is part of +what the Fish completion had to do: + +```fish +sed -e '1d; s/\* \(.*\):[[:space:]]\{2,\}\(.*\)[[:space:]]\{2,\}(\(aliases.*\))/\1\t\2\t\3/' +``` + +Even reformatting a line of `task --list-all` could break those completions. + +## One engine instead of five scripts + +The new scripts hand the command line over to a hidden `task __complete` +command. The binary returns suggestions and instructions for the shell, such as +whether to offer files or preserve the order of the results. + +Each wrapper still handles the details of its shell: reading the words under the +cursor, quoting values and displaying suggestions. Task names, required +variables and flags now come from one implementation in the binary. + +## What this unlocks + +### Completing required variables + +This is the one I wanted for a long time. The old scripts did not suggest a +task's [required variables][requires] or their allowed values. The engine does: + +```yaml +version: '3' + +tasks: + deploy: + desc: Deploy the app + requires: + vars: + - name: ENVIRONMENT + enum: [dev, staging, prod] + - REGION + cmds: + - ./deploy.sh +``` + +```shell +$ task deploy +ENVIRONMENT=dev ENVIRONMENT=staging ENVIRONMENT=prod REGION= +``` + +Variables with an `enum` give you the allowed values directly. Variables without +one give you `VAR=`. The engine returns these suggestions in the order of your +`requires` block. + +Assignments already on the command line are left out of the suggestions: + +```shell +$ task deploy ENVIRONMENT=prod +REGION= +``` + +Once both variables are supplied, completion offers task names again so you can +add another task to the same command. When several tasks are already named, the +engine combines their required variables without suggesting a name twice. + +Enums defined by reference work too: + +```yaml +version: '3' + +vars: + ALLOWED_ENVS: [dev, staging, prod] + +tasks: + deploy: + requires: + vars: + - name: ENVIRONMENT + enum: + ref: .ALLOWED_ENVS +``` + +This uses the same enum resolver as the [interactive prompt][prompt-post], with +one important limit: completion does not run `sh:` variables. If an enum needs a +shell command to produce its values, completion offers `ENVIRONMENT=` instead. + +### Everything else, everywhere + +All five shells now get their task names, aliases, flags and flag values from +the engine. `--dir`, `--taskfile` and `--global` are honoured when loading the +Taskfile, so completing inside another directory works. Completing `--taskfile` +offers `.yml` and `.yaml` files, plus directories you can navigate into. + +Flags gated behind an [experiment][experiments] are another good example. They +are read from Task's own flag set at the moment you press TAB, so they show up +when the experiment is enabled. The wrappers no longer need separate flag lists +or their own checks of `task --experiments`. + +The suggestions are shared, but the shells still control how they are inserted +and displayed. For example, PowerShell can add a space after `VAR=`, older Bash +versions may sort the results, and Nushell does not append a trailing space. + +## Completions should never surprise you + +Completion runs on a keystroke, so it is allowed to do very little: + +- No remote Taskfile downloads. Completion uses local files and cached remote + Taskfiles. If an uncached include prevents the Taskfile from loading, task + suggestions are unavailable until it has been fetched by a normal Task run. +- Nothing is read from stdin. A Taskfile supplied with `--taskfile -` is skipped + during completion. +- No `sh:` variable is evaluated. Pressing TAB never runs a command from your + Taskfile. +- A broken or missing Taskfile still leaves you with flag completion. + +## Load the new completions + +Starting with Task v3.54.0, `--completion` generates the new wrappers. If your +shell configuration already runs that command at startup, restart your shell +after upgrading. If you saved a completion script to a file, regenerate it with +the updated binary. + +Here are the startup commands for each shell: + +::: code-group + +```shell [bash] +# ~/.bashrc +eval "$(task --completion bash)" +``` + +```shell [zsh] +# ~/.zshrc +eval "$(task --completion zsh)" +``` + +```shell [fish] +# ~/.config/fish/config.fish +task --completion fish | source +``` + +```powershell [powershell] +# Add to your PowerShell profile ($PROFILE) +Invoke-Expression (&task --completion powershell | Out-String) +``` + +```nu [nushell] +# Add to config.nu; completions are loaded 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") +``` + +::: + +The [installation docs][install] cover saving scripts to completion directories, +Nushell's external completer and the Zsh `verbose` and `show-aliases` settings. + +## Feedback + +Please tell us how it behaves in your shell. If a suggestion is missing or +inserted incorrectly, include your Task version, shell version and a small +Taskfile that reproduces it. You can find us on our [Discord server][discord] or +[open an issue][gh-issue]. + +[release]: https://github.com/go-task/task/releases/tag/v3.54.0 +[requires]: /docs/reference/schema#requires +[prompt-post]: /blog/if-and-variable-prompt +[experiments]: /docs/experiments/ +[install]: /docs/installation#setup-completions +[discord]: https://discord.com/invite/6TY36E39UK +[gh-issue]: https://github.com/go-task/task/issues diff --git a/website/src/latest/blog/windows-core-utils.md b/website/src/latest/blog/windows-core-utils.md index 60fa16ea..8f3a3d2c 100644 --- a/website/src/latest/blog/windows-core-utils.md +++ b/website/src/latest/blog/windows-core-utils.md @@ -135,7 +135,7 @@ project][sponsor]! [uroot-base]: https://github.com/u-root/u-root/blob/main/pkg/core/base.go [middleware]: https://github.com/mvdan/sh/blob/master/x/coreutils/coreutils.go -[task-core-utils]: /docs/reference/environment#task-core-utils +[task-core-utils]: ../docs/reference/environment.md#task-core-utils [discord]: https://discord.com/invite/6TY36E39UK [gh-issue]: https://github.com/go-task/task/issues [sponsor]: /donate diff --git a/website/src/latest/docs/changelog.md b/website/src/latest/docs/changelog.md index c76438ce..6fbc44eb 100644 --- a/website/src/latest/docs/changelog.md +++ b/website/src/latest/docs/changelog.md @@ -1,5 +1,10 @@ --- title: Changelog +description: + Release history for Task, including new features, improvements, fixes, and + breaking changes +section: Project +docType: project outline: deep editLink: false --- @@ -8,7 +13,54 @@ editLink: false ::: v-pre -## v3.53.0 - 2026-08-18 +## v3.54.0 - 2026-10-01 + +### 🚀 Features + +- Added versioned Homebrew casks (`go-task@.`) to install a + specific minor version of Task (#3023 by @vmaerten). +- Added a `remote.headers` config option to send HTTP headers when downloading a + remote Taskfile, configured per host. Header values support templating + functions, e.g. `{{env "GITLAB_TOKEN"}}`. This keeps the credential out of the + include URL, where it would leak into error messages and the confirmation + prompt (#2329 by @vmaerten). + +### 🐛 Fixes + +- Fixed remote Git Taskfile cache poisoning on shared hosts (GHSA-679p-658w-m3wr, + reported by @danielcadev, fixed by @vmaerten). +- Fixed tasks cancelled by the user returning exit code `201` instead of `205` + (#3040, #3041 by @r3wretrhy). +- Fixed a bug on Windows where watching source paths did not work as expected + (#2863, #3028 by @pd93). +- Fixed a remote Taskfile whose server refuses the credentials being reported as + a missing Taskfile. A `401` now stops the search and reports the status code, + instead of retrying every default Taskfile name and concluding that no + Taskfile exists (#2329 by @vmaerten). + +- `task --completion ` now serves a new completion engine that unifies + Bash, Fish, Zsh, Nushell and PowerShell behind a single `task __complete` + command, so every shell offers the same suggestions: task names, aliases, + flags, flag values and per-task CLI variables. The Zsh `show-aliases` and + `verbose` zstyles keep working, now backed by the `--no-aliases` and + `--no-descriptions` completion flags (#2897 by @vmaerten). + +### 📦 Package API + +- Bumped the minimum Go version to 1.26. Task follows Go's two-latest support + window, and is now tested against 1.26 and 1.27. This only affects projects + importing Task as a Go module (#2920 by @vmaerten). + +### Other + +- Refactored some functional options to always return a concrete type instead of + an interface and moved options into their own file (#3037 by @pd93). +- Refactored the execext package to use mvdan/sh's new BashOpts API (#3035 by + @pd93). + +## v3.53.1 - 2026-08-18 + +### 🚀 Features - **Remote Taskfiles are now generally available!** This has been an experimental feature for 3 years, but is now enabled by default. Massive @@ -16,21 +68,37 @@ editLink: false here). We've also given the [Remote Taskfiles documentation](https://taskfile.dev/docs/remote-taskfiles) a bit of a polish (#1317, #2906 by @pd93). +- 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). - 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). +- `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). +- 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). +- 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 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). + +### 🐛 Fixes + +- Fixed a pinned `checksum:` not being verified when a remote Taskfile came from + the cache (#2980 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 @@ -38,37 +106,31 @@ editLink: false 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 pressing `Esc` at an interactive variable prompt not cancelling the run + (#2942 by @anilnatha). +- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing + `http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin). - 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). + +### 📚 Documentation & Website + +- Updated taskfile versions doc to mention when version checks were introduced + (#2184 by @jubr). - Load the sidebar data and titles/excerpts from the blog post markdown document and its frontmatter on the website (#2981 by @pd93). +## v3.53.0 - 2026-08-18 + +- Failed due to an issue with our release process. + ## v3.52.0 - 2026-07-02 - Fixed --interactive prompts for required vars sometimes appearing in a random diff --git a/website/src/latest/docs/community.md b/website/src/latest/docs/community.md index 53beb7f2..807608cc 100644 --- a/website/src/latest/docs/community.md +++ b/website/src/latest/docs/community.md @@ -3,6 +3,8 @@ title: Community description: Task community contributions, installation methods, and integrations maintained by third parties +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/contributing.md b/website/src/latest/docs/contributing.md index 993f570b..24d3ff97 100644 --- a/website/src/latest/docs/contributing.md +++ b/website/src/latest/docs/contributing.md @@ -3,6 +3,8 @@ title: Contributing description: Comprehensive guide for contributing to the Task project, including setup, development, testing, and submitting PRs +section: Contributing +docType: contributing outline: deep --- @@ -126,6 +128,19 @@ by using `task website` (requires `nodejs` & `pnpm`). All content is written in Markdown and is located in the `website/src` directory. All Markdown documents should have an 80 character line wrap limit (enforced by Prettier). +Search is provided by Algolia DocSearch. The crawler runs on Algolia's side and +is configured through their dashboard, but `website/docsearch.config.js` holds +the same configuration in the repository so it can be read and reviewed. If you +change one, change the other. A page's `section:` frontmatter is what the +crawler shows as the breadcrumb on a search result, while `docType:` powers its +search facet, so a new page needs both. + +After building the site, run `pnpm check:links` from `website/` to check links +in the generated Markdown pages and LLM indexes. The LLM plugin is patched in +`website/patches/` to resolve links before it moves directory indexes such as +`docs/guide/index.md` to `docs/guide.md`. When upgrading the plugin, retain the +patch until upstream handles those links, and check both documentation channels. + When making a change, consider whether a change to the [Usage Guide][usage-guide] is necessary. This document contains descriptions and examples of how to use Task features. If you're adding a new feature, try to @@ -140,14 +155,17 @@ for fields in the docs and the schema should match. #### Documentation channels -The docs and the blog exist in two copies, so that taskfile.dev never announces -a feature that is not in the released binary yet: +The docs, the blog and the coding-agent guide exist in two copies, so that +taskfile.dev never announces a feature that is not in the released binary yet: | Directory | Channel | Published on | | -------------------------------- | -------- | ----------------- | | `website/src/next/{docs,blog}` | `next` | next.taskfile.dev | | `website/src/latest/{docs,blog}` | `latest` | taskfile.dev | +The coding-agent guide follows the same channels as `src/next/agents.md` and +`src/latest/agents.md`, and is promoted at release time too. + Everything else - the homepage, the team, adopters, images - is shared by both channels and goes live as soon as the site is deployed. @@ -253,9 +271,9 @@ If you have questions, feel free to ask them in the `#help` forum channel on our [discord-server]: https://discord.gg/6TY36E39UK [discussion]: https://github.com/go-task/task/discussions [conventional-commits]: https://www.conventionalcommits.org -[experiments]: ./experiments/ -[experiments-workflow]: ./experiments/#workflow -[styleguide]: ./styleguide -[cli-reference]: ./reference/cli -[schema-reference]: ./reference/schema -[usage-guide]: ./guide +[experiments]: ./experiments/index.md +[experiments-workflow]: ./experiments/index.md#workflow +[styleguide]: ./styleguide.md +[cli-reference]: ./reference/cli.md +[schema-reference]: ./reference/schema.md +[usage-guide]: ./guide/index.md diff --git a/website/src/latest/docs/deprecations/completion-scripts.md b/website/src/latest/docs/deprecations/completion-scripts.md index d1cfbbc8..d0e6ca70 100644 --- a/website/src/latest/docs/deprecations/completion-scripts.md +++ b/website/src/latest/docs/deprecations/completion-scripts.md @@ -1,6 +1,8 @@ --- title: 'Completion Scripts' description: Deprecation of direct completion scripts in Task’s Git directory +section: Project +docType: project outline: deep --- @@ -21,5 +23,5 @@ the future as the scripts may be moved or deleted entirely. Any configuration should be updated to use the [new method for generating shell completions][completions] instead. -[completions]: /docs/installation#setup-completions +[completions]: ../installation.md#setup-completions [task]: https://github.com/go-task/task diff --git a/website/src/latest/docs/deprecations/index.md b/website/src/latest/docs/deprecations/index.md index d58ee2d3..4b8d4c77 100644 --- a/website/src/latest/docs/deprecations/index.md +++ b/website/src/latest/docs/deprecations/index.md @@ -3,6 +3,8 @@ title: Deprecations description: Guide to deprecated features in Task and how to migrate to the new alternatives +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/deprecations/template-functions.md b/website/src/latest/docs/deprecations/template-functions.md index 64374188..36a7b337 100644 --- a/website/src/latest/docs/deprecations/template-functions.md +++ b/website/src/latest/docs/deprecations/template-functions.md @@ -3,6 +3,8 @@ title: 'Template Functions' description: Deprecation of some templating functions in Task, with guidance on their replacements. +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/deprecations/version-2-schema.md b/website/src/latest/docs/deprecations/version-2-schema.md index 15be1dfc..e1c2f441 100644 --- a/website/src/latest/docs/deprecations/version-2-schema.md +++ b/website/src/latest/docs/deprecations/version-2-schema.md @@ -1,6 +1,8 @@ --- title: 'Version 2 Schema (#1197)' description: Deprecation of Taskfile schema version 2 and migration to version 3 +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/experiments/env-precedence.md b/website/src/latest/docs/experiments/env-precedence.md index 5df9f3ca..ae9e4b23 100644 --- a/website/src/latest/docs/experiments/env-precedence.md +++ b/website/src/latest/docs/experiments/env-precedence.md @@ -2,6 +2,8 @@ title: 'Env Precedence (#1038)' description: Experiment to change the precedence of environment variables in Task +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/experiments/gentle-force.md b/website/src/latest/docs/experiments/gentle-force.md index cd303106..870e0f16 100644 --- a/website/src/latest/docs/experiments/gentle-force.md +++ b/website/src/latest/docs/experiments/gentle-force.md @@ -1,6 +1,8 @@ --- title: 'Gentle Force (#1200)' description: Experiment to modify the behavior of the --force flag in Task +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/experiments/index.md b/website/src/latest/docs/experiments/index.md index 6ba48d89..3d4a1fea 100644 --- a/website/src/latest/docs/experiments/index.md +++ b/website/src/latest/docs/experiments/index.md @@ -1,6 +1,8 @@ --- title: Experiments description: Guide to Task’s experimental features and how to use them +section: Project +docType: project outline: deep --- diff --git a/website/src/latest/docs/experiments/remote-taskfiles.md b/website/src/latest/docs/experiments/remote-taskfiles.md index c242620b..ef508cdd 100644 --- a/website/src/latest/docs/experiments/remote-taskfiles.md +++ b/website/src/latest/docs/experiments/remote-taskfiles.md @@ -1,5 +1,8 @@ --- +title: Remote Taskfiles (#1317) description: Experimentation for using Taskfiles stored in remote locations +section: Project +docType: project outline: deep --- @@ -9,6 +12,6 @@ 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]. -[changelog]: ../changelog.md#v3511---2026-05-16 +[changelog]: ../changelog.md#v3-51-1-2026-05-16 [remote-taskfile-docs]: ../remote-taskfiles.md -[blog-post]: ../../blog/remote-taskfiles +[blog-post]: ../../blog/remote-taskfiles.md diff --git a/website/src/latest/docs/experiments/template.md b/website/src/latest/docs/experiments/template.md index 9df41586..6b4ccfec 100644 --- a/website/src/latest/docs/experiments/template.md +++ b/website/src/latest/docs/experiments/template.md @@ -1,5 +1,6 @@ --- title: '--- Template ---' +description: Template for documenting a new experiment. --- # \{Name of Experiment\} (#\{Issue\}) @@ -33,4 +34,4 @@ information. \{Short explanation of how users should migrate to the new behavior\} -[enabling-experiments]: /docs/experiments/#enabling-experiments +[enabling-experiments]: ./index.md#enabling-experiments diff --git a/website/src/latest/docs/faq.md b/website/src/latest/docs/faq.md index 1efdbda7..783d138f 100644 --- a/website/src/latest/docs/faq.md +++ b/website/src/latest/docs/faq.md @@ -3,6 +3,8 @@ title: FAQ description: Frequently asked questions about Task, including ETAs, shell limitations, and Windows compatibility +section: Project +docType: project outline: deep --- @@ -104,7 +106,7 @@ This is possible because Task compiles a small set of core utilities in Go and enables them by default on Windows for greater compatibility. It's possible to control whether these builtin core utilities are used or not -with the [`TASK_CORE_UTILS`](/docs/reference/environment#task-core-utils) +with the [`TASK_CORE_UTILS`](./reference/environment.md#task-core-utils) environment variable: ```bash diff --git a/website/src/latest/docs/getting-started.md b/website/src/latest/docs/getting-started.md index a6e8f7d9..48bc41b7 100644 --- a/website/src/latest/docs/getting-started.md +++ b/website/src/latest/docs/getting-started.md @@ -1,14 +1,17 @@ --- -title: Getting Started +title: Quick Start description: Guide for getting started with Task +section: Getting Started +docType: guide outline: deep --- -# Getting Started +# Quick Start {#getting-started} The following guide will help introduce you to the basics of Task. We'll cover how to create a Taskfile, how to write a basic task and how to call it. If you -haven't installed Task yet, head over to our [installation guide](installation). +haven't installed Task yet, head over to our +[installation guide](./installation.md). ## Creating your first Taskfile @@ -72,9 +75,9 @@ task default Note that we don't have to specify the name of the Taskfile. Task will automatically look for a file called `Taskfile.yml` (or any of Task's -[supported file names](/docs/guide#supported-file-names)) in the current -directory. Additionally, tasks with the name `default` are special. They can -also be run without specifying the task name. +[supported file names](./guide/running-tasks.md#supported-file-names)) in the +current directory. Additionally, tasks with the name `default` are special. They +can also be run without specifying the task name. If you created a Taskfile in a different directory, you can run it by passing the absolute or relative path to the directory as an argument using the `--dir` @@ -131,5 +134,6 @@ task build That's about it for the basics, but there's _so much_ more that you can do with Task. Check out the rest of the documentation to learn more about all the features Task has to offer! We recommend taking a look at the -[usage guide](/docs/guide) next. Alternatively, you can check out our reference -docs for the [Taskfile schema](reference/schema) and [CLI](reference/cli). +[usage guide](./guide/index.md) next. Alternatively, you can check out our +reference docs for the [Taskfile schema](./reference/schema.md) and +[CLI](./reference/cli.md). diff --git a/website/src/latest/docs/guide.md b/website/src/latest/docs/guide.md deleted file mode 100644 index 38e0caf7..00000000 --- a/website/src/latest/docs/guide.md +++ /dev/null @@ -1,2950 +0,0 @@ ---- -outline: deep ---- - -# Guide - -## Running Taskfiles - -Specific Taskfiles can be called by specifying the `--taskfile` flag. If you -don't specify a Taskfile, Task will automatically look for a file with one of -the [supported file names](#supported-file-names) in the current directory. If -you want to search in a different directory, you can use the `--dir` flag. - -### Supported file names - -Task looks for files with the following names, in order of priority: - -- `Taskfile.yml` -- `taskfile.yml` -- `Taskfile.yaml` -- `taskfile.yaml` -- `Taskfile.dist.yml` -- `taskfile.dist.yml` -- `Taskfile.dist.yaml` -- `taskfile.dist.yaml` - -The `.dist` variants allow projects to have one committed file (`.dist`) while -still allowing individual users to override the Taskfile by adding an additional -`Taskfile.yml` (which would be in your `.gitignore`). - -### Running a Taskfile from a subdirectory - -If a Taskfile cannot be found in the current working directory, it will walk up -the file tree until it finds one (similar to how `git` works). When running Task -from a subdirectory like this, it will behave as if you ran it from the -directory containing the Taskfile. - -You can use this functionality along with the special -`{{.USER_WORKING_DIR}}` variable to create some very useful -reusable tasks. For example, if you have a monorepo with directories for each -microservice, you can `cd` into a microservice directory and run a task command -to bring it up without having to create multiple tasks or Taskfiles with -identical content. For example: - -```yaml -version: '3' - -tasks: - up: - dir: '{{.USER_WORKING_DIR}}' - preconditions: - - test -f docker-compose.yml - cmds: - - docker-compose up -d -``` - -In this example, we can run `cd ` and `task up` and as long as the -`` directory contains a `docker-compose.yml`, the Docker composition -will be brought up. - -### Running a global Taskfile - -If you call Task with the `--global` (alias `-g`) flag, it will look for your -home directory instead of your working directory. In short, Task will look for a -Taskfile that matches `$HOME/{T,t}askfile.{yml,yaml}` . - -This is useful to have automation that you can run from anywhere in your system! - -::: info - -When running your global Taskfile with `-g`, tasks will run on `$HOME` by -default, and not on your working directory! - -As mentioned in the previous section, the -`{{.USER_WORKING_DIR}}` special variable can be very handy -here to run stuff on the directory you're calling `task -g` from. - -```yaml -version: '3' - -tasks: - from-home: - cmds: - - pwd - - from-working-directory: - dir: '{{.USER_WORKING_DIR}}' - cmds: - - pwd -``` - -::: - -### 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 -from stdin, you must specify the `-t/--taskfile` flag with the special `-` -value. You may then pipe into Task as you would any other program: - -```shell -task -t - < ./Taskfile.yml -# OR -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 - -You can use `env` to set custom environment variables for a specific task: - -```yaml -version: '3' - -tasks: - greet: - cmds: - - echo $GREETING - env: - GREETING: Hey, there! -``` - -Additionally, you can set global environment variables that will be available to -all tasks: - -```yaml -version: '3' - -env: - GREETING: Hey, there! - -tasks: - greet: - cmds: - - echo $GREETING -``` - -::: info - -`env` supports expansion and retrieving output from a shell command just like -variables, as you can see in the [Variables](#variables) section. - -::: - -### .env files - -You can also ask Task to include `.env` like files by using the `dotenv:` -setting: - -::: code-group - -```shell [.env] -KEYNAME=VALUE -``` - -```shell [testing/.env] -ENDPOINT=testing.com -``` - -::: - -```yaml -version: '3' - -env: - ENV: testing - -dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env'] - -tasks: - greet: - cmds: - - echo "Using $KEYNAME and endpoint $ENDPOINT" -``` - -When the same variable is defined in multiple dotenv files, the **first file in -the list takes precedence**. This allows you to set up override patterns by -placing higher-priority files first: - -```yaml -version: '3' - -dotenv: - - .env.local # Highest priority - local developer overrides - - .env.{{.ENV}} # Environment-specific settings - - .env # Base defaults (lowest priority) -``` - -Dotenv files can also be specified at the task level: - -```yaml -version: '3' - -env: - ENV: testing - -tasks: - greet: - dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env'] - cmds: - - echo "Using $KEYNAME and endpoint $ENDPOINT" -``` - -Environment variables specified explicitly at the task-level will override -variables defined in dotfiles: - -```yaml -version: '3' - -env: - ENV: testing - -tasks: - greet: - dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env'] - env: - KEYNAME: DIFFERENT_VALUE - cmds: - - echo "Using $KEYNAME and endpoint $ENDPOINT" -``` - -::: info - -Please note that you are not currently able to use the `dotenv` key inside -included Taskfiles. - -::: - -## Including other Taskfiles - -If you want to share tasks between different projects (Taskfiles), you can use -the importing mechanism to include other Taskfiles using the `includes` keyword: - -```yaml -version: '3' - -includes: - docs: ./documentation # will look for ./documentation/Taskfile.yml - docker: ./DockerTasks.yml -``` - -The tasks described in the given Taskfiles will be available with the informed -namespace. So, you'd call `task docs:serve` to run the `serve` task from -`documentation/Taskfile.yml` or `task docker:build` to run the `build` task from -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: - -```yaml -version: '3' - -includes: - build: ./Taskfile_{{OS}}.yml -``` - -### Directory of included Taskfile - -By default, included Taskfile's tasks are run in the current directory, even if -the Taskfile is in another directory, but you can force its tasks to run in -another directory by using this alternative syntax: - -```yaml -version: '3' - -includes: - docs: - taskfile: ./docs/Taskfile.yml - dir: ./docs -``` - -::: info - -The included Taskfiles must be using the same schema version as the main -Taskfile uses. - -::: - -### Optional includes - -Includes marked as optional will allow Task to continue execution as normal if -the included file is missing. - -```yaml -version: '3' - -includes: - tests: - taskfile: ./tests/Taskfile.yml - optional: true - -tasks: - greet: - cmds: - - echo "This command can still be successfully executed if - ./tests/Taskfile.yml does not exist" -``` - -### Internal includes - -Includes marked as internal will set all the tasks of the included file to be -internal as well (see the [Internal tasks](#internal-tasks) section below). This -is useful when including utility tasks that are not intended to be used directly -by the user. - -```yaml -version: '3' - -includes: - tests: - taskfile: ./taskfiles/Utils.yml - internal: true -``` - -### Flatten includes - -You can flatten the included Taskfile tasks into the main Taskfile by using the -`flatten` option. It means that the included Taskfile tasks will be available -without the namespace. - -::: code-group - -```yaml [Taskfile.yml] -version: '3' - -includes: - lib: - taskfile: ./Included.yml - flatten: true - -tasks: - greet: - cmds: - - echo "Greet" - - task: foo -``` - -```yaml [Included.yml] -version: '3' - -tasks: - foo: - cmds: - - echo "Foo" -``` - -::: - -If you run `task -a` it will print : - -```sh -task: Available tasks for this project: -* greet: -* foo -``` - -You can run `task foo` directly without the namespace. - -You can also reference the task in other tasks without the namespace. So if you -run `task greet` it will run `greet` and `foo` tasks and the output will be : - -```text -Greet -Foo -``` - -If multiple tasks have the same name, an error will be thrown: - -::: code-group - -```yaml [Taskfile.yml] -version: '3' -includes: - lib: - taskfile: ./Included.yml - flatten: true - -tasks: - greet: - cmds: - - echo "Greet" - - task: foo -``` - -```yaml [Included.yml] -version: '3' - -tasks: - greet: - cmds: - - echo "Foo" -``` - -::: - -If you run `task -a` it will print: - -```text -task: Found multiple tasks (greet) included by "lib" -``` - -If the included Taskfile has a task with the same name as a task in the main -Taskfile, you may want to exclude it from the flattened tasks. - -You can do this by using the -[`excludes` option](#exclude-tasks-from-being-included). - -### Exclude tasks from being included - -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 - -```yaml [Taskfile.yml] -version: '3' - -includes: - included: - taskfile: ./Included.yml - excludes: [foo, 'internal:*', 'debug:*'] -``` - -```yaml [Included.yml] -version: '3' - -tasks: - foo: echo "Foo" - bar: echo "Bar" - internal:setup: echo "Internal setup" - debug:status: echo "Debug status" -``` - -::: - -`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. - -### Vars of included Taskfiles - -You can also specify variables when including a Taskfile. This may be useful for -having a reusable Taskfile that can be tweaked or even included more than once: - -```yaml -version: '3' - -includes: - backend: - taskfile: ./taskfiles/Docker.yml - vars: - DOCKER_IMAGE: backend_image - - frontend: - taskfile: ./taskfiles/Docker.yml - vars: - DOCKER_IMAGE: frontend_image -``` - -### Namespace aliases - -When including a Taskfile, you can give the namespace a list of `aliases`. This -works in the same way as [task aliases](#task-aliases) and can be used together -to create shorter and easier-to-type commands. - -```yaml -version: '3' - -includes: - generate: - taskfile: ./taskfiles/Generate.yml - aliases: [gen] -``` - -::: info - -Vars declared in the included Taskfile have preference over the variables in the -including Taskfile! If you want a variable in an included Taskfile to be -overridable, use the -[default function](https://sprig.taskfile.dev/defaults.html): -`MY_VAR: '{{.MY_VAR | default "my-default-value"}}'`. - -::: - -## Internal tasks - -Internal tasks are tasks that cannot be called directly by the user. They will -not appear in the output when running `task --list|--list-all`. Other tasks may -call internal tasks in the usual way. This is useful for creating reusable, -function-like tasks that have no useful purpose on the command line. - -```yaml -version: '3' - -tasks: - build-image-1: - cmds: - - task: build-image - vars: - DOCKER_IMAGE: image-1 - - build-image: - internal: true - cmds: - - docker build -t {{.DOCKER_IMAGE}} . -``` - -## Task directory - -By default, tasks will be executed in the directory where the Taskfile is -located. But you can easily make the task run in another folder, informing -`dir`: - -```yaml -version: '3' - -tasks: - serve: - dir: public/www - cmds: - # run http server - - caddy -``` - -If the directory does not exist, `task` creates it. - -## Task dependencies - -> Dependencies run in parallel, so dependencies of a task should not depend one -> another. If you want to force tasks to run serially, take a look at the -> [Calling Another Task](#calling-another-task) section below. - -You may have tasks that depend on others. Just pointing them on `deps` will make -them run automatically before running the parent task: - -```yaml -version: '3' - -tasks: - build: - deps: [assets] - cmds: - - go build -v -i main.go - - assets: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css -``` - -In the above example, `assets` will always run right before `build` if you run -`task build`. - -A task can have only dependencies and no commands to group tasks together: - -```yaml -version: '3' - -tasks: - assets: - deps: [js, css] - - js: - cmds: - - esbuild --bundle --minify js/index.js > public/bundle.js - - css: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css -``` - -If there is more than one dependency, they always run in parallel for better -performance. - -::: tip - -You can also make the tasks given by the command line run in parallel by using -the `--parallel` flag (alias `-p`). Example: `task --parallel js css`. - -::: - -If you want to pass information to dependencies, you can do that the same manner -as you would to [call another task](#calling-another-task): - -```yaml -version: '3' - -tasks: - default: - deps: - - task: echo_sth - vars: { TEXT: 'before 1' } - - task: echo_sth - vars: { TEXT: 'before 2' } - silent: true - cmds: - - echo "after" - - echo_sth: - cmds: - - echo {{.TEXT}} -``` - -### Fail-fast dependencies - -By default, Task waits for all dependencies to finish running before continuing. -If you want Task to stop executing further dependencies as soon as one fails, -you can set `failfast: true` on your [`.taskrc.yml`][config] or for a specific -task: - -```yaml -# .taskrc.yml -failfast: true # applies to all tasks -``` - -```yaml -# Taskfile.yml -version: '3' - -tasks: - default: - deps: [task1, task2, task3] - failfast: true # applies only to this task -``` - -Alternatively, you can use `--failfast`, which also work for `--parallel`. - -## Platform specific tasks and commands - -If you want to restrict the running of tasks to explicit platforms, this can be -achieved using the `platforms:` key. Tasks can be restricted to a specific OS, -architecture or a combination of both. On a mismatch, the task or command will -be skipped, and no error will be thrown. - -The values allowed as OS or Arch are valid `GOOS` and `GOARCH` values, as -defined by the Go language -[here](https://github.com/golang/go/blob/master/src/internal/syslist/syslist.go). - -The `build-windows` task below will run only on Windows, and on any -architecture: - -```yaml -version: '3' - -tasks: - build-windows: - platforms: [windows] - cmds: - - echo 'Running command on Windows' -``` - -This can be restricted to a specific architecture as follows: - -```yaml -version: '3' - -tasks: - build-windows-amd64: - platforms: [windows/amd64] - cmds: - - echo 'Running command on Windows (amd64)' -``` - -It is also possible to restrict the task to specific architectures: - -```yaml -version: '3' - -tasks: - build-amd64: - platforms: [amd64] - cmds: - - echo 'Running command on amd64' -``` - -Multiple platforms can be specified as follows: - -```yaml -version: '3' - -tasks: - build: - platforms: [windows/amd64, darwin] - cmds: - - echo 'Running command on Windows (amd64) and macOS' -``` - -Individual commands can also be restricted to specific platforms: - -```yaml -version: '3' - -tasks: - build: - cmds: - - cmd: echo 'Running command on Windows (amd64) and macOS' - platforms: [windows/amd64, darwin] - - cmd: echo 'Running on all platforms' -``` - -## Calling another task - -When a task has many dependencies, they are executed concurrently. This will -often result in a faster build pipeline. However, in some situations, you may -need to call other tasks serially. In this case, use the following syntax: - -```yaml -version: '3' - -tasks: - main-task: - cmds: - - task: task-to-be-called - - task: another-task - - echo "Both done" - - task-to-be-called: - cmds: - - echo "Task to be called" - - another-task: - cmds: - - echo "Another task" -``` - -Using the `vars` and `silent` attributes you can choose to pass variables and -toggle [silent mode](#silent-mode) on a call-by-call basis: - -```yaml -version: '3' - -tasks: - greet: - vars: - RECIPIENT: '{{default "World" .RECIPIENT}}' - cmds: - - echo "Hello, {{.RECIPIENT}}!" - - greet-pessimistically: - cmds: - - task: greet - vars: { RECIPIENT: 'Cruel World' } - silent: true -``` - -The above syntax is also supported in `deps`. - -::: tip - -NOTE: If you want to call a task declared in the root Taskfile from within an -[included Taskfile](#including-other-taskfiles), add a leading `:` like this: -`task: :task-name`. - -::: - -## Prevent unnecessary work - -### By fingerprinting locally generated files and their sources - -If a task generates something, you can inform Task the source and generated -files, so Task will prevent running them if not necessary. - -```yaml -version: '3' - -tasks: - build: - deps: [js, css] - cmds: - - go build -v -i main.go - - js: - cmds: - - esbuild --bundle --minify js/index.js > public/bundle.js - sources: - - src/js/**/*.js - generates: - - public/bundle.js - - css: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css - sources: - - src/css/**/*.css - generates: - - public/bundle.css -``` - -`sources` and `generates` can be files or glob patterns. When given, Task will -compare the checksum of the source files to determine if it's necessary to run -the task. If not, it will just print a message like `Task "js" is up to date`. - -`exclude:` can also be used to exclude files from fingerprinting. Sources are -evaluated in order, so `exclude:` must come after the positive glob it is -negating. - -```yaml -version: '3' - -tasks: - css: - sources: - - mysources/**/*.css - - exclude: mysources/ignoreme.css - generates: - - public/bundle.css -``` - -If you prefer these check to be made by the modification timestamp of the files, -instead of its checksum (content), just set the `method` property to -`timestamp`. This can be done at two levels: - -At the task level for a specific task: - -```yaml -version: '3' - -tasks: - build: - cmds: - - go build . - sources: - - ./*.go - generates: - - app{{exeExt}} - method: timestamp -``` - -At the root level of the Taskfile to apply it globally to all tasks: - -```yaml -version: '3' - -method: timestamp # Will be the default for all tasks - -tasks: - build: - cmds: - - go build . - sources: - - ./*.go - generates: - - app{{exeExt}} -``` - -In situations where you need more flexibility the `status` keyword can be used. -You can even combine the two. See the documentation for -[status](#using-programmatic-checks-to-indicate-a-task-is-up-to-date) for an -example. - -::: info - -By default, task stores checksums on a local `.task` directory in the project's -directory. Most of the time, you'll want to have this directory on `.gitignore` -(or equivalent) so it isn't committed. (If you have a task for code generation -that is committed it may make sense to commit the checksum of that task as well, -though). - -If you want these files to be stored in another directory, you can set a -`TASK_TEMP_DIR` environment variable in your machine. It can contain a relative -path like `tmp/task` that will be interpreted as relative to the project -directory, or an absolute or home path like `/tmp/.task` or `~/.task` -(subdirectories will be created for each project). - -```shell -export TASK_TEMP_DIR='~/.task' -``` - -::: - -::: info - -Each task has only one checksum stored for its `sources`. If you want to -distinguish a task by any of its input variables, you can add those variables as -part of the task's label, and it will be considered a different task. - -This is useful if you want to run a task once for each distinct set of inputs -until the sources actually change. For example, if the sources depend on the -value of a variable, or you if you want the task to rerun if some arguments -change even if the source has not. - -::: - -::: tip - -The method `none` skips any validation and always runs the task. - -::: - -::: info - -For the `checksum` (default) or `timestamp` method to work, it is only necessary -to inform the source files. When the `timestamp` method is used, the last time -of the running the task is considered as a generate. - -::: - -::: tip - -If your globs match files that are ignored by Git (build artifacts, caches, -etc.), you can set `use_gitignore: true` at the root of your Taskfile to -exclude anything matched by `.gitignore` rules from `sources` and `generates` -resolution. The setting can also be enabled or disabled per task, which takes -precedence over the root value. - -::: - -### Using programmatic checks to indicate a task is up to date - -Alternatively, you can inform a sequence of tests as `status`. If no error is -returned (exit status 0), the task is considered up-to-date: - -```yaml -version: '3' - -tasks: - generate-files: - cmds: - - mkdir directory - - touch directory/file1.txt - - touch directory/file2.txt - # test existence of files - status: - - test -d directory - - test -f directory/file1.txt - - test -f directory/file2.txt -``` - -Normally, you would use `sources` in combination with `generates` - but for -tasks that generate remote artifacts (Docker images, deploys, CD releases) the -checksum source and timestamps require either access to the artifact or for an -out-of-band refresh of the `.checksum` fingerprint file. - -Two special variables `{{.CHECKSUM}}` and -`{{.TIMESTAMP}}` are available for interpolation within -`cmds` and `status` commands, depending on the method assigned to fingerprint -the sources. Only `source` globs are fingerprinted. - -Note that the `{{.TIMESTAMP}}` variable is a "live" Go -`time.Time` struct, and can be formatted using any of the methods that -`time.Time` responds to. - -See [the Go Time documentation](https://golang.org/pkg/time/) for more -information. - -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. - -`status` can be combined with the -[fingerprinting](#by-fingerprinting-locally-generated-files-and-their-sources) -to have a task run if either the source/generated artifacts changes, or the -programmatic check fails: - -```yaml -version: '3' - -tasks: - build:prod: - desc: Build for production usage. - cmds: - - composer install - # Run this task if source files changes. - sources: - - composer.json - - composer.lock - generates: - - ./vendor/composer/installed.json - - ./vendor/autoload.php - # But also run the task if the last build was not a production build. - status: - - grep -q '"dev"{{:}} false' ./vendor/composer/installed.json -``` - -### Using programmatic checks to cancel the execution of a task and its dependencies - -In addition to `status` checks, `preconditions` checks are the logical inverse -of `status` checks. That is, if you need a certain set of conditions to be -_true_ you can use the `preconditions` stanza. `preconditions` are similar to -`status` lines, except they support `sh` expansion, and they SHOULD all -return 0. - -```yaml -version: '3' - -tasks: - generate-files: - cmds: - - mkdir directory - - touch directory/file1.txt - - touch directory/file2.txt - # test existence of files - preconditions: - - test -f .env - - sh: '[ 1 = 0 ]' - msg: "One doesn't equal Zero, Halting" -``` - -Preconditions can set specific failure messages that can tell a user what steps -to take using the `msg` field. - -If a task has a dependency on a sub-task with a precondition, and that -precondition is not met - the calling task will fail. Note that a task executed -with a failing precondition will not run unless `--force` is given. - -Unlike `status`, which will skip a task if it is up to date and continue -executing tasks that depend on it, a `precondition` will fail a task, along with -any other tasks that depend on it. - -```yaml -version: '3' - -tasks: - task-will-fail: - preconditions: - - sh: 'exit 1' - - task-will-also-fail: - deps: - - task-will-fail - - task-will-still-fail: - cmds: - - task: task-will-fail - - echo "I will not run" -``` - -### Conditional execution with `if` - -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. - -#### Task-level `if` - -When `if` is set on a task, the entire task is skipped if the condition fails: - -```yaml -version: '3' - -tasks: - deploy: - if: '[ "$CI" = "true" ]' - cmds: - - echo "Deploying..." - - ./deploy.sh -``` - -#### Command-level `if` - -When `if` is set on a command, only that specific command is skipped: - -```yaml -version: '3' - -tasks: - build: - cmds: - - cmd: echo "Building for production" - if: '[ "$ENV" = "production" ]' - - cmd: echo "Building for development" - if: '[ "$ENV" = "development" ]' - - go build ./... -``` - -#### 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): - -```yaml -version: '3' - -tasks: - conditional: - vars: - ENABLE_FEATURE: 'true' - cmds: - - cmd: echo "Feature is enabled" - if: '{{eq .ENABLE_FEATURE "true"}}' - - cmd: echo "Feature is disabled" - if: '{{ne .ENABLE_FEATURE "true"}}' -``` - -#### Using `if` with `for` loops - -When used inside a `for` loop, the `if` condition is evaluated for each -iteration: - -```yaml -version: '3' - -tasks: - process-items: - cmds: - - for: ['a', 'b', 'c'] - cmd: echo "processing {{.ITEM}}" - if: '[ "{{.ITEM}}" != "b" ]' -``` - -This will output: - -``` -processing a -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" | - -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 -make sense. - -### Limiting when tasks run - -If a task executed by multiple `cmds` or multiple `deps` you can control when it -is executed using `run`. `run` can also be set at the root of the Taskfile to -change the behavior of all the tasks unless explicitly overridden. - -Supported values for `run`: - -- `always` (default) always attempt to invoke the task regardless of the number - of previous executions -- `once` only invoke this task once regardless of the number of references -- `when_changed` only invokes the task once for each unique set of variables - passed into the task - -```yaml -version: '3' - -tasks: - default: - cmds: - - task: generate-file - vars: { CONTENT: '1' } - - task: generate-file - vars: { CONTENT: '2' } - - task: generate-file - vars: { CONTENT: '2' } - - generate-file: - run: when_changed - deps: - - install-deps - cmds: - - echo {{.CONTENT}} - - install-deps: - run: once - cmds: - - sleep 5 # long operation like installing packages -``` - -### Ensuring required variables are set - -If you want to check that certain variables are set before running a task then -you can use `requires`. This is useful when might not be clear to users which -variables are needed, or if you want clear message about what is required. Also -some tasks could have dangerous side effects if run with un-set variables. - -Using `requires` you specify an array of strings in the `vars` sub-section under -`requires`, these strings are variable names which are checked prior to running -the task. If any variables are un-set then the task will error and not run. - -Environmental variables are also checked. - -Syntax: - -```yaml -requires: - vars: [] # Array of strings -``` - -::: info - -Variables set to empty zero length strings, will pass the `requires` check. - -::: - -Example of using `requires`: - -```yaml -version: '3' - -tasks: - docker-build: - cmds: - - 'docker build . -t {{.IMAGE_NAME}}:{{.IMAGE_TAG}}' - - # Make sure these variables are set before running - requires: - vars: [IMAGE_NAME, IMAGE_TAG] -``` - -### Ensuring required variables have allowed values - -If you want to ensure that a variable is set to one of a predefined set of valid -values before executing a task, you can use requires. This is particularly -useful when there are strict requirements for what values a variable can take, -and you want to provide clear feedback to the user when an invalid value is -detected. - -To use `requires`, you specify an array of allowed values in the vars -sub-section under requires. Task will check if the variable is set to one of the -allowed values. If the variable does not match any of these values, the task -will raise an error and stop execution. - -This check applies both to user-defined variables and environment variables. - -Example of using `requires`: - -```yaml -version: '3' - -tasks: - deploy: - cmds: - - echo "deploying to {{.ENV}}" - - requires: - vars: - - name: ENV - enum: [dev, beta, prod] -``` - -If `ENV` is not one of 'dev', 'beta' or 'prod' an error will be raised. - -::: info - -This is supported only for string variables. - -::: - -### Using variable references for enum values - -Instead of hardcoding enum values, you can reference a variable containing the -allowed values. This is useful when you want to define allowed values once and -reuse them, or when the values are computed dynamically. - -Use the `ref` key to reference a variable: - -```yaml -version: '3' - -vars: - ALLOWED_ENVS: [dev, staging, prod] - -tasks: - deploy: - requires: - vars: - - name: ENV - enum: - ref: .ALLOWED_ENVS - cmds: - - echo "Deploying to {{.ENV}}" -``` - -You can also use template expressions to transform the value: - -```yaml -version: '3' - -vars: - CONFIG: - sh: cat config.json - -tasks: - deploy: - requires: - vars: - - name: ENV - enum: - ref: ( .CONFIG | fromJson ).allowed_environments - cmds: - - echo "Deploying to {{.ENV}}" -``` - -Or generate values dynamically from a shell command: - -```yaml -version: '3' - -vars: - AVAILABLE_SERVICES: - sh: ls services/ - -tasks: - deploy: - requires: - vars: - - name: SERVICE - enum: - ref: .AVAILABLE_SERVICES | splitLines | compact - cmds: - - echo "Deploying {{.SERVICE}}" -``` - -### Prompting for missing variables interactively - -If you want Task to prompt users for missing required variables instead of -failing, you can enable interactive mode in your `.taskrc.yml`: - -```yaml -# ~/.taskrc.yml -interactive: true -``` - -When enabled, Task will display an interactive prompt for any missing required -variable. For variables with an `enum`, a selection menu is shown. For variables -without an enum, a text input is displayed. - -```yaml -# Taskfile.yml -version: '3' - -tasks: - deploy: - requires: - vars: - - name: ENVIRONMENT - enum: [dev, staging, prod] - - VERSION - cmds: - - echo "Deploying {{.VERSION}} to {{.ENVIRONMENT}}" -``` - -```shell -$ task deploy -? Select value for ENVIRONMENT: -❯ dev - staging - prod -? Enter value for VERSION: 1.0.0 -Deploying 1.0.0 to prod -``` - -If the variable is already set (via CLI, environment, or Taskfile), no prompt is -shown: - -```shell -$ task deploy ENVIRONMENT=prod VERSION=1.0.0 -Deploying 1.0.0 to prod -``` - -::: info - -Interactive prompts require a TTY (terminal). Task automatically detects -non-interactive environments like GitHub Actions, GitLab CI, and other CI -pipelines where stdin/stdout are not connected to a terminal. In these cases, -prompts are skipped and missing variables will cause an error as usual. - -You can enable prompts from the command line with `--interactive` or by setting -`interactive: true` in your `.taskrc.yml`. - -::: - -## Variables - -Task allows you to set variables using the `vars` keyword. The following -variable types are supported: - -- `string` -- `bool` -- `int` -- `float` -- `array` -- `map` - -::: info - -Defining a map requires that you use a special `map` subkey (see example below). - -::: - -```yaml -version: 3 - -tasks: - foo: - vars: - STRING: 'Hello, World!' - BOOL: true - INT: 42 - FLOAT: 3.14 - ARRAY: [1, 2, 3] - MAP: - map: { A: 1, B: 2, C: 3 } - cmds: - - 'echo {{.STRING}}' # Hello, World! - - 'echo {{.BOOL}}' # true - - 'echo {{.INT}}' # 42 - - 'echo {{.FLOAT}}' # 3.14 - - 'echo {{.ARRAY}}' # [1 2 3] - - 'echo {{index .ARRAY 0}}' # 1 - - 'echo {{.MAP}}' # map[A:1 B:2 C:3] - - 'echo {{.MAP.A}}' # 1 -``` - -Variables can be set in many places in a Taskfile. When executing -[templates][templating-reference], Task will look for variables in the order -listed below (most important first): - -- Variables declared in the task definition -- Variables given while calling a task from another (See - [Calling another task](#calling-another-task) above) -- Variables of the [included Taskfile](#including-other-taskfiles) (when the - task is included) -- Variables of the [inclusion of the Taskfile](#vars-of-included-taskfiles) - (when the task is included) -- Global variables (those declared in the `vars:` option in the Taskfile) -- Environment variables - -Example of sending parameters with environment variables: - -```shell -$ TASK_VARIABLE=a-value task do-something -``` - -::: tip - -A special variable `.TASK` is always available containing the task name. - -::: - -Since some shells do not support the above syntax to set environment variables -(Windows) tasks also accept a similar style when not at the beginning of the -command. - -```shell -$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!" -``` - -Example of locally declared vars: - -```yaml -version: '3' - -tasks: - print-var: - cmds: - - echo "{{.VAR}}" - vars: - VAR: Hello! -``` - -Example of global vars in a `Taskfile.yml`: - -```yaml -version: '3' - -vars: - GREETING: Hello from Taskfile! - -tasks: - greet: - cmds: - - echo "{{.GREETING}}" -``` - -Example of a `default` value to be overridden from CLI: - -```yaml -version: '3' - -tasks: - greet_user: - desc: 'Greet the user with a name.' - vars: - USER_NAME: '{{.USER_NAME| default "DefaultUser"}}' - cmds: - - echo "Hello, {{.USER_NAME}}!" -``` - -```shell -$ task greet_user -task: [greet_user] echo "Hello, DefaultUser!" -Hello, DefaultUser! -$ task greet_user USER_NAME="Bob" -task: [greet_user] echo "Hello, Bob!" -Hello, Bob! -``` - -### Dynamic variables - -The below syntax (`sh:` prop in a variable) is considered a dynamic variable. -The value will be treated as a command and the output assigned. If there are one -or more trailing newlines, the last newline will be trimmed. - -```yaml -version: '3' - -tasks: - build: - cmds: - - go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go - vars: - GIT_COMMIT: - sh: git log -n 1 --format=%h -``` - -This works for all types of variables. - -### Referencing other variables - -Templating is great for referencing string values if you want to pass a value -from one task to another. However, the templating engine is only able to output -strings. If you want to pass something other than a string to another task then -you will need to use a reference (`ref`) instead. - -::: code-group - -```yaml [Templating Engine] -version: 3 - -tasks: - foo: - vars: - FOO: [A, B, C] # <-- FOO is defined as an array - cmds: - - task: bar - vars: - FOO: '{{.FOO}}' # <-- FOO gets converted to a string when passed to bar - bar: - cmds: - - 'echo {{index .FOO 0}}' # <-- FOO is a string so the task outputs '91' which is the ASCII code for '[' instead of the expected 'A' -``` - -```yaml [Reference] -version: 3 - -tasks: - foo: - vars: - FOO: [A, B, C] # <-- FOO is defined as an array - cmds: - - task: bar - vars: - FOO: - ref: .FOO # <-- FOO gets passed by reference to bar and maintains its type - bar: - cmds: - - 'echo {{index .FOO 0}}' # <-- FOO is still a map so the task outputs 'A' as expected -``` - -::: - -This also works the same way when calling `deps` and when defining a variable -and can be used in any combination: - -```yaml -version: 3 - -tasks: - foo: - vars: - FOO: [A, B, C] # <-- FOO is defined as an array - BAR: - ref: .FOO # <-- BAR is defined as a reference to FOO - deps: - - task: bar - vars: - BAR: - ref: .BAR # <-- BAR gets passed by reference to bar and maintains its type - bar: - cmds: - - 'echo {{index .BAR 0}}' # <-- BAR still refers to FOO so the task outputs 'A' -``` - -All references use the same templating syntax as regular templates, so in -addition to calling `.FOO`, you can also pass subkeys (`.FOO.BAR`) or indexes -(`index .FOO 0`) and use functions (`len .FOO`) as described in the -[templating-reference][templating-reference]: - -```yaml -version: 3 - -tasks: - foo: - vars: - FOO: [A, B, C] # <-- FOO is defined as an array - cmds: - - task: bar - vars: - FOO: - ref: index .FOO 0 # <-- The element at index 0 is passed by reference to bar - bar: - cmds: - - 'echo {{.FOO}}' # <-- FOO is just the letter 'A' -``` - -### Parsing JSON/YAML into map variables - -If you have a raw JSON or YAML string that you want to process in Task, you can -use a combination of the `ref` keyword and the `fromJson` or `fromYaml` -templating functions to parse the string into a map variable. For example: - -```yaml -version: '3' - -tasks: - task-with-map: - vars: - JSON: '{"a": 1, "b": 2, "c": 3}' - FOO: - ref: 'fromJson .JSON' - cmds: - - echo {{.FOO}} -``` - -```txt -map[a:1 b:2 c:3] -``` - -### Secret variables - -Task supports marking variables as `secret` to prevent their values from being -displayed in command logs. When a variable is marked as secret, its value will -be replaced with `*****` in the task output logs. - -::: warning - -**Security Notice**: This feature helps prevent accidental exposure of secrets -in logs, but is **not a substitute** for proper secret management practices. - -**What this protects:** - -- ✅ Secret values in console/terminal logs -- ✅ Secret values in CI/CD logs -- ✅ Accidental copy-paste of logs containing secrets - -**What this does NOT protect:** - -- ❌ Secrets visible in process inspection (e.g., `ps aux`) -- ❌ Secrets in shell history -- ❌ 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. - -::: - -To mark a variable as secret, add `secret: true` to the variable definition: - -```yaml -version: '3' - -vars: - API_KEY: - value: 'sk-1234567890abcdef' - secret: true - -tasks: - deploy: - cmds: - - curl -H "Authorization: {{.API_KEY}}" api.example.com - # Logged as: task: [deploy] curl -H "Authorization: *****" api.example.com -``` - -Secret variables work with all variable types: - -::: code-group - -```yaml [Simple Value] -version: '3' - -vars: - PASSWORD: - value: 'my-secret-password' - secret: true - -tasks: - connect: - cmds: - - psql -U user -p {{.PASSWORD}} mydb - # Logged as: psql -U user -p ***** mydb -``` - -```yaml [Shell Command] -version: '3' - -vars: - DB_PASSWORD: - sh: vault read -field=password secret/db - secret: true - -tasks: - migrate: - cmds: - - psql -U admin -p {{.DB_PASSWORD}} mydb - # Password from vault is masked in logs -``` - -```yaml [Task-Level Secret] -version: '3' - -vars: - PUBLIC_URL: https://example.com - -tasks: - deploy: - vars: - DEPLOY_TOKEN: - value: 'secret-token-123' - secret: true - cmds: - - echo "Deploying to {{.PUBLIC_URL}} with token {{.DEPLOY_TOKEN}}" - # Logged as: echo "Deploying to https://example.com with token *****" -``` - -::: - -Multiple secrets in the same command are all masked: - -```yaml -version: '3' - -vars: - API_KEY: - value: 'api-key-123' - secret: true - PASSWORD: - value: 'password-456' - secret: true - -tasks: - setup: - cmds: - - ./setup.sh --api {{.API_KEY}} --pwd {{.PASSWORD}} - # Logged as: ./setup.sh --api ***** --pwd ***** -``` - -::: tip - -**Best practices for secret variables:** - -1. **Use shell commands to load secrets**, not hardcoded values: - - ```yaml - # ❌ BAD - Secret visible in Taskfile - vars: - API_KEY: - value: 'hardcoded-secret' - secret: true - - # ✅ GOOD - Secret loaded from external source - vars: - API_KEY: - sh: vault kv get -field=api_key secret/myapp - secret: true - ``` - -2. **Combine with environment variables:** - - ```yaml - vars: - API_KEY: - sh: echo $MY_API_KEY - secret: true - ``` - -3. **Use .gitignore for secret files:** - - If you use dotenv files, add them to `.gitignore`: - - ```yaml - dotenv: ['.env.local'] # Load from .env.local (in .gitignore) - ``` - -::: - -::: warning - -**Secrets are not propagated to derived variables.** The `secret` flag only -masks the variable it is set on. A non-secret variable that references a secret -will expose the resolved value in logs: - -```yaml -version: '3' - -vars: - API_KEY: - value: 'secret-api-key-123' - secret: true - HEADER: - value: 'Bearer {{.API_KEY}}' # ❌ not marked as secret - -tasks: - call: - cmds: - - curl -H "{{.HEADER}}" api.example.com - # Logged as: curl -H "Bearer secret-api-key-123" api.example.com (LEAK) -``` - -Mark every variable that carries a secret value as `secret: true`: - -```yaml -vars: - HEADER: - value: 'Bearer {{.API_KEY}}' - secret: true # ✅ masked -``` - -::: - -## Looping over values - -Task allows you to loop over certain values and execute a command for each. -There are a number of ways to do this depending on the type of value you want to -loop over. - -### Looping over a static list - -The simplest kind of loop is an explicit one. This is useful when you want to -loop over a set of values that are known ahead of time. - -```yaml -version: '3' - -tasks: - default: - cmds: - - for: ['foo.txt', 'bar.txt'] - cmd: cat {{ .ITEM }} -``` - -### Looping over a matrix - -If you need to loop over all permutations of multiple lists, you can use the -`matrix` property. This should be familiar to anyone who has used a matrix in a -CI/CD pipeline. - -```yaml -version: '3' - -tasks: - default: - silent: true - cmds: - - for: - matrix: - OS: ['windows', 'linux', 'darwin'] - ARCH: ['amd64', 'arm64'] - cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" -``` - -This will output: - -```txt -windows/amd64 -windows/arm64 -linux/amd64 -linux/arm64 -darwin/amd64 -darwin/arm64 -``` - -You can also use references to other variables as long as they are also lists: - -```yaml -version: '3' - -vars: - OS_VAR: ['windows', 'linux', 'darwin'] - ARCH_VAR: ['amd64', 'arm64'] - -tasks: - default: - cmds: - - for: - matrix: - OS: - ref: .OS_VAR - ARCH: - ref: .ARCH_VAR - cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" -``` - -### Looping over your task's sources or generated files - -You are also able to loop over the sources of your task or the files it -generates: - -::: code-group - -```yaml [Sources] -version: '3' - -tasks: - default: - sources: - - foo.txt - - bar.txt - cmds: - - for: sources - cmd: cat {{ .ITEM }} -``` - -```yaml [Generates] -version: '3' - -tasks: - default: - generates: - - foo.txt - - bar.txt - cmds: - - for: generates - cmd: cat {{ .ITEM }} -``` - -::: - -This will also work if you use globbing syntax in `sources` or `generates`. For -example, if you specify a source for `*.txt`, the loop will iterate over all -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. - -::: code-group - -```yaml [Sources] -version: '3' - -tasks: - default: - vars: - MY_DIR: /path/to/dir - dir: '{{.MY_DIR}}' - sources: - - foo.txt - - bar.txt - cmds: - - for: sources - cmd: cat {{joinPath .MY_DIR .ITEM}} -``` - -```yaml [Generates] -version: '3' - -tasks: - default: - vars: - MY_DIR: /path/to/dir - dir: '{{.MY_DIR}}' - generates: - - foo.txt - - bar.txt - cmds: - - for: generates - cmd: cat {{joinPath .MY_DIR .ITEM}} -``` - -::: - -### Looping over variables - -To loop over the contents of a variable, use the `var` key followed by the name -of the variable you want to loop over. By default, string variables will be -split on any whitespace characters. - -```yaml -version: '3' - -tasks: - default: - vars: - MY_VAR: foo.txt bar.txt - cmds: - - for: { var: MY_VAR } - cmd: cat {{.ITEM}} -``` - -If you need to split a string on a different character, you can do this by -specifying the `split` property: - -```yaml -version: '3' - -tasks: - default: - vars: - MY_VAR: foo.txt,bar.txt - cmds: - - for: { var: MY_VAR, split: ',' } - cmd: cat {{.ITEM}} -``` - -You can also loop over arrays and maps directly: - -```yaml -version: 3 - -tasks: - foo: - vars: - LIST: [foo, bar, baz] - cmds: - - for: - var: LIST - cmd: echo {{.ITEM}} -``` - -When looping over a map we also make an additional `{{.KEY}}` -variable available that holds the string value of the map key. Remember that -maps are unordered, so the order in which the items are looped over is random. - -All of this also works with dynamic variables! - -```yaml -version: '3' - -tasks: - default: - vars: - MY_VAR: - sh: find -type f -name '*.txt' - cmds: - - for: { var: MY_VAR } - cmd: cat {{.ITEM}} -``` - -### Renaming variables - -If you want to rename the iterator variable to make it clearer what the value -contains, you can do so by specifying the `as` property: - -```yaml -version: '3' - -tasks: - default: - vars: - MY_VAR: foo.txt bar.txt - cmds: - - for: { var: MY_VAR, as: FILE } - cmd: cat {{.FILE}} -``` - -### Looping over tasks - -Because the `for` property is defined at the `cmds` level, you can also use it -alongside the `task` keyword to run tasks multiple times with different -variables. - -```yaml -version: '3' - -tasks: - default: - cmds: - - for: [foo, bar] - task: my-task - vars: - FILE: '{{.ITEM}}' - - my-task: - cmds: - - echo '{{.FILE}}' -``` - -Or if you want to run different tasks depending on the value of the loop: - -```yaml -version: '3' - -tasks: - default: - cmds: - - for: [foo, bar] - task: task-{{.ITEM}} - - task-foo: - cmds: - - echo 'foo' - - task-bar: - cmds: - - echo 'bar' -``` - -### Looping over dependencies - -All of the above looping techniques can also be applied to the `deps` property. -This allows you to combine loops with concurrency: - -```yaml -version: '3' - -tasks: - default: - deps: - - for: [foo, bar] - task: my-task - vars: - FILE: '{{.ITEM}}' - - my-task: - cmds: - - echo '{{.FILE}}' -``` - -It is important to note that as `deps` are run in parallel, the order in which -the iterations are run is not guaranteed and the output may vary. For example, -the output of the above example may be either: - -```shell -foo -bar -``` - -or - -```shell -bar -foo -``` - -## Forwarding CLI arguments to commands - -If `--` is given in the CLI, all following parameters are added to a special -`.CLI_ARGS` variable. This is useful to forward arguments to another command. - -The below example will run `yarn install`. - -```shell -$ task yarn -- install -``` - -```yaml -version: '3' - -tasks: - yarn: - cmds: - - yarn {{.CLI_ARGS}} -``` - -## Wildcard arguments - -Another way to parse arguments into a task is to use a wildcard in your task's -name. Wildcards are denoted by an asterisk (`*`) and can be used multiple times -in a task's name to pass in multiple arguments. - -Matching arguments will be captured and stored in the `.MATCH` variable and can -then be used in your task's commands like any other variable. This variable is -an array of strings and so will need to be indexed to access the individual -arguments. We suggest creating a named variable for each argument to make it -clear what they contain: - -```yaml -version: '3' - -tasks: - start:*:*: - vars: - SERVICE: '{{index .MATCH 0}}' - REPLICAS: '{{index .MATCH 1}}' - cmds: - - echo "Starting {{.SERVICE}} with {{.REPLICAS}} replicas" - - start:*: - vars: - SERVICE: '{{index .MATCH 0}}' - cmds: - - echo "Starting {{.SERVICE}}" -``` - -This call matches the `start:*` task and the string "foo" is captured by the -wildcard and stored in the `.MATCH` variable. We then index the `.MATCH` array -and store the result in the `.SERVICE` variable which is then echoed out in the -cmds: - -```shell -$ task start:foo -Starting foo -``` - -You can use whitespace in your arguments as long as you quote the task name: - -```shell -$ task "start:foo bar" -Starting foo bar -``` - -If multiple matching tasks are found, the first one listed in the Taskfile will -be used. If you are using included Taskfiles, tasks in parent files will be -considered first. - -```shell -$ 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: - -```yaml -version: '3' - -tasks: - start:*: - aliases: [run:*] - vars: - SERVICE: '{{index .MATCH 0}}' - cmds: - - echo "Running {{.SERVICE}}" -``` - -In this example, you can call the task using the alias run:\*: - -```shell -$ task run:foo -Running foo -``` - -## Doing task cleanup with `defer` - -With the `defer` keyword, it's possible to schedule cleanup to be run once the -task finishes. The difference with just putting it as the last command is that -this command will run even when the task fails. - -In the example below, `rm -rf tmpdir/` will run even if the third command fails: - -```yaml -version: '3' - -tasks: - default: - cmds: - - mkdir -p tmpdir/ - - defer: rm -rf tmpdir/ - - echo 'Do work on tmpdir/' -``` - -If you want to move the cleanup command into another task, that is possible as -well: - -```yaml -version: '3' - -tasks: - default: - cmds: - - mkdir -p tmpdir/ - - defer: { task: cleanup } - - echo 'Do work on tmpdir/' - - cleanup: rm -rf tmpdir/ -``` - -::: info - -Due to the nature of how the -[Go's own `defer` work](https://go.dev/tour/flowcontrol/13), the deferred -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: - -```yaml -version: '3' - -tasks: - default: - cmds: - - defer: - echo '{{if .EXIT_CODE}}Failed with {{.EXIT_CODE}}!{{else}}Success!{{end}}' - - exit 1 -``` - -## Help - -Running `task --list` (or `task -l`) lists all tasks with a description. The -following Taskfile: - -```yaml -version: '3' - -tasks: - build: - desc: Build the go binary. - cmds: - - go build -v -i main.go - - test: - desc: Run all the go tests. - cmds: - - go test -race ./... - - js: - cmds: - - esbuild --bundle --minify js/index.js > public/bundle.js - - css: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css -``` - -would print the following output: - -```shell -* build: Build the go binary. -* test: Run all the go tests. -``` - -If you want to see all tasks, there's a `--list-all` (alias `-a`) flag as well. - -## Display summary of task - -Running `task --summary task-name` will show a summary of a task. The following -Taskfile: - -```yaml -version: '3' - -tasks: - release: - deps: [build] - summary: | - Release your project to github - - It will build your project before starting the release. - Please make sure that you have set GITHUB_TOKEN before starting. - cmds: - - your-release-tool - - build: - cmds: - - your-build-tool -``` - -with running `task --summary release` would print the following output: - -``` -task: release - -Release your project to github - -It will build your project before starting the release. -Please make sure that you have set GITHUB_TOKEN before starting. - -dependencies: - - build - -commands: - - your-release-tool -``` - -If a summary is missing, the description will be printed. If the task does not -have a summary or a description, a warning is printed. - -Please note: _showing the summary will not execute the command_. - -## Task aliases - -Aliases are alternative names for tasks. They can be used to make it easier and -quicker to run tasks with long or hard-to-type names. You can use them on the -command line, when [calling sub-tasks](#calling-another-task) in your Taskfile -and when [including tasks](#including-other-taskfiles) with aliases from another -Taskfile. They can also be used together with -[namespace aliases](#namespace-aliases). - -```yaml -version: '3' - -tasks: - generate: - aliases: [gen] - cmds: - - task: gen-mocks - - generate-mocks: - aliases: [gen-mocks] - cmds: - - echo "generating..." -``` - -## Overriding task name - -Sometimes you may want to override the task name printed on the summary, -up-to-date messages to STDOUT, etc. In this case, you can just set `label:`, -which can also be interpolated with variables: - -```yaml -version: '3' - -tasks: - default: - cmds: - - task: print - vars: - MESSAGE: hello - - task: print - vars: - MESSAGE: world - - print: - label: 'print-{{.MESSAGE}}' - cmds: - - echo "{{.MESSAGE}}" -``` - -## Warning Prompts - -Warning Prompts are used to prompt a user for confirmation before a task is -executed. - -Below is an example using `prompt` with a dangerous command, that is called -between two safe commands: - -```yaml -version: '3' - -tasks: - example: - cmds: - - task: not-dangerous - - task: dangerous - - task: another-not-dangerous - - not-dangerous: - cmds: - - echo 'not dangerous command' - - another-not-dangerous: - cmds: - - echo 'another not dangerous command' - - dangerous: - prompt: This is a dangerous command... Do you want to continue? - cmds: - - echo 'dangerous command' -``` - -```shell -❯ task dangerous -task: "This is a dangerous command... Do you want to continue?" [y/N] -``` - -Prompts can be a single value or a list of prompts, like below: - -```yaml -version: '3' - -tasks: - example: - cmds: - - task: dangerous - - dangerous: - prompt: - - This is a dangerous command... Do you want to continue? - - Are you sure? - cmds: - - echo 'dangerous command' -``` - -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. - -```shell -❯ task example -not dangerous command -task: "This is a dangerous command. Do you want to continue?" [y/N] -y -dangerous command -another not dangerous command -``` - -To skip warning prompts automatically, you can use the `--yes` (alias `-y`) -option when calling the task. By including this option, all warnings, will be -automatically confirmed, and no prompts will be shown. - -::: warning - -Tasks with prompts always fail by default on non-terminal environments, like a -CI, where an `stdin` won't be available for the user to answer. In those cases, -use `--yes` (`-y`) to force all tasks with a prompt to run. - -::: - -## Silent mode - -Silent mode disables the echoing of commands before Task runs it. For the -following Taskfile: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - echo "Print something" -``` - -Normally this will be printed: - -```shell -echo "Print something" -Print something -``` - -With silent mode on, the below will be printed instead: - -```shell -Print something -``` - -There are four ways to enable silent mode: - -- At command level: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - cmd: echo "Print something" - silent: true -``` - -- At task level: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - echo "Print something" - silent: true -``` - -- Globally at Taskfile level: - -```yaml -version: '3' - -silent: true - -tasks: - echo: - cmds: - - echo "Print something" -``` - -- Or globally with `--silent` or `-s` flag - -If you want to suppress STDOUT instead, just redirect a command to `/dev/null`: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - echo "This will print nothing" > /dev/null -``` - -## Dry run mode - -Dry run mode (`--dry`) compiles and steps through each task, printing the -commands that would be run without executing them. This is useful for debugging -your Taskfiles. - -## Ignore errors - -You have the option to ignore errors during command execution. Given the -following Taskfile: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - exit 1 - - echo "Hello World" -``` - -Task will abort the execution after running `exit 1` because the status code `1` -stands for `EXIT_FAILURE`. However, it is possible to continue with execution -using `ignore_error`: - -```yaml -version: '3' - -tasks: - echo: - cmds: - - cmd: exit 1 - ignore_error: true - - echo "Hello World" -``` - -`ignore_error` can also be set for a task, which means errors will be suppressed -for all commands. Nevertheless, keep in mind that this option will not propagate -to other tasks called either by `deps` or `cmds`! - -## Output syntax - -By default, Task just redirects the STDOUT and STDERR of the running commands to -the shell in real-time. This is good for having live feedback for logging -printed by commands, but the output can become messy if you have multiple -commands running simultaneously and printing lots of stuff. - -To make this more customizable, there are currently three different output -options you can choose: - -- `interleaved` (default) -- `group` -- `prefixed` - -To choose another one, just set it to root in the Taskfile: - -```yaml -version: '3' - -output: 'group' - -tasks: - # ... -``` - -The `group` output will print the entire output of a command once after it -finishes, so you will not have live feedback for commands that take a long time -to run. - -When using the `group` output, you can optionally provide a templated message to -print at the start and end of the group. This can be useful for instructing CI -systems to group all of the output for a given task, such as with -[GitHub Actions' `::group::` command](https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#grouping-log-lines) -or -[Azure Pipelines](https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?expand=1&view=azure-devops&tabs=bash#formatting-commands). - -```yaml -version: '3' - -output: - group: - begin: '::group::{{.TASK}}' - end: '::endgroup::' - -tasks: - default: - cmds: - - echo 'Hello, World!' - silent: true -``` - -```shell -$ task default -::group::default -Hello, World! -::endgroup:: -``` - -When using the `group` output, you may swallow the output of the executed -command on standard output and standard error if it does not fail (zero exit -code). - -```yaml -version: '3' - -silent: true - -output: - group: - error_only: true - -tasks: - passes: echo 'output-of-passes' - errors: echo 'output-of-errors' && exit 1 -``` - -```shell -$ task passes -$ task errors -output-of-errors -task: Failed to run task "errors": exit status 1 -``` - -The `prefix` output will prefix every line printed by a command with -`[task-name] ` as the prefix, but you can customize the prefix for a command -with the `prefix:` attribute: - -```yaml -version: '3' - -output: prefixed - -tasks: - default: - deps: - - task: print - vars: { TEXT: foo } - - task: print - vars: { TEXT: bar } - - task: print - vars: { TEXT: baz } - - print: - cmds: - - echo "{{.TEXT}}" - prefix: 'print-{{.TEXT}}' - silent: true -``` - -```shell -$ task default -[print-foo] foo -[print-bar] bar -[print-baz] baz -``` - -::: tip - -The `output` option can also be specified by the `--output` or `-o` flags. - -::: - -## CI Integration - -### Colored output - -Task automatically enables colored output when running in CI environments -(`CI=true`). Most CI providers set this variable automatically. - -You can also force colored output with `FORCE_COLOR=1` or disable it with -`NO_COLOR=1`. - -### Error annotations - -When running in GitHub Actions (`GITHUB_ACTIONS=true`), Task automatically emits -error annotations when a task fails. These annotations appear in the workflow -summary, making it easier to spot failures without scrolling through logs. - -```shell -::error title=Task 'build' failed::exit status 1 -``` - -This feature requires no configuration and works automatically. - -## Interactive CLI application - -When running interactive CLI applications inside Task they can sometimes behave -weirdly, especially when the [output mode](#output-syntax) is set to something -other than `interleaved` (the default), or when interactive apps are run in -parallel with other tasks. - -The `interactive: true` tells Task this is an interactive application and Task -will try to optimize for it: - -```yaml -version: '3' - -tasks: - default: - cmds: - - vim my-file.txt - interactive: true -``` - -If you still have problems running an interactive app through Task, please open -an issue about it. - -## Short task syntax - -Starting on Task v3, you can now write tasks with a shorter syntax if they have -the default settings (e.g. no custom `env:`, `vars:`, `desc:`, `silent:` , etc): - -```yaml -version: '3' - -tasks: - build: go build -v -o ./app{{exeExt}} . - - run: - - task: build - - ./app{{exeExt}} -h localhost -p 8080 -``` - -## `set` and `shopt` - -It's possible to specify options to the -[`set`](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html) -and -[`shopt`](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) -builtins. This can be added at global, task or command level. - -```yaml -version: '3' - -set: [pipefail] -shopt: [globstar] - -tasks: - # `globstar` required for double star globs to work - default: echo **/*.go -``` - -::: info - -Keep in mind that not all options are available in the -[shell interpreter library](https://github.com/mvdan/sh) that Task uses. - -::: - -## Watch tasks - -With the flags `--watch` or `-w` task will watch for file changes and run the -task again. This requires the `sources` attribute to be given, so task knows -which files to watch. - -The default watch interval is 100 milliseconds, but it's possible to change it -by either setting `interval: '500ms'` in the root of the Taskfile or by passing -it as an argument like `--interval=500ms`. This interval is the time Task will -wait for duplicated events. It will only run the task again once, even if -multiple changes happen within the interval. - -Also, it's possible to set `watch: true` in a given task and it'll automatically -run in watch mode: - -```yaml -version: '3' - -interval: 500ms - -tasks: - build: - desc: Builds the Go application - watch: true - sources: - - '**/*.go' - cmds: - - go build # ... -``` - -::: info - -Note that when setting `watch: true` to a task, it'll only run in watch mode -when running from the CLI via `task my-watch-task`, but won't run in watch mode -if called by another task, either directly or as a dependency. - -::: - -::: warning - -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. - -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 -[report any issues](https://github.com/go-task/task/issues/new?template=bug_report.yml) -to us. - -::: - -[config]: /docs/reference/config -[gotemplate]: https://golang.org/pkg/text/template/ -[templating-reference]: /docs/reference/templating diff --git a/website/src/latest/docs/guide/arguments.md b/website/src/latest/docs/guide/arguments.md new file mode 100644 index 00000000..4daeea1b --- /dev/null +++ b/website/src/latest/docs/guide/arguments.md @@ -0,0 +1,140 @@ +--- +title: Command-line arguments +description: + Supply variables with NAME=value, forward arguments after --, and capture + values with wildcard task names. +section: Guide +docType: guide +outline: deep +--- + +# Command-line arguments {#passing-arguments} + +Choose how to pass input based on what needs to receive it: + +| Input | Example | Read it with | +| ----------------------- | ---------------------- | --------------------------------------- | +| A Task variable | `task greet NAME=Bob` | `{{.NAME}}` | +| Arguments for a command | `task yarn -- install` | `{{.CLI_ARGS}}` | +| Part of a task name | `task start:api` | `{{index .MATCH 0}}` | + +## Pass named values {#variable-assignments} + +Pass `NAME=value` to supply a Task variable. A default in the root `vars` block +can be overridden from the command line: + +```yaml +version: '3' + +vars: + NAME: World + +tasks: + greet: + cmds: + - echo "Hello, {{.NAME}}!" +``` + +```shell +task greet NAME=Bob +task greet "NAME=Jane Doe" +``` + +Quote assignments that contain spaces. These assignments work across shells, +including Windows, and are shared by all tasks in the invocation: + +```shell +task build test ENV=production +``` + +A value declared in a task's own `vars` can override the command-line value. See +[variable resolution](./variables.md#resolution-order) for precedence and +configurable defaults. To set values in a command's shell environment, see +[Environment variables](./environment.md). + +## Forward command arguments {#forwarding-cli-arguments-to-commands} + +Everything after `--` is available in `.CLI_ARGS`, including values containing +`=`. Insert it into a command to forward those arguments. This example runs +`yarn install`: + +```shell +$ task yarn -- install +``` + +```yaml +version: '3' + +tasks: + yarn: + cmds: + - yarn {{.CLI_ARGS}} +``` + +## Capture task-name inputs {#wildcard-arguments} + +Use `*` in a task name to turn a call such as `task start:api` into an input. +Task captures each wildcard in the `.MATCH` array. Give the captured values +names with `vars` so their meaning stays clear: + +```yaml +version: '3' + +tasks: + start:*:*: + vars: + SERVICE: '{{index .MATCH 0}}' + REPLICAS: '{{index .MATCH 1}}' + cmds: + - echo "Starting {{.SERVICE}} with {{.REPLICAS}} replicas" + + start:*: + vars: + SERVICE: '{{index .MATCH 0}}' + cmds: + - echo "Starting {{.SERVICE}}" +``` + +The first captured value becomes `SERVICE`: + +```shell +$ task start:foo +Starting foo +``` + +You can use whitespace in your arguments as long as you quote the task name: + +```shell +$ task "start:foo bar" +Starting foo bar +``` + +If multiple matching tasks are found, the first one listed in the Taskfile will +be used. If you are using included Taskfiles, tasks in parent files will be +considered first. + +```shell +$ task start:foo:3 +Starting foo with 3 replicas +``` + +Wildcard task names also work with aliases: + +```yaml +version: '3' + +tasks: + start:*: + aliases: [run:*] + vars: + SERVICE: '{{index .MATCH 0}}' + cmds: + - echo "Running {{.SERVICE}}" +``` + +Call the task through the `run:*` alias: + +```shell +$ task run:foo +Running foo +``` diff --git a/website/src/latest/docs/guide/conditional-execution.md b/website/src/latest/docs/guide/conditional-execution.md new file mode 100644 index 00000000..77d88628 --- /dev/null +++ b/website/src/latest/docs/guide/conditional-execution.md @@ -0,0 +1,186 @@ +--- +title: Conditional execution +description: + Skip optional work with if, enforce requirements with preconditions, and ask + for confirmation before execution with prompt. +section: Guide +docType: guide +outline: deep +--- + +# Conditional execution + +Decide what a failed check should mean before choosing a setting: skip optional +work, stop with an error, or ask the user whether to continue. + +| What do you need? | Use | +| -------------------------------- | ---------------------------------------------------------------------------------------------------- | +| Skip optional work | [`if`](#conditional-execution-with-if) | +| Stop when a requirement is unmet | [`preconditions`](#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies) | +| Ask before executing commands | [`prompt`](#confirmation-prompts) | +| Skip work already completed | [Up-to-date checks](./up-to-date.md) | + +## Skip optional work {#conditional-execution-with-if} + +An `if` condition is a shell command. Exit code `0` allows execution; a non-zero +exit code skips the guarded task or command without failing the run. + +### Skip a whole task {#task-level-if} + +Use a task-level condition for optional work. This task only runs when a `docs/` +directory exists: + +```yaml +version: '3' + +tasks: + docs: + if: test -d docs + cmds: + - echo 'Building documentation' +``` + +Run `task docs` with and without the directory. If it is absent, Task skips the +task and its dependencies. Other tasks in the invocation can continue. + +### Skip one command {#command-level-if} + +Put `if` on a command when the rest of the task should still run: + +```yaml +version: '3' + +tasks: + build: + cmds: + - cmd: echo 'Building documentation' + if: test -d docs + - echo 'Building the application' +``` + +`task build` always prints the application message. It prints the documentation +message first only if `docs/` exists. + +### Check a Task variable {#using-templates-in-if-conditions} + +Template comparisons produce `true` or `false`, which are also shell commands +with the corresponding exit codes. Put a configurable default at the root: + +```yaml +version: '3' + +vars: + ENABLE_FEATURE: 'false' + +tasks: + feature: + if: '{{eq .ENABLE_FEATURE "true"}}' + cmds: + - echo 'Feature is enabled' +``` + +`task feature ENABLE_FEATURE=true` runs the command. Without that override, Task +skips it. + +### Filter loop iterations {#using-if-with-for-loops} + +A command's condition is evaluated for each iteration, with that iteration's +values: + +```yaml +version: '3' + +tasks: + process-items: + cmds: + - for: ['a', 'b', 'c'] + cmd: echo "processing {{.ITEM}}" + if: '[ "{{.ITEM}}" != "b" ]' +``` + +Run `task process-items` to print `processing a` and `processing c`. See +[Loops](./loops.md) for the other iteration forms. + +## Enforce a requirement {#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies} + +Use `preconditions` when missing a requirement should fail the task. Every check +must exit with code `0`. Add `msg` to explain how to resolve a failure: + +```yaml +version: '3' + +tasks: + generate-files: + preconditions: + - sh: test -f .env + msg: 'Create a .env file before generating files.' + cmds: + - mkdir -p directory + - touch directory/file.txt +``` + +`task generate-files` fails with the message if `.env` is missing. Create the +file and run it again to generate `directory/file.txt`. + +A plain shell string also works when no custom message is needed. A failed +precondition fails tasks that call or depend on this task. Dependencies of the +checked task have already run before its preconditions are evaluated; put a +check on the task whose commands need protecting. + +`--force` bypasses preconditions as well as up-to-date checks. + +### Choose skip or failure {#if-vs-preconditions} + +Use `if` when skipping is an acceptable result. Use `preconditions` when a +caller should receive an error instead. To require a variable or restrict its +allowed values, use [Validation and prompts](./required-variables.md). + +## Ask for confirmation {#confirmation-prompts} + +Use `prompt` to ask for approval before a task's commands run. For example, this +task asks before deleting a local build directory: + +```yaml +version: '3' + +tasks: + clean: + prompt: Remove the local build directory? + cmds: + - rm -rf build/ +``` + +Run `task clean` in a terminal and answer the confirmation. Declining stops the +task with [exit code](../reference/cli.md#exit-codes) `205`. + +Unlike +[prompts for missing input](./required-variables.md#prompting-for-missing-variables-interactively), +confirmation prompts do not require `--interactive`. Supplying every required +variable does not bypass them. + +For several confirmations, use a list: + +```yaml +prompt: + - Remove the local build directory? + - Have you saved everything you need from it? +``` + +Task asks after dependencies have completed and before running `cmds`. If +approval must precede other tasks, call them from `cmds` in the prompted task +instead of listing them as dependencies. + +Use `task --yes clean` (or `task -y clean`) to accept automatically. In CI or +another environment without a terminal, confirmation fails unless automatic +acceptance is enabled. + +::: tip Related guide + + + +To control how often a task runs when several tasks call it, use +[`run: once` or `run: when_changed`](./dependencies.md#repeated-calls). These +settings apply within one invocation. Use [up-to-date checks](./up-to-date.md) +to skip completed work across invocations. + +::: diff --git a/website/src/latest/docs/guide/defining-tasks.md b/website/src/latest/docs/guide/defining-tasks.md new file mode 100644 index 00000000..cd9eb415 --- /dev/null +++ b/website/src/latest/docs/guide/defining-tasks.md @@ -0,0 +1,229 @@ +--- +title: Defining tasks +description: + Task syntax shortcuts, internal tasks, aliases, the directory a task runs in, + and the help text Task shows for it. +section: Guide +docType: guide +outline: deep +searchKeywords: + task-aliases: [aliases, task aliases] +--- + +# Defining tasks + +Define tasks under `tasks`. Each task has a name and a list of commands in +`cmds`. Add `desc` to explain what a task does: + +```yaml +version: '3' + +tasks: + greet: + desc: Print a greeting + cmds: + - echo "Hello, World!" +``` + +Run `task greet` to execute it, or `task --list` to see its description. See +[Running tasks](./running-tasks.md) for selecting a Taskfile and previewing +commands. + +## Choose a task name + +The name under `tasks` is the name you pass to the CLI. Call your main task +`default` if it should run when someone types `task` without a name. + +Use `desc` for the short explanation shown by `task --list`, `aliases` for +alternative names, and `label` to customize log messages. The sections below +show each independently. + +## Use command shortcuts {#short-task-syntax} + +Use shorthand syntax for tasks that only need commands. Use the full form when +you need properties such as `env`, `vars`, `desc` or `silent`: + +```yaml +version: '3' + +tasks: + build: go build -v -o ./app{{exeExt}} . + + run: + - task: build + - ./app{{exeExt}} -h localhost -p 8080 +``` + +## Keep helpers internal {#internal-tasks} + +Set `internal: true` on a helper that should only be called by other tasks. It +stays out of `task --list` and `task --list-all`, and a direct CLI call fails. +Expose a public task that supplies the helper's inputs: + +```yaml +version: '3' + +tasks: + build-image-1: + cmds: + - task: build-image + vars: + DOCKER_IMAGE: image-1 + + build-image: + internal: true + cmds: + - docker build -t {{.DOCKER_IMAGE}} . +``` + +## Set the working directory {#task-directory} + +Set `dir` when commands need to run in a subdirectory. Relative paths are +resolved from the Taskfile's execution directory: + +```yaml +version: '3' + +tasks: + serve: + dir: public/www + cmds: + # run http server + - caddy +``` + +Run `task serve` to start the server in `public/www`. Task creates the directory +if it does not exist. For included Taskfiles, configure the +[include directory](./includes.md#directory-of-included-taskfile). + +## Add shorter names {#task-aliases} + +Aliases are alternative names for tasks. They can be used to make it easier and +quicker to run tasks with long or hard-to-type names. You can use them on the +command line, when [calling sub-tasks](./dependencies.md#calling-another-task) +in your Taskfile and when [including tasks](./includes.md) with aliases from +another Taskfile. They can also be used together with +[namespace aliases](./includes.md#namespace-aliases). + +```yaml +version: '3' + +tasks: + generate: + aliases: [gen] + cmds: + - task: gen-mocks + + generate-mocks: + aliases: [gen-mocks] + cmds: + - echo "generating..." +``` + +## Customize log labels {#overriding-task-name} + +Use `label` to customize the name shown in summaries and status messages. Labels +can contain templates. They do not rename the task you call: + +```yaml +version: '3' + +tasks: + default: + cmds: + - task: print + vars: + MESSAGE: hello + - task: print + vars: + MESSAGE: world + + print: + label: 'print-{{.MESSAGE}}' + cmds: + - echo "{{.MESSAGE}}" +``` + +## Describe public tasks {#help} + +Running `task --list` (or `task -l`) lists all tasks with a description. The +following Taskfile: + +```yaml +version: '3' + +tasks: + build: + desc: Build the Go binary. + cmds: + - go build -v main.go + + test: + desc: Run all Go tests. + cmds: + - go test -race ./... + + js: + cmds: + - esbuild --bundle --minify js/index.js > public/bundle.js + + css: + cmds: + - esbuild --bundle --minify css/index.css > public/bundle.css +``` + +would print the following output: + +```shell +* build: Build the Go binary. +* test: Run all Go tests. +``` + +Use `--list-all` (or `-a`) to also list tasks without a description. Internal +tasks remain hidden. + +## Explain a task in detail {#display-summary-of-task} + +Running `task --summary task-name` will show a summary of a task. The following +Taskfile: + +```yaml +version: '3' + +tasks: + release: + deps: [build] + summary: | + Release your project to GitHub + + It will build your project before starting the release. + Please make sure that you have set GITHUB_TOKEN before starting. + cmds: + - your-release-tool + + build: + cmds: + - your-build-tool +``` + +`task --summary release` prints: + +``` +task: release + +Release your project to GitHub + +It will build your project before starting the release. +Please make sure that you have set GITHUB_TOKEN before starting. + +dependencies: + - build + +commands: + - your-release-tool +``` + +If a summary is missing, the description will be printed. If the task does not +have a summary or a description, a warning is printed. + +Showing a summary does not execute the task. diff --git a/website/src/latest/docs/guide/dependencies.md b/website/src/latest/docs/guide/dependencies.md new file mode 100644 index 00000000..b406d780 --- /dev/null +++ b/website/src/latest/docs/guide/dependencies.md @@ -0,0 +1,266 @@ +--- +title: Dependencies and task calls +description: + Run checks before a build, put tasks in order, pass variables, and control + repeated calls and cleanup. +section: Guide +docType: guide +outline: deep +--- + +# Dependencies and task calls + +A build often needs several steps: lint the code, run tests, then compile. Use +`deps` when the checks can run in parallel, or task calls in `cmds` when each +step must finish before the next starts. + +## Run dependencies first {#task-dependencies} + +In a Go project, this Taskfile runs lint and tests before building: + +```yaml +version: '3' + +tasks: + build: + deps: [lint, test] + cmds: + - go build ./... + + lint: + cmds: + - go vet ./... + + test: + cmds: + - go test ./... +``` + +Run `task build`. Task starts `lint` and `test` concurrently and waits for both +to succeed before running `go build`. If either fails, the build command does +not run. + +The order of entries in `deps` does not set their execution order. Use +[task calls in `cmds`](#calling-another-task) if tests must wait for lint to +finish. + +You can also group tasks without adding commands. Add this task to the same +Taskfile to run only the checks with `task check`: + +```yaml +tasks: + check: + deps: [lint, test] +``` + +## Run task calls in order {#calling-another-task} + +To run lint, then tests, then the build, replace `build` in the example above +with: + +```yaml +tasks: + build: + cmds: + - task: lint + - task: test + - go build ./... +``` + +Task waits for each command or task call to succeed before starting the next. If +lint fails, neither tests nor the build run. + +Each called task still runs its own dependencies first. You can combine the two +forms: use `deps` for independent prerequisites and `cmds` for the steps that +need an order. + +::: tip Calling tasks from another Taskfile + +To call a task declared in the root Taskfile from an +[included Taskfile](./includes.md), add a leading `:`, for example +`task: :build`. + +::: + +## Pass variables to a task + +Use the object form of a task call to provide `vars`. You can also set +`silent: true` to hide the command being executed for that call: + +```yaml +version: '3' + +tasks: + greet: + cmds: + - echo "Hello, {{.RECIPIENT}}!" + + greet:all: + cmds: + - task: greet + vars: { RECIPIENT: 'World' } + - task: greet + vars: { RECIPIENT: 'Cruel World' } + silent: true +``` + +`task greet:all` prints both greetings in order. The second call still prints +its greeting: [silent mode](./output.md#silent-mode) hides the command, not its +output. + +The same `task`, `vars`, and `silent` fields work in `deps`. Use +[references](./variables.md#referencing-other-variables) to pass arrays and maps +without turning them into strings. To call a task for each value in a list, see +[Looping over tasks](./loops.md#looping-over-tasks). + +## Control parallel work + +Dependencies run concurrently by default. To run tasks from the command line in +parallel too, use `task --parallel lint test` (or `task -p lint test`). + +### Limit concurrent tasks {#limiting-how-much-runs-at-once} + +Use `--concurrency` (or `-C`) when tasks compete for resources such as database +connections or memory: + +```shell +task --concurrency 2 build +``` + +The default is `0`, meaning no limit. A limit of `1` restricts concurrency but +does not establish an order between dependencies; use task calls in `cmds` when +order matters. + +### Cancel on failure {#fail-fast-dependencies} + +By default, Task lets the other dependencies finish if one fails. In either +case, the parent task's commands do not run after a dependency failure. + +Set `failfast: true` on a task to cancel its remaining dependency work when one +dependency fails. For the build example: + +```yaml +tasks: + build: + deps: [lint, test] + failfast: true + cmds: + - go build ./... +``` + +Already-running commands receive cancellation; this does not undo work they have +completed. You can also set `failfast: true` in [`.taskrc.yml`][config] or use +`task --failfast build`. The CLI flag also applies to tasks started with +`--parallel`. + +### Read parallel output {#interleaved-output-is-expected} + +Concurrent tasks can interleave their output, and the order may change between +runs. Set `output: prefixed` to label each line with its task, or +`output: group` to print each command's buffered output in one block when that +command finishes. A group is per command, so blocks from different tasks can +still alternate. See [Output and logging](./output.md) for examples. + +## Control repeated calls {#repeated-calls} + +A shared dependency can be reached through several tasks. By default, Task +attempts to run it for each call. Use `run` to control repeated calls within one +invocation: + +| Value | Behavior | +| ------------------ | ------------------------------------------------- | +| `always` (default) | Attempt to run the task on every call. | +| `once` | Run the task once, even if it is called again. | +| `when_changed` | Run once for each distinct set of call variables. | + +Set `run` on a task, or at the root of the Taskfile to provide a default for all +tasks. A task's own setting takes precedence. + +### Run shared setup once {#running-a-task-only-once} + +If lint and tests both need setup, mark the setup task with `run: once`: + +```yaml +version: '3' + +tasks: + check: + deps: [lint, test] + + lint: + deps: [setup] + cmds: + - echo "Linting" + + test: + deps: [setup] + cmds: + - echo "Testing" + + setup: + run: once + cmds: + - echo "Setting up" +``` + +`task check` prints `Setting up` once. Both lint and tests wait for that setup +to finish. Without `run: once`, setup runs for each task that depends on it. + +### Run once per input {#once-per-set-of-variables} + +Use `run: when_changed` when a task may be called several times with the same +inputs: + +```yaml +version: '3' + +tasks: + default: + cmds: + - task: generate + vars: { CONTENT: '1' } + - task: generate + vars: { CONTENT: '2' } + - task: generate + vars: { CONTENT: '2' } + + generate: + run: when_changed + cmds: + - echo {{.CONTENT}} +``` + +This prints `1` and `2`. The third call repeats the second call's variables and +is skipped. + +The `run` settings do not remember earlier invocations of Task. To skip work +when files or external artifacts have not changed, use +[up-to-date checks](./up-to-date.md). + +## Clean up after a task {#doing-task-cleanup-with-defer} + +Use `defer` when a task acquires a resource that needs to be released. For +example, this task starts Docker Compose services, runs integration tests, and +stops the services even if the tests fail: + +```yaml +version: '3' + +tasks: + integration: + cmds: + - docker compose up -d + - defer: docker compose down + - go test -tags=integration ./... +``` + +Cleanup is registered when Task reaches the `defer` entry. Dependencies run +before `cmds`, so a failed dependency prevents that registration. Keep the +resource setup, `defer`, and the work that uses the resource in the command +sequence, as above. + +For multiple cleanup steps, cleanup tasks, and inspecting failures with +`.EXIT_CODE`, see +[Errors and cleanup](./errors-and-cleanup.md#cleanup-with-defer). + +[config]: ../reference/config.md diff --git a/website/src/latest/docs/guide/environment.md b/website/src/latest/docs/guide/environment.md new file mode 100644 index 00000000..6010f617 --- /dev/null +++ b/website/src/latest/docs/guide/environment.md @@ -0,0 +1,142 @@ +--- +title: Environment variables +description: + Set environment variables on a single task or on every task, and load them + from `.env` files. +section: Guide +docType: guide +outline: deep +--- + +# Environment variables + +Use `env` for values a program reads from its environment. In this example, the +shell reads `GREETING` with `$GREETING`: + +```yaml +version: '3' + +tasks: + greet: + env: + GREETING: Hello, World! + cmds: + - echo "$GREETING" +``` + +Run `task greet` to print the greeting. Task uses the same shell syntax on +supported platforms, including Windows. For values used in Task templates, use +[Variables](./variables.md#env-and-vars-are-not-the-same-thing). + +## Set values for commands {#task} + +Put `env` on a task to configure its commands, or at the root to provide values +for every task: + +```yaml +version: '3' + +env: + GREETING: Hello, World! + +tasks: + greet: + cmds: + - echo "$GREETING" + + greet:local: + env: + GREETING: Hello from this task! + cmds: + - echo "$GREETING" +``` + +With no `GREETING` in the process environment, `task greet` uses the root value +and `task greet:local` uses the task's value. + +By default, a variable already present in the process environment takes +precedence over Taskfile `env` values. If the result differs from the example, +check the environment used to launch Task. The +[Env Precedence experiment](../experiments/env-precedence.md) changes this rule. + +`env` values support templates and dynamic `sh` commands. For example, an entry +`BUILD_MODE: '{{.MODE}}'` exports a Task variable to a +command's environment. A `vars` entry alone is not exported to commands in +`cmds`. + +## Load values from files {#env-files} + +Use `dotenv` to load values from files instead of repeating them in the +Taskfile. Create these two files in your project: + +::: code-group + +```dotenv [.env] +GREETING=Hello from .env! +``` + +```yaml [Taskfile.yml] +version: '3' + +dotenv: ['.env'] + +tasks: + greet: + cmds: + - echo "$GREETING" +``` + +::: + +Run `task greet` to use the value from `.env`, assuming the process environment +does not already set `GREETING`. + +### Choose file precedence + +When several dotenv files define a name, the **first file wins**. Put local +overrides before shared defaults: + +```yaml +version: '3' + +vars: + ENV: development + +tasks: + greet: + dotenv: + - .env.local + - .env.{{.ENV}} + - .env + cmds: + - echo "$GREETING" +``` + +`task greet ENV=testing` selects `.env.testing` for the middle entry. This +example puts `dotenv` on the task so it can use call variables; root-level +dotenv files are loaded before those variables are available. Missing dotenv +files are skipped. Keep files containing local credentials out of version +control. + +### Load values for one task + +Put `dotenv` on a task when only that task needs the file. Explicit task-level +`env` values take precedence over values loaded from dotenv files: + +```yaml +version: '3' + +tasks: + greet: + dotenv: ['.env'] + env: + GREETING: Hello from the task! + cmds: + - echo "$GREETING" +``` + +The process environment still takes precedence by default. Dotenv paths can +contain templates, as in `'{{.HOME}}/.env'`. + +The `dotenv` key is not supported inside included Taskfiles. Load shared values +in the entrypoint Taskfile instead. See [Including Taskfiles](./includes.md). diff --git a/website/src/latest/docs/guide/errors-and-cleanup.md b/website/src/latest/docs/guide/errors-and-cleanup.md new file mode 100644 index 00000000..a915eb68 --- /dev/null +++ b/website/src/latest/docs/guide/errors-and-cleanup.md @@ -0,0 +1,97 @@ +--- +title: Errors and cleanup +description: + Continue after selected command failures with ignore_error, schedule cleanup + with defer, and inspect a failed command's exit code. +section: Guide +docType: guide +outline: deep +--- + +# Errors and cleanup + +By default, a failed command stops its task. Use `ignore_error` when a failure +can be tolerated, and `defer` for cleanup that must run after work finishes. For +concurrent dependencies, see +[fail-fast behavior](./dependencies.md#fail-fast-dependencies). + +## Clean up after a task {#cleanup-with-defer} + +Schedule a cleanup command with `defer`. Once Task reaches that entry in `cmds`, +it registers the command to run when the task finishes, including if a later +command fails. Deferred commands run in reverse order of registration. A `defer` +that Task never reaches is not registered, for example when an earlier command +or a dependency fails. + +In this example, Task removes `tmpdir/` after the work command finishes: + +```yaml +version: '3' + +tasks: + default: + cmds: + - mkdir -p tmpdir/ + - defer: rm -rf tmpdir/ + - echo 'Work completed' > tmpdir/result.txt +``` + +Run `task`, then check that `tmpdir/` was removed. Replace the last command with +`exit 1` to try the failure path: cleanup still runs and Task reports the +failure. The directory name here is for the example; choose a task-specific path +for real work. + +### Reuse a cleanup task + +Use a deferred task call when several tasks share the same cleanup: + +```yaml +version: '3' + +tasks: + default: + cmds: + - mkdir -p tmpdir/ + - defer: { task: cleanup } + - echo 'Work completed' > tmpdir/result.txt + + cleanup: rm -rf tmpdir/ +``` + +### Inspect a failed command + +A special variable `.EXIT_CODE` is exposed when a command exited with a non-zero +[exit code](../reference/cli.md#exit-codes). You can check its presence to know +if the task completed successfully or not: + +```yaml +version: '3' + +tasks: + default: + cmds: + - defer: + echo '{{if .EXIT_CODE}}Failed with + {{.EXIT_CODE}}!{{else}}Success!{{end}}' + - exit 1 +``` + +## Continue after an error {#ignoring-command-errors} + +Set `ignore_error: true` on a command to continue after it fails: + +```yaml +version: '3' + +tasks: + example: + cmds: + - cmd: exit 1 + ignore_error: true + - echo "Continuing after the failed command" +``` + +Without `ignore_error`, the `echo` command would not run. + +You can also set `ignore_error` on a task to apply it to that task's commands. +The setting does not propagate to other tasks called through `cmds` or `deps`. diff --git a/website/src/latest/docs/guide/includes.md b/website/src/latest/docs/guide/includes.md new file mode 100644 index 00000000..befc904b --- /dev/null +++ b/website/src/latest/docs/guide/includes.md @@ -0,0 +1,247 @@ +--- +title: Including Taskfiles +description: + Reuse tasks across projects with `includes`, covering namespaces, optional and + internal includes, flattening, and per-include variables. +section: Guide +docType: guide +outline: deep +searchKeywords: + namespace-aliases: [aliases, namespace aliases] +--- + +# Including Taskfiles {#including-other-taskfiles} + +Use `includes` to split a project into smaller Taskfiles or reuse tasks across +projects. Give each included file a namespace, then call its tasks through that +name. + +Start with a Markdown file at `docs/README.md`, then create these two Taskfiles: + +::: code-group + +```yaml [Taskfile.yml] +version: '3' + +includes: + docs: + taskfile: ./docs/Taskfile.yml + dir: ./docs +``` + +```yaml [docs/Taskfile.yml] +version: '3' + +tasks: + build: + cmds: + - mkdir -p build + - cp README.md build/index.md +``` + +::: + +Run `task docs:build` to copy `docs/README.md` to `docs/build/index.md`. The +`docs` namespace comes from the include key, not the directory name. You can +also call `docs:build` from another task's `cmds` or `deps`. + +An include path can point to a file or a directory. With `docs: ./docs`, Task +looks for a supported Taskfile name in that directory. Paths are relative to the +including file, and included Taskfiles must use the same schema version. + +## Set the working directory {#directory-of-included-taskfile} + +The `dir: ./docs` setting makes the included task read `docs/README.md` and +write into `docs/build/`, even when you run `task docs:build` from the project +root. + +Without `dir`, included tasks use the including Taskfile's execution directory. +The same commands would look for `README.md` and create `build/` at the project +root. A Taskfile's location alone does not set its execution directory. + +Individual tasks can also specify their own +[working directory](./defining-tasks.md#task-directory). + +## Configure reusable tasks {#vars-of-included-taskfiles} + +Use `vars` on an include to configure reusable tasks. This example includes the +same file twice with different image names: + +::: code-group + +```yaml [Taskfile.yml] +version: '3' + +includes: + backend: + taskfile: ./taskfiles/Docker.yml + vars: + DOCKER_IMAGE: backend_image + frontend: + taskfile: ./taskfiles/Docker.yml + vars: + DOCKER_IMAGE: frontend_image +``` + +```yaml [taskfiles/Docker.yml] +version: '3' + +vars: + DOCKER_IMAGE: '{{.DOCKER_IMAGE | default "app"}}' + +tasks: + build: + cmds: + - echo 'Building {{.DOCKER_IMAGE}}' +``` + +::: + +`task backend:build` prints `Building backend_image`; `task frontend:build` +prints `Building frontend_image`. + +The template default in the included file is deliberate. A constant value in +that file's `vars` would override the value supplied by the include. See +[variable precedence](./variables.md#resolution-order) for the full rules. + +## Shorten namespace names {#namespace-aliases} + +Add namespace `aliases` to shorten frequently used task names: + +```yaml +version: '3' + +includes: + documentation: + taskfile: ./docs/Taskfile.yml + dir: ./docs + aliases: [docs] +``` + +Both `task documentation:build` and `task docs:build` call the same task. +Namespace aliases can be combined with +[task aliases](./defining-tasks.md#task-aliases). + +## Allow a missing file {#optional-includes} + +Use `optional: true` when a missing local Taskfile should not prevent the rest +of the project from running: + +```yaml +version: '3' + +includes: + local: + taskfile: ./Taskfile.local.yml + optional: true + +tasks: + greet: + cmds: + - echo 'Hello, World!' +``` + +`task greet` works even without `Taskfile.local.yml`. Optional includes do not +make tasks from a missing file available. + +## Keep included tasks internal {#internal-includes} + +Use `internal: true` when all tasks in an included file are helpers for your +public tasks: + +```yaml +version: '3' + +includes: + docs: + taskfile: ./docs/Taskfile.yml + dir: ./docs + internal: true + +tasks: + build: + cmds: + - task: docs:build +``` + +With the `docs/Taskfile.yml` from the first example, `task build` works, but +`task docs:build` cannot be called directly. Internal tasks are also hidden from +task listings. + +## Remove the namespace {#flatten-includes} + +Use `flatten: true` to expose included tasks without a namespace: + +```yaml +version: '3' + +includes: + docs: + taskfile: ./docs/Taskfile.yml + dir: ./docs + flatten: true +``` + +With the first example's included file, call `task build` instead of +`task docs:build`. Calls within the Taskfile can also use the flattened name. + +If the root Taskfile already defines `build`, this inclusion fails with a name +collision. Keep the namespace or exclude the conflicting included task. + +## Exclude selected tasks {#exclude-tasks-from-being-included} + +Use `excludes` to remove selected tasks from an include. Names match exactly; +append `:*` to exclude a namespace: + +::: code-group + +```yaml [Taskfile.yml] +version: '3' + +includes: + tools: + taskfile: ./Tools.yml + excludes: [debug, 'internal:*'] +``` + +```yaml [Tools.yml] +version: '3' + +tasks: + check: echo 'Checking project' + debug: echo 'Debug details' + internal:setup: echo 'Internal setup' +``` + +::: + +`task tools:check` works. `task tools:debug` and `task tools:internal:setup` +fail because those tasks were excluded. `excludes` also works with `flatten`. + +## Choose a file by OS {#os-specific-taskfiles} + +Use the `OS` template function to select a file for the current platform: + +```yaml +version: '3' + +includes: + build: ./Taskfile_{{OS}}.yml +``` + +Provide files such as `Taskfile_linux.yml`, `Taskfile_darwin.yml`, and +`Taskfile_windows.yml` for the platforms you support. If only a few commands +differ, +[platform restrictions](./platforms.md#platform-specific-tasks-and-commands) may +be easier to maintain. + +::: tip Related guide + + + +Replace the local path with an HTTP or Git location to reuse tasks maintained +outside the project. Only run remote Taskfiles from sources you trust; they +execute commands on your machine. See [Remote Taskfiles](../remote-taskfiles.md) +for a complete example, checksum pinning, and offline use. + +::: diff --git a/website/src/latest/docs/guide/index.md b/website/src/latest/docs/guide/index.md new file mode 100644 index 00000000..fffb9e75 --- /dev/null +++ b/website/src/latest/docs/guide/index.md @@ -0,0 +1,68 @@ +--- +title: Guide +description: + Learn to define tasks, supply inputs, control execution, configure the + environment and output, and include other Taskfiles. +section: Guide +docType: guide +outline: deep +--- + +# Guide + +Use the guide to learn a feature or solve a specific problem. If you are new to +Task, start with the [Quick Start](../getting-started.md). For accepted keys, +flags and functions, use the [Taskfile Schema](../reference/schema.md), +[CLI](../reference/cli.md) and [Templating](../reference/templating.md) +references. + + + +## Writing and running tasks {#writing-and-running-tasks} + +- [Defining tasks](./defining-tasks.md): command lists, descriptions, aliases + and display labels. +- [Running tasks](./running-tasks.md): choosing a Taskfile, running from other + directories, previewing commands and using interactive applications. + +## Variables and arguments {#variables-and-environment} + +- [Variables](./variables.md): declaring values, computing them with shell + commands, preserving types and understanding resolution order. +- [Command-line arguments](./arguments.md): assigning variables, forwarding + arguments with `--` and capturing values from task names. +- [Validation and prompts](./required-variables.md): requiring inputs, + restricting allowed values and asking for missing values. +- [Secret variables](./secret-variables.md): loading sensitive values and + masking them in Task's command logs. + +## Task execution {#controlling-what-runs} + +- [Dependencies and task calls](./dependencies.md): running tasks concurrently + or in sequence, limiting concurrency and controlling repeated calls. +- [Loops](./loops.md): repeating commands or task calls over values, files and + matrices. +- [Conditional execution](./conditional-execution.md): skipping optional work + with `if`, enforcing requirements with `preconditions` and asking for + [confirmation](./conditional-execution.md#confirmation-prompts). +- [Errors and cleanup](./errors-and-cleanup.md): continuing after selected + failures and running cleanup with `defer`. +- [Up-to-date checks](./up-to-date.md): skipping unchanged builds, checking for + missing outputs and combining file checks with custom conditions. +- [Watch mode](./watch.md): rerunning tasks when source files change. + +## Environment and output {#execution-environment} + +- [Environment variables](./environment.md): setting the environment for + commands and loading `.env` files. +- [Platforms and shells](./platforms.md): selecting platform-specific commands, + understanding shell context and setting shell options. +- [Output and logging](./output.md): streaming, grouping and prefixing output, + hiding command echoes and displaying CI annotations. + +## Including Taskfiles {#composing-taskfiles} + +- [Including Taskfiles](./includes.md): sharing tasks with namespaces, + configuring includes and passing variables to them. +- [Remote Taskfiles](../remote-taskfiles.md): loading Taskfiles over HTTP or Git + and managing trust, checksums and cached copies. diff --git a/website/src/latest/docs/guide/loops.md b/website/src/latest/docs/guide/loops.md new file mode 100644 index 00000000..d30103e5 --- /dev/null +++ b/website/src/latest/docs/guide/loops.md @@ -0,0 +1,275 @@ +--- +title: Loops +description: + Repeat a command over a static list, a matrix, a variable, your task's + sources, or other tasks. +section: Guide +docType: guide +outline: deep +--- + +# Loops + +Use `for` to repeat a command or task call with different values. Start with a +list, then choose a different input source when the values come from a variable, +files, or several combinations. + +## Repeat a command {#looping-over-a-static-list} + +In a project containing `README.md` and `LICENSE`, this task saves a copy of +each file in `backup/`. Put `for` beside `cmd` and read the current filename +through `.ITEM`: + +```yaml +version: '3' + +tasks: + backup: + cmds: + - mkdir -p backup + - for: [README.md, LICENSE] + cmd: cp '{{.ITEM}}' backup/ +``` + +Run `task backup` to create `backup/README.md` and `backup/LICENSE`. Command +loops run in list order. Use [dependency loops](#looping-over-dependencies) for +iterations that may run concurrently. + +For a changing set of files, use +[a source glob](#looping-over-your-task-s-sources-or-generated-files) instead of +maintaining a fixed list. + +## Read values from variables {#looping-over-variables} + +Use `var` to read an existing variable. Strings are split on whitespace: + +```yaml +version: '3' + +tasks: + greet: + vars: + NAMES: Alice Bob + cmds: + - for: { var: NAMES } + cmd: echo "Hello, {{.ITEM}}!" +``` + +For another separator, set `split`: + +```yaml +version: '3' + +tasks: + greet: + vars: + NAMES: Alice,Bob + cmds: + - for: { var: NAMES, split: ',' } + cmd: echo "Hello, {{.ITEM}}!" +``` + +Arrays preserve values containing spaces: + +```yaml +version: '3' + +tasks: + greet: + vars: + NAMES: ['Alice Smith', 'Bob Jones'] + cmds: + - for: { var: NAMES } + cmd: echo "Hello, {{.ITEM}}!" +``` + +Maps expose the key as `.KEY` and the value as `.ITEM`. Their iteration order is +not guaranteed: + +```yaml +version: '3' + +tasks: + services: + vars: + PORTS: + map: { api: 8080, worker: 9090 } + cmds: + - for: { var: PORTS } + cmd: echo "{{.KEY}} uses port {{.ITEM}}" +``` + +Dynamic variables work too. This example reads newline-separated names from an +existing `names.txt` file: + +```yaml +version: '3' + +tasks: + greet: + vars: + NAMES: + sh: cat names.txt + cmds: + - for: { var: NAMES, split: "\n" } + cmd: echo "Hello, {{.ITEM}}!" +``` + +## Name the current item {#renaming-variables} + +Use `as` to name the current item when that makes a command easier to read: + +```yaml +version: '3' + +tasks: + greet: + cmds: + - for: { var: NAMES, as: NAME } + cmd: echo "Hello, {{.NAME}}!" + vars: + NAMES: [Alice, Bob] +``` + +## Repeat a task call {#looping-over-tasks} + +Put `task` beside `for` to reuse another task for each item: + +```yaml +version: '3' + +tasks: + default: + cmds: + - for: [api, worker] + task: check + vars: + SERVICE: '{{.ITEM}}' + + check: + cmds: + - echo "Checking {{.SERVICE}}" +``` + +`task` checks `api` before `worker`. Each call finishes before the next starts. +You can also template the task name itself: + +```yaml +version: '3' + +tasks: + default: + cmds: + - for: [api, worker] + task: check:{{.ITEM}} + + check:api: echo 'Checking API' + check:worker: echo 'Checking worker' +``` + +## Run iterations in parallel {#looping-over-dependencies} + +Use a loop in `deps` when the calls can run concurrently: + +```yaml +version: '3' + +tasks: + default: + deps: + - for: [api, worker] + task: check + vars: + SERVICE: '{{.ITEM}}' + + check: + cmds: + - echo "Checking {{.SERVICE}}" +``` + +The messages may appear in either order. All the input forms shown on this page +also work with dependency loops. See +[Dependencies and task calls](./dependencies.md) for concurrency limits and +repeated-call policies. + +## Try every combination {#looping-over-a-matrix} + +Use `matrix` to visit every combination of several lists: + +```yaml +version: '3' + +tasks: + targets: + cmds: + - for: + matrix: + OS: [linux, darwin] + ARCH: [amd64, arm64] + cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" +``` + +`task targets` prints `linux/amd64`, `linux/arm64`, `darwin/amd64`, and +`darwin/arm64`. These are ordinary iteration values; they do not change the +platform on which Task runs. + +Use `ref` to reuse lists defined elsewhere: + +```yaml +version: '3' + +vars: + SYSTEMS: [linux, darwin] + ARCHITECTURES: [amd64, arm64] + +tasks: + targets: + cmds: + - for: + matrix: + OS: { ref: .SYSTEMS } + ARCH: { ref: .ARCHITECTURES } + cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}" +``` + +## Loop over files {#looping-over-your-task-s-sources-or-generated-files} + +Use `for: sources` or `for: generates` to reuse the task's file declarations. +Globs are expanded before iteration: + +::: code-group + +```yaml [Sources] +version: '3' + +tasks: + show: + sources: ['src/*.txt'] + cmds: + - for: sources + cmd: cat '{{.ITEM}}' +``` + +```yaml [Generates] +version: '3' + +tasks: + show: + generates: ['output/*.txt'] + cmds: + - for: generates + cmd: cat '{{.ITEM}}' +``` + +::: + +Run `task show` with matching files present. Paths are relative to the task's +working directory. Source declarations also enable +[up-to-date checks](./up-to-date.md); use `method: none` if this task should +print the files every time. + +To build an absolute path, combine a directory with the item using the +`joinPath` template function, for example +`{{joinPath .TASK_DIR .ITEM}}`. See the +[file-path variables](../reference/templating.md#file-paths) for the available +directory values. diff --git a/website/src/latest/docs/guide/output.md b/website/src/latest/docs/guide/output.md new file mode 100644 index 00000000..9eaa9740 --- /dev/null +++ b/website/src/latest/docs/guide/output.md @@ -0,0 +1,214 @@ +--- +title: Output and logging +description: + Choose an output mode, hide command echoes, and display colors and failure + annotations in CI. +section: Guide +docType: guide +outline: deep +--- + +# Output and logging + +When several tasks run together, their output can be hard to follow. Choose an +output mode to identify the source of each line or keep each command's output +together. Use `silent` separately to hide the command text Task logs. + +## Choose an output mode {#output-syntax} + +| What do you need? | Mode | +| ------------------------------------ | ----------------------- | +| Live output without extra formatting | `interleaved` (default) | +| Live output labeled by task | `prefixed` | +| Each command's output in one block | `group` | + +### Identify parallel output + +Set `output: prefixed` at the root of the Taskfile: + +```yaml +version: '3' + +output: prefixed + +tasks: + check: + deps: [lint, test] + + lint: + cmds: + - echo 'Lint passed' + + test: + cmds: + - echo 'Tests passed' +``` + +Run `task --silent check`. The command output identifies each task: + +```text +[lint] Lint passed +[test] Tests passed +``` + +The lines may appear in either order because the tasks run concurrently. You can +override the output mode for one invocation with `task --output group check` (or +`task -o group check`). + +Use a task's `prefix` to distinguish repeated calls with different inputs: + +```yaml +version: '3' + +output: prefixed + +tasks: + default: + deps: + - task: check + vars: { SERVICE: api } + - task: check + vars: { SERVICE: worker } + + check: + prefix: 'check-{{.SERVICE}}' + silent: true + cmds: + - echo 'Passed' +``` + +The output uses `[check-api]` and `[check-worker]` prefixes. + +### Group command output + +Set `output: group` to buffer each command's stdout and stderr until that +command finishes. Long-running commands do not provide live feedback in this +mode. Groups are per command, so blocks from different tasks can still alternate +between commands. + +To show buffered output only when a command fails: + +```yaml +version: '3' + +silent: true +output: + group: + error_only: true + +tasks: + passes: echo 'Everything passed' + fails: echo 'Failure details' && exit 1 +``` + +`task passes` prints nothing. `task fails` prints `Failure details` and the +failure message. Hiding successful output does not change exit codes. + +## Hide command echoes {#silent-mode} + +Use `--silent` (or `-s`) to hide the command text Task logs before execution. +The command's own output remains visible: + +```yaml +version: '3' + +tasks: + greet: + cmds: + - echo 'Hello, World!' +``` + +`task greet` shows the command and its output. `task --silent greet` prints only +`Hello, World!`. + +To make this permanent for selected commands: + +```yaml +version: '3' + +tasks: + greet: + cmds: + - cmd: echo 'Hello, World!' + silent: true +``` + +You can also set `silent: true` on a task for all its commands, or at the root +of the Taskfile for all tasks. + +To suppress a command's stdout, use shell redirection instead: + +```yaml +version: '3' + +tasks: + quiet: + cmds: + - echo 'This output is discarded' > /dev/null +``` + +Stderr remains visible unless you redirect it too. Silent mode is not a +substitute for [secret masking](./secret-variables.md). + +## Make CI logs readable {#ci-integration} + +### Fold command logs + +Use `output.group.begin` and `end` to add the markers a CI system uses for +collapsible logs. For GitHub Actions: + +```yaml +version: '3' + +output: + group: + begin: '::group::{{.TASK}}' + end: '::endgroup::' + +tasks: + default: + silent: true + cmds: + - echo 'Hello, World!' +``` + +Running `task` produces: + +```text +::group::default +Hello, World! +::endgroup:: +``` + +These markers follow +[GitHub Actions' grouping format](https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#grouping-log-lines). +Other providers, such as +[Azure Pipelines](https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?expand=1&view=azure-devops&tabs=bash#formatting-commands), +use different markers. + +### Control colors {#colored-output} + +Task enables its colored output when `CI=true`, which most CI providers set +automatically. Use `FORCE_COLOR=1` to force colors or `NO_COLOR=1` to disable +them. Programs launched by Task may have their own color settings. + +### Surface failures {#error-annotations} + +When `GITHUB_ACTIONS=true`, Task automatically emits an annotation when a task +fails, so the workflow can surface the error: + +```text +::error title=Task 'build' failed::exit status 1 +``` + +No Taskfile configuration is required for these annotations. + +::: tip Related guide + + + +To continue after a selected failure, use `ignore_error`. See +[Errors and cleanup](./errors-and-cleanup.md#ignoring-command-errors) for its +scope and examples. + +::: diff --git a/website/src/latest/docs/guide/platforms.md b/website/src/latest/docs/guide/platforms.md new file mode 100644 index 00000000..b5cb936c --- /dev/null +++ b/website/src/latest/docs/guide/platforms.md @@ -0,0 +1,129 @@ +--- +title: Platforms and shells +description: + Restrict tasks and commands to an operating system or architecture, and set + shell options with `set` and `shopt`. +section: Guide +docType: guide +outline: deep +--- + +# Platforms and shells {#platform-specific-behaviour} + +Task runs on Linux, macOS, and Windows. A portable Taskfile also needs commands +and tools that work on the machines where you run it. Use `platforms` to select +OS-specific steps, and keep shared work in the same task. + +## Select platform commands {#platform-specific-tasks-and-commands} + +Set `platforms` on an individual command when only part of a task differs by +platform: + +```yaml +version: '3' + +tasks: + setup: + cmds: + - cmd: echo 'Preparing Windows tools' + platforms: [windows] + - cmd: echo 'Preparing Unix tools' + platforms: [linux, darwin] + - echo 'Preparing shared files' +``` + +Run `task setup`. A command whose platform does not match is skipped without an +error; the shared command runs on every platform. + +### Restrict a whole task + +Put `platforms` on the task when none of its commands should run elsewhere: + +```yaml +version: '3' + +tasks: + setup:windows: + platforms: [windows/amd64] + cmds: + - echo 'Preparing tools for Windows on amd64' +``` + +| Restriction | Matches | +| ------------------------- | ---------------------------------------------- | +| `[windows]` | Windows on any architecture | +| `[amd64]` | Any supported OS on amd64 | +| `[windows/amd64]` | Windows on amd64 | +| `[windows/amd64, darwin]` | Windows on amd64, or macOS on any architecture | + +OS and architecture names use Go's `GOOS` and `GOARCH` values. These +restrictions check the machine running Task; they do not configure a compiler's +target. + +### Share platform values + +The `OS` and `ARCH` template functions expose the current platform. Use them to +select [OS-specific Taskfiles](./includes.md#os-specific-taskfiles) or construct +arguments. Use `exeExt` for executable names that need `.exe` on Windows: + +```yaml +version: '3' + +tasks: + build: + cmds: + - go build -o app{{exeExt}} main.go +``` + +## Understand command shells + +Task runs commands through its embedded shell interpreter. It does not start +your interactive shell or load that shell's startup configuration. Use +[Taskfile `env` and `dotenv`](./environment.md) for values commands need. + +Each `cmds` entry gets a separate shell context. A `cd` or `export` in one entry +does not carry over to the next. Set `dir` and `env` on the task instead: + +```yaml +version: '3' + +tasks: + inspect: + dir: src + env: + BUILD_MODE: development + cmds: + - pwd + - echo "$BUILD_MODE" +``` + +If several commands need to share shell state, put them in one multiline `cmd` +or a script. Programs such as `go`, `npm`, or `docker` must still be installed. +Invoke `bash`, `pwsh`, or `cmd /c` explicitly when a command needs that +particular shell, and restrict it to machines where it is available. + +## Configure shell options {#set-and-shopt} + +Use `set` for POSIX shell options and `shopt` for supported Bash-style options. +For example, `pipefail` makes a pipeline fail when an earlier command fails, and +`globstar` enables recursive `**` globs in shell commands: + +```yaml +version: '3' + +set: [pipefail] +shopt: [globstar] + +tasks: + list: + cmds: + - echo **/*.go +``` + +These options can be set at the root, task, or command level. The shell +interpreter supports a subset of shell options; see the +[shell options reference](../reference/schema.md#shell-options). + +`shopt` controls shell expansion inside commands. Globs in `sources` and +`generates` use [Task's file matching](./up-to-date.md#track-the-right-files) +and do not require `globstar`. diff --git a/website/src/latest/docs/guide/required-variables.md b/website/src/latest/docs/guide/required-variables.md new file mode 100644 index 00000000..009ff321 --- /dev/null +++ b/website/src/latest/docs/guide/required-variables.md @@ -0,0 +1,170 @@ +--- +title: Validation and prompts +description: + Require variables to be set, restrict them to allowed values, and prompt for + missing input. +section: Guide +docType: guide +outline: deep +--- + +# Validation and prompts {#required-variables-and-prompts} + +Use `requires` to catch missing inputs before a task runs. Add `enum` when only +certain values are allowed, and enable interactive prompts when users should be +able to fill in missing values at the terminal. + +## Require an input {#ensuring-required-variables-are-set} + +Declare inputs in `requires.vars`, then pass them on the command line: + +```yaml +version: '3' + +tasks: + release: + requires: + vars: [VERSION] + cmds: + - echo "Preparing release {{.VERSION}}" +``` + +Run `task release VERSION=1.2.3` to print the message. Without `VERSION`, Task +fails and identifies the missing input. Task variables and values inherited from +the process environment can satisfy the requirement. + +A variable set to an empty string counts as present. To reject an empty value, +use an enum of nonempty strings or a +[precondition](./conditional-execution.md#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies). + +## Restrict allowed values {#ensuring-required-variables-have-allowed-values} + +Use `name` and `enum` to require a string from a fixed list: + +```yaml +version: '3' + +tasks: + deploy: + requires: + vars: + - name: ENV + enum: [dev, staging, prod] + cmds: + - echo "Deploying to {{.ENV}}" +``` + +`task deploy ENV=staging` succeeds. `task deploy ENV=preview` fails before +running the command. Enum validation applies to string variables, including +strings inherited from the environment. + +## Ask for missing input {#prompting-for-missing-variables-interactively} + +Run `task --interactive deploy` with the example above to choose the missing +`ENV` from a menu. Required variables without an enum use a text input instead. + +To enable this behavior by default, set it in your +[Task configuration](../reference/config.md#interactive): + +```yaml [~/.taskrc.yml] +interactive: true +``` + +For a task with both kinds of input: + +```yaml +version: '3' + +tasks: + deploy: + requires: + vars: + - name: ENVIRONMENT + enum: [dev, staging, prod] + - VERSION + cmds: + - echo "Deploying {{.VERSION}} to {{.ENVIRONMENT}}" +``` + +`task --interactive deploy` asks for an environment and a version. Values +already supplied through the CLI, environment, or Taskfile do not prompt: + +```shell +task deploy ENVIRONMENT=prod VERSION=1.0.0 +``` + +Prompts require a terminal. In CI or another non-interactive environment, +missing variables cause an error; supply all required values explicitly. + +## Reuse allowed values {#using-variable-references-for-enum-values} + +Define a shared list and reference it from an enum: + +```yaml +version: '3' + +vars: + ALLOWED_ENVS: [dev, staging, prod] + +tasks: + deploy: + requires: + vars: + - name: ENV + enum: + ref: .ALLOWED_ENVS + cmds: + - echo "Deploying to {{.ENV}}" +``` + +References can also transform values. Given a `config.json` file containing +`{"allowed_environments": ["dev", "prod"]}`, this reads the list from it: + +```yaml +version: '3' + +vars: + CONFIG: + sh: cat config.json + +tasks: + deploy: + requires: + vars: + - name: ENV + enum: + ref: ( .CONFIG | fromJson ).allowed_environments + cmds: + - echo "Deploying to {{.ENV}}" +``` + +For newline-separated command output, convert it to a list before using it as an +enum. This example uses the entries in an existing `services/` directory: + +```yaml +version: '3' + +vars: + AVAILABLE_SERVICES: + sh: ls services/ + +tasks: + deploy: + requires: + vars: + - name: SERVICE + enum: + ref: .AVAILABLE_SERVICES | splitLines | compact + cmds: + - echo "Deploying {{.SERVICE}}" +``` + +::: tip Related guide + + + +A prompt for input fills in a value. A +[confirmation prompt](./conditional-execution.md#confirmation-prompts) asks +whether execution should proceed, even if all input values are already present. + +::: diff --git a/website/src/latest/docs/guide/running-tasks.md b/website/src/latest/docs/guide/running-tasks.md new file mode 100644 index 00000000..5f237e91 --- /dev/null +++ b/website/src/latest/docs/guide/running-tasks.md @@ -0,0 +1,150 @@ +--- +title: Running tasks +description: + How Task finds a Taskfile, and how to run one from a subdirectory, from your + home directory, from standard input or as a dry run. +section: Guide +docType: guide +outline: deep +--- + +# Running tasks + +Run `task ` from your project to execute a task. With no name, Task runs +the `default` task. Start by listing tasks, then run one: + +```shell +task --list +task build +``` + +`--list` shows tasks with descriptions. Use `--list-all` to include tasks +without descriptions; [internal tasks](./defining-tasks.md#internal-tasks) +remain hidden. See [Defining tasks](./defining-tasks.md) to create these +entries. + +Pass several names, such as `task lint test`, to run them in order. Use +[`--parallel`](./dependencies.md#limiting-how-much-runs-at-once) for independent +tasks that can run concurrently. To pass values or command arguments, see +[Command-line arguments](./arguments.md). + +## Preview commands {#dry-run-mode} + +Use `--dry` (or `-n`) to print the commands Task would run: + +```shell +task --dry build +``` + +Task still resolves templates and dynamic variables while preparing the +commands. A variable declared with `sh` can therefore execute its shell command +during a dry run. See [Variables](./variables.md#when-values-are-computed). + +## Run from a subdirectory {#running-a-taskfile-from-a-subdirectory} + +If Task cannot find a Taskfile in the current directory, it searches parent +directories. Tasks run from the directory containing that Taskfile unless +[their `dir` setting](./defining-tasks.md#task-directory) changes it. + +Use `{{.USER_WORKING_DIR}}` when the task should act on the +directory where you invoked it. In a monorepo, this lets each service use the +same task to start its Docker Compose services: + +```yaml +version: '3' + +tasks: + up: + dir: '{{.USER_WORKING_DIR}}' + preconditions: + - test -f docker-compose.yml + cmds: + - docker compose up -d +``` + +From a service directory containing `docker-compose.yml`, run `task up`. The +root Taskfile supplies the task; the service directory supplies its files. + +## Use a personal Taskfile {#running-a-global-taskfile} + +Store a Taskfile in your home directory and use `--global` (or `-g`) to call it +from anywhere: + +```shell +task --global from-working-directory +``` + +Global tasks run in your home directory by default. Set `dir` to +`{{.USER_WORKING_DIR}}` when a personal utility should work +on the current project: + +```yaml +version: '3' + +tasks: + from-home: + cmds: + - pwd + + from-working-directory: + dir: '{{.USER_WORKING_DIR}}' + cmds: + - pwd +``` + +## Read a Taskfile from stdin {#running-a-taskfile-from-stdin} + +Use `--taskfile -` (or `-t -`) to read a generated Taskfile from standard input. +For example, to read an existing file through stdin: + +```shell +task --taskfile - < ./Taskfile.yml +``` + +You can also pipe the output of a Taskfile generator into `task --taskfile -`. +With no task name, these commands run the generated file's `default` task. + +## Run a terminal app {#interactive-cli-application} + +Set `interactive: true` on a task that launches a terminal application: + +```yaml +version: '3' + +tasks: + edit: + interactive: true + cmds: + - vim my-file.txt +``` + +Run `task edit` to open the editor. Interactive applications need direct access +to the terminal; buffered or prefixed [output modes](./output.md#output-syntax) +and other tasks running concurrently can interfere with their input and display. + +This task setting is distinct from the CLI `--interactive` option, which +[prompts for missing variables](./required-variables.md#prompting-for-missing-variables-interactively). + +## Choose a file name {#supported-file-names} + +Use `--taskfile` to choose a specific file or `--dir` to run in another project: + +```shell +task --taskfile Taskfile.ci.yml build +task --dir ./backend build +``` + +Task looks for these names in order of priority: + +- `Taskfile.yml` +- `taskfile.yml` +- `Taskfile.yaml` +- `taskfile.yaml` +- `Taskfile.dist.yml` +- `taskfile.dist.yml` +- `Taskfile.dist.yaml` +- `taskfile.dist.yaml` + +Commit a `.dist` variant if users need to supply their own `Taskfile.yml` +override. The local file takes priority; add it to `.gitignore` if it should +remain personal. diff --git a/website/src/latest/docs/guide/secret-variables.md b/website/src/latest/docs/guide/secret-variables.md new file mode 100644 index 00000000..bea7735f --- /dev/null +++ b/website/src/latest/docs/guide/secret-variables.md @@ -0,0 +1,104 @@ +--- +title: Secret variables +description: + Mask sensitive variable values in Task's command logs, load secrets from + external sources, and understand what masking does not protect. +section: Guide +docType: guide +outline: deep +--- + +# Secret variables + +Set `secret: true` on a variable to replace its value with `*****` in Task's own +command logs. The command still receives the original value. + +```yaml +version: '3' + +vars: + API_TOKEN: + sh: echo "$MY_API_TOKEN" + secret: true + +tasks: + request: + cmds: + - 'curl -H "Authorization: Bearer {{.API_TOKEN}}" https://api.example.com' + # Logged as: curl -H "Authorization: Bearer *****" https://api.example.com +``` + +Set `MY_API_TOKEN` in the environment before running `task request`. Task's log +masks the token, while `curl` receives the real value. The example URL is a +placeholder; replace it with your API endpoint. + +Secret variables can be declared globally or on a task. Use `value` instead of +`sh` for a literal or template value, and keep real credentials out of committed +Taskfiles. + +## Load from a secret store {#loading-secrets} + +Use a dynamic variable to read a secret from an external source: + +```yaml +version: '3' + +vars: + API_TOKEN: + sh: vault kv get -field=api_key secret/myapp + secret: true + +tasks: + request: + cmds: + - 'curl -H "Authorization: Bearer {{.API_TOKEN}}" https://api.example.com' +``` + +To read an existing environment variable, replace the `sh` command with +`echo "$MY_API_TOKEN"`. Keep local credential files, such as `.env.local`, out +of version control. + +For dynamic variable evaluation and caching, see +[When values are computed](./variables.md#when-values-are-computed). + +## Mark derived secrets {#derived-values} + +The `secret` flag does not propagate to variables that reference a secret. Mark +every variable carrying the sensitive value as secret: + +```yaml +version: '3' + +vars: + API_TOKEN: + sh: echo "$MY_API_TOKEN" + secret: true + AUTH_HEADER: + value: 'Bearer {{.API_TOKEN}}' + secret: true + +tasks: + request: + cmds: + - 'curl -H "Authorization: {{.AUTH_HEADER}}" https://api.example.com' + # Logged as: curl -H "Authorization: *****" https://api.example.com +``` + +Without `secret: true` on `AUTH_HEADER`, Task's command log would expose the +derived value. + +## Understand masking limits {#limits-of-masking} + +Masking applies to Task's own command logs, including when those logs are +collected by a CI system. It does not redact: + +- stdout or stderr produced by commands; +- process arguments visible to tools such as `ps`; +- values stored in shell history or committed files; +- derived variables that are not themselves marked as secret. + +For example, a command that echoes a secret still prints its real value, even +though Task masks the command text it logs before execution. + +The `secret` flag applies to `vars`, not `env`. Use your command's supported +credential mechanism to control how it receives secrets. diff --git a/website/src/latest/docs/guide/up-to-date.md b/website/src/latest/docs/guide/up-to-date.md new file mode 100644 index 00000000..a375cf8c --- /dev/null +++ b/website/src/latest/docs/guide/up-to-date.md @@ -0,0 +1,236 @@ +--- +title: Up-to-date checks +description: + Skip unchanged builds, check whether work is already done, and choose between + source fingerprints and status commands. +section: Guide +docType: guide +outline: deep +--- + +# Up-to-date checks {#skipping-work-that-is-up-to-date} + +A build should run when its inputs change or its output is missing. Declare +those files with `sources` and `generates`, and Task can skip the commands on +your next run. For other kinds of work, use `status` to check whether the result +is already available. + +## Skip unchanged builds {#by-fingerprinting-locally-generated-files-and-their-sources} + +For a Go application in `main.go`, declare the source file and the executable +that the build produces: + +```yaml +version: '3' + +tasks: + build: + sources: [main.go] + generates: ['app{{exeExt}}'] + cmds: + - go build -o app{{exeExt}} main.go +``` + +Run `task build` to create the executable. Run it again without changing +`main.go`, and Task reports that `build` is up to date. Edit `main.go` or delete +the executable, and the next call builds it again. + +The default method, `checksum`, compares the content of source files with a +saved fingerprint. It checks that declared outputs exist; it does not compare +their contents. Editing the executable alone will not trigger a rebuild. + +These checks skip the task's commands. Its [dependencies](./dependencies.md) +still run first and perform their own up-to-date checks. + +### Track the right files + +`sources` and `generates` accept files and glob patterns, relative to the task's +[working directory](./defining-tasks.md#task-directory). Include every file that +affects the result, such as source code, configuration, and dependency +lockfiles. + +For a Go module with several source files, replace `sources` and `cmds` in the +example above with: + +```yaml +sources: + - '**/*.go' + - go.mod + - go.sum + - exclude: '**/*_test.go' +cmds: + - go build -o app{{exeExt}} . +``` + +Patterns are evaluated in order. Put each `exclude` after the positive glob it +narrows. Here, test files are excluded because this task builds the application; +a test task should track them. + +Set `use_gitignore: true` at the root of the Taskfile to filter glob matches +using `.gitignore` rules. A task can override that setting. Keep it disabled for +tasks that need to track ignored files as inputs. + +`generates` is optional. A task such as a test suite can use `sources` alone to +skip work when its inputs have not changed. `generates` alone does not provide a +file fingerprint; use `status` if you only need to check that a result exists. + +### Choose a check method + +| Method | How it checks sources | +| -------------------- | -------------------------------------------------------------------- | +| `checksum` (default) | Compares file contents with a saved fingerprint. | +| `timestamp` | Compares modification times with outputs and Task's saved timestamp. | +| `none` | Disables file-based skipping. | + +To use modification times for the build above, add `method: timestamp` to the +task: + +```yaml +tasks: + build: + method: timestamp + sources: [main.go] + generates: ['app{{exeExt}}'] + cmds: + - go build -o app{{exeExt}} main.go +``` + +You can also set `method` at the root of the Taskfile to change the default for +all tasks. A task's own setting takes precedence. + +With `timestamp`, touching a source can cause a rerun even if its content has +not changed. Without `generates`, Task uses its saved timestamp for the +comparison. Use `method: none` when `sources` should drive +[watch mode](./watch.md) without making the task up to date. + +## Check existing work {#using-programmatic-checks-to-indicate-a-task-is-up-to-date} + +Use `status` when a command can determine whether work is needed. Every check +must exit with code `0` for Task to skip the commands. If any check fails, Task +runs the commands: + +```yaml +version: '3' + +tasks: + prepare: + status: + - test -d directory + - test -f directory/file1.txt + - test -f directory/file2.txt + cmds: + - mkdir -p directory + - touch directory/file1.txt directory/file2.txt +``` + +Run `task prepare` twice: the first call creates the files, and the second skips +the commands. Delete either file, and Task runs the commands again. + +Keep status checks fast and read-only: they may run each time the task is +called. They can inspect files, installed tools, services, or remote artifacts. +A failed check means "do the work", so the commands should handle partially +completed work, as `mkdir -p` does above. + +If a failed check should stop execution with an error, use +[preconditions](./conditional-execution.md#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies). + +### Combine files and status + +Use both `sources` and `status` when the result depends on local files but +cannot be checked with `generates`. This Docker example tags the image with a +checksum of its build inputs: + +```yaml +version: '3' + +tasks: + image: + sources: + - Dockerfile + - src/**/* + status: + - docker image inspect example/app:{{.CHECKSUM}} > /dev/null 2>&1 + cmds: + - docker build -t example/app:{{.CHECKSUM}} . +``` + +Task skips the build only when the sources are unchanged **and** the status +check succeeds. A changed source produces a new tag; a missing image makes the +check fail. Include any other files used by your Dockerfile in `sources`. + +You can also combine `sources`, `generates`, and `status`: every configured +check must pass for Task to consider the work up to date. + +### Use source values + +With `method: checksum`, `{{.CHECKSUM}}` contains the source +fingerprint. With `method: timestamp`, `{{.TIMESTAMP}}` +contains the latest source modification time. Both can be used in `cmds` and +`status`; they describe the sources, not the generated files. + +`.TIMESTAMP` is a Go `time.Time` value. For example, +`{{.TIMESTAMP.Unix}}` produces a Unix timestamp, and +`{{.TIMESTAMP.Format "2006-01-02"}}` formats a date. + +## Check or force a run + +To check whether tasks are up to date without running their commands: + +```shell +task --status build +``` + +You can pass multiple task names. The command exits with a non-zero +[exit code](../reference/cli.md#exit-codes) if any task is not up to date. + +To run a task even when its checks say the work is already done: + +```shell +task --force build +``` + +`-f` is the short form of `--force`. To rerun automatically when files change, +use [Watch mode](./watch.md). + +## Track different inputs + +With the checksum method, Task stores one source fingerprint per task label. If +build variables affect the result, include them in the label and use separate +output paths. For example, to build with different Go build tags: + +```yaml +version: '3' + +tasks: + build: + label: 'build-{{.MODE}}' + sources: [main.go] + generates: ['app-{{.MODE}}{{exeExt}}'] + cmds: + - go build -tags '{{.MODE}}' -o app-{{.MODE}}{{exeExt}} main.go +``` + +Run `task build MODE=debug`, then `task build MODE=release`. Each mode has its +own executable and saved checksum, so a later `task build MODE=debug` can skip +the build. A change to `main.go` makes both modes need a rebuild when next +called. + +These saved checks apply across invocations. To limit repeated task calls within +a single invocation, use +[`run: once` or `run: when_changed`](./dependencies.md#repeated-calls). + +## Store fingerprints + +Task stores its file fingerprints in `.task/` under the project directory. +Usually, add this directory to `.gitignore`. For generated code committed to +version control, you may choose to commit the corresponding checksum too. + +Set `TASK_TEMP_DIR` to store fingerprints elsewhere: + +```shell +export TASK_TEMP_DIR='~/.task' +``` + +Relative paths, such as `tmp/task`, are resolved from the project directory. +Absolute paths and paths starting with `~` use a separate subdirectory for each +project. diff --git a/website/src/latest/docs/guide/variables.md b/website/src/latest/docs/guide/variables.md new file mode 100644 index 00000000..4911b8cd --- /dev/null +++ b/website/src/latest/docs/guide/variables.md @@ -0,0 +1,343 @@ +--- +title: Variables +description: + Declare variables, compute values with shell commands, preserve types with + references, and understand resolution order. +section: Guide +docType: guide +outline: deep +--- + +# Variables + +Declare variables with `vars`, then read them in a command with a template: + +```yaml +version: '3' + +vars: + NAME: World + +tasks: + greet: + cmds: + - echo "Hello, {{.NAME}}!" +``` + +Run `task greet` to print `Hello, World!`, or `task greet NAME=Bob` to print +`Hello, Bob!`. This example puts the default at the root of the Taskfile so +callers can override it. + +Use a literal for a fixed value, `sh` to compute text with a command, and `ref` +to preserve arrays and maps. The examples come first; +[resolution order](#resolution-order) explains how values from different places +interact. + + + +Pass `NAME=value` on the command line to supply variables to Task. See +[Command-line arguments](./arguments.md#variable-assignments) for quoting, +multiple tasks and the difference from arguments after `--`. + +::: tip + +The special variable `.TASK` contains the name of the task being run. + +::: + +## Choose a value type {#variable-types} + +Variables support the following types: + +- `string` +- `bool` +- `int` +- `float` +- `array` +- `map` + +::: info + +Defining a map requires that you use a special `map` subkey (see example below). + +::: + +```yaml +version: 3 + +tasks: + foo: + vars: + STRING: 'Hello, World!' + BOOL: true + INT: 42 + FLOAT: 3.14 + ARRAY: [1, 2, 3] + MAP: + map: { A: 1, B: 2, C: 3 } + cmds: + - 'echo {{.STRING}}' # Hello, World! + - 'echo {{.BOOL}}' # true + - 'echo {{.INT}}' # 42 + - 'echo {{.FLOAT}}' # 3.14 + - 'echo {{.ARRAY}}' # [1 2 3] + - 'echo {{index .ARRAY 0}}' # 1 + - 'echo {{.MAP}}' # map[A:1 B:2 C:3] + - 'echo {{.MAP.A}}' # 1 +``` + +## Compute a value {#dynamic-variables} + +Use `sh` to compute a variable from a shell command. Task captures its output +and trims the final trailing newline, if present. + +```yaml +version: '3' + +tasks: + build: + cmds: + - go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go + vars: + GIT_COMMIT: + sh: git log -n 1 --format=%h +``` + +The result is text. To convert JSON or YAML output into structured data, use +[parsing functions with `ref`](#parsing-json-yaml-into-map-variables). + +## Pass lists and maps {#referencing-other-variables} + +Use `ref` to pass an array or map to another task without converting it to text. +In this example, `show` receives the original list: + +```yaml +version: '3' + +tasks: + default: + vars: + SERVICES: [api, worker] + cmds: + - task: show + vars: + SERVICES: + ref: .SERVICES + + show: + cmds: + - echo '{{index .SERVICES 0}}' +``` + +Run `task` to print `api`. Replacing the reference with +`SERVICES: '{{.SERVICES}}'` would pass the string +`[api worker]`. Indexing that string returns a byte, not a list element. + +References also work in dependency calls and variable definitions: + +```yaml +version: '3' + +tasks: + default: + vars: + SERVICES: [api, worker] + SELECTED: + ref: .SERVICES + deps: + - task: show + vars: + SERVICE: + ref: index .SELECTED 0 + + show: + cmds: + - echo '{{.SERVICE}}' +``` + +Use subkeys, indexes, and functions inside `ref`, without the template braces. +See the [Templating reference][templating-reference] for available functions. + +## Parse JSON or YAML {#parsing-json-yaml-into-map-variables} + +If you have a raw JSON or YAML string that you want to process in Task, you can +use a combination of the `ref` keyword and the `fromJson` or `fromYaml` +templating functions to parse the string into a map variable. For example: + +```yaml +version: '3' + +tasks: + task-with-map: + vars: + JSON: '{"a": 1, "b": 2, "c": 3}' + FOO: + ref: 'fromJson .JSON' + cmds: + - echo {{.FOO}} +``` + +```txt +map[a:1 b:2 c:3] +``` + +## Understand precedence {#resolution-order} + +Applied first to last. Later wins. + +| # | Source | Set by | +| --- | ----------------------------------- | ----------------------------------------------------------------------------- | +| 1 | The process environment | the shell that ran `task` | +| 2 | Special variables | Task itself (`TASK`, `ROOT_DIR`, `CLI_ARGS`, …) | +| 3 | Taskfile `env:` | the `env:` block; `dotenv:` files fill only names `env:` does not already set | +| 4 | Global `vars:` | the `vars:` block of every Taskfile in the run | +| 5 | Include `vars:` | the `vars:` given on an `includes:` entry | +| 6 | The included Taskfile's own `vars:` | the `vars:` block of the file being included | +| 7 | Call variables | `task foo BAR=1`, or `vars:` on a `task:` command | +| 8 | The task's `vars:` | the `vars:` block of the task being run | + +## Apply precedence rules {#what-this-means-in-practice} + +### Let callers override {#a-task-s-own-variables-cannot-be-overridden-from-the-command-line} + +Step 8 comes after step 7, so a variable declared on the task always wins: + +```yaml +version: '3' + +tasks: + greet: + vars: + NAME: from-task + cmds: + - echo "{{.NAME}}" +``` + +```shell +$ task greet NAME=from-cli +from-task +``` + +To let a caller supply a value, give the default somewhere earlier, in global +`vars:`, or use a template default: + +```yaml +version: '3' + +vars: + NAME: from-global + +tasks: + greet: + cmds: + - echo "{{.NAME}}" +``` + +```shell +$ task greet NAME=from-cli +from-cli +``` + +To keep the default on the task itself, read the caller's value in a template: + +```yaml +vars: + NAME: '{{.NAME | default "World"}}' +``` + +### Configure include defaults {#let-callers-configure-an-included-taskfile} + +Step 6 comes after step 5, so a constant declared in the included Taskfile's +`vars:` overrides the value supplied by `includes.vars`. + +To keep a configurable default in the included Taskfile, use a template that +reads the previously resolved value: + +```yaml +version: '3' + +vars: + DOCKER_IMAGE: '{{.DOCKER_IMAGE | default "app"}}' + +tasks: + build: + cmds: + - echo "building {{.DOCKER_IMAGE}}" +``` + +An inclusion that supplies `DOCKER_IMAGE: backend_image` now prints +`building backend_image`; without a supplied value, it prints `building app`. +The default stays in one place and applies to every task in the included file. + +### Avoid global collisions {#global-variable-names-are-shared-across-every-taskfile-in-the-run} + +Global `vars:` are merged into one set before any task runs, so a name declared +in both the entrypoint and an included Taskfile resolves to the included one, +including for tasks defined in the entrypoint. + +Give globals that belong to an included Taskfile a distinctive name, or move +them onto the tasks that use them, where step 8 keeps them local. + +### Choose vars or env {#env-and-vars-are-not-the-same-thing} + +A `vars:` entry is not exported to commands in `cmds`, whichever level it was +declared at. Read it with a template instead of `$FOO`. Dynamic variables +(`sh:`) have a different environment, described below. + +`env:` is exported to the environment of the commands Task runs, so `$FOO` +works. Whether a template also sees it depends on where it was declared: + +| Declared at | `{{.FOO}}` | `$FOO` | +| ------------------------ | ------------------------------------------ | ------ | +| the root of the Taskfile | yes, it is step 3 above | yes | +| on a task | keeps the value from other sources, if any | yes | + +A task's `env:` is assembled after the variable set has been resolved, so it +never takes part in the order on this page. If global `env:` sets `FOO: root` +and a task's `env:` sets `FOO: task`, the template `{{.FOO}}` +renders `root`, while `$FOO` in a command reads `task` (assuming the process +environment does not already set `FOO`). The template only renders empty if no +other source defines the variable. Read a task-level environment value with +`$FOO`, or declare it in `vars:` if a template needs it. + +## Understand evaluation {#when-values-are-computed} + +Dynamic variables (`sh:`) are executed while the set is being built, in the +order above. Within a block, variables are resolved in declaration order, so a +`sh:` command can also reference variables declared earlier in the same block: + +```yaml +vars: + INPUT: hello + OUTPUT: + sh: echo {{.INPUT}} +``` + +Here `OUTPUT` resolves to `hello`. Variables from later declarations or later +steps are not available yet. + +The shell used by `sh:` also receives previously resolved scalar variables, so +`sh: echo $INPUT` works in this example too. The process environment takes +precedence for shell lookups unless the +[Env Precedence experiment](../experiments/env-precedence.md) is enabled. +Commands in `cmds` only receive the process environment and Task's `env:` and +`dotenv:` values; they do not inherit `vars:` this way. + +Results are cached for the run, keyed on the command string, so the same `sh:` +command appearing twice runs once. + +To pass a variable without flattening it to text, an array or a map, use `ref:` +instead of `{{ }}`. A template renders a string; `ref:` +preserves the type. + +::: tip Related guide + + + +Mark sensitive values with `secret: true` to mask them in Task's own command +logs. See [Secret variables](./secret-variables.md) for examples, loading values +from external sources and the limits of masking. + +::: + +[templating-reference]: ../reference/templating.md diff --git a/website/src/latest/docs/guide/watch.md b/website/src/latest/docs/guide/watch.md new file mode 100644 index 00000000..d0d058d3 --- /dev/null +++ b/website/src/latest/docs/guide/watch.md @@ -0,0 +1,80 @@ +--- +title: Watch mode +description: Re-run a task automatically whenever its sources change. +section: Guide +docType: guide +outline: deep +--- + +# Watch mode + +Use `--watch` (or `-w`) to keep a task running and rerun it when its source +files change. For a Go project: + +```yaml +version: '3' + +tasks: + build: + sources: + - '**/*.go' + - go.mod + - go.sum + cmds: + - go build ./... +``` + +Run `task --watch build`, edit a Go file, and save it to trigger another build. +Press Ctrl+C to stop watching. + +Watch mode detects changes; [up-to-date checks](./up-to-date.md) decide whether +the task's commands need to run. Both use the same `sources`. + +## Enable watching by default + +Set `watch: true` on a task if its normal CLI use should start a watcher: + +```yaml +version: '3' + +tasks: + build: + watch: true + sources: ['**/*.go'] + cmds: + - go build ./... +``` + +Now `task build` starts watch mode. The `watch` setting applies when the task is +called from the CLI; calls from another task through `cmds` or `deps` do not +start a watcher. + +## Combine rapid changes + +The default watch interval is 100 milliseconds. Increase it if saving several +files produces duplicate events: + +```shell +task --watch --interval=500ms build +``` + +You can also set `interval: '500ms'` at the root of the Taskfile. The interval +groups events close together so that Task reruns the task once for the batch. + +## Watch long-running apps + +Builds and checks finish after each run. Servers keep running and need to stop +before a replacement can take over their port. + +::: warning + +There is a [known issue](https://github.com/go-task/task/issues/160) where watch +mode may leave child processes running. Prefer building and running the +executable directly over `go run`, which starts another process. + +::: + +For applications that need dedicated live-reload behavior, consider tools such +as [Air](https://github.com/air-verse/air/). Report Task-specific problems with +a small reproducer in the +[issue tracker](https://github.com/go-task/task/issues/new?template=bug_report.yml). diff --git a/website/src/latest/docs/index.md b/website/src/latest/docs/index.md new file mode 100644 index 00000000..997493f2 --- /dev/null +++ b/website/src/latest/docs/index.md @@ -0,0 +1,69 @@ +--- +title: Documentation +description: + Task is a task runner and build tool that aims to be simpler and easier to use + than GNU Make. Start here to install it, learn it, or look something up. +section: Overview +docType: overview +aside: false +outline: false +pageClass: docs-overview +--- + +# Documentation + +Install Task, learn the basics, or look up syntax for your `Taskfile.yml`. + +
+
+ +## Start with Task {#new-to-task} + +Install Task and run your first Taskfile. + +- [Installation](./installation.md) +- [Quick Start](./getting-started.md) + +
+
+ +## Use Task {#using-task} + +Find a guide for your everyday workflows. + +- [Browse the guide](./guide/index.md) +- [Variables](./guide/variables.md) +- [Dependencies and task calls](./guide/dependencies.md) + +
+
+ +## Reference {#looking-something-up} + +Look up syntax, flags and functions. + +- [Taskfile Schema](./reference/schema.md) +- [CLI](./reference/cli.md) +- [Templating](./reference/templating.md) + +
+
+ +For settings outside the Taskfile, see [Configuration](./reference/config.md) +and [Environment](./reference/environment.md). + +## Keeping up + +- [Changelog](./changelog.md): what shipped, and when. +- [Experiments](./experiments/index.md) and + [Deprecations](./deprecations/index.md): what is coming, and what is going + away. +- [FAQ](./faq.md): the questions that come up most often. +- [Community](./community.md): integrations and tools built by other people. + +## Using an AI coding assistant + +[Task documentation for coding agents](../agents.md) is a compact map of these +pages plus the semantics that are easiest to get wrong. Every page is also +available as raw Markdown by appending `.md` to its URL, and the whole corpus is +at [/llms.txt](/llms.txt). diff --git a/website/src/latest/docs/installation.md b/website/src/latest/docs/installation.md index bcf568b8..484debdb 100644 --- a/website/src/latest/docs/installation.md +++ b/website/src/latest/docs/installation.md @@ -1,244 +1,444 @@ --- title: Installation description: Installation methods for Task +section: Getting Started +docType: guide outline: deep +pageClass: installation-page --- + + # Installation -Task offers many installation methods. Check out the available methods below. +Choose a package manager for your system, or install Task from a binary. -## Official Package Managers + -These installation methods are maintained by the Task team and are always -up-to-date. + -:::info Package Repository Hosting +## Official packages {#official-package-managers} -[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=for-the-badge)](https://cloudsmith.com) +Maintained by the Task team and kept up-to-date. -Package repository hosting for deb/rpm/apk is graciously provided by [Cloudsmith](https://cloudsmith.com). -Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that -enables your organization to create, store and share packages in any format, to any place, with total -confidence. + -::: + -If you Set up the repository by running : + ```shell brew install go-task/tap/go-task ``` -Alternatively it can be installed from the official Homebrew repository -[[package](https://formulae.brew.sh/formula/go-task)] -[[source](https://github.com/Homebrew/homebrew-core/blob/master/Formula/g/go-task.rb)] -by running: +Or use the Homebrew core formula: ```shell brew install go-task ``` -### [Snap](https://snapcraft.io/task) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) {#snap} + -Task is available on [Snapcraft](https://snapcraft.io/task) -[[source](https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml)], but -keep in mind that your Linux distribution should allow classic confinement for -Snaps to Task work correctly: + + + + + + +Set up the repository: + +```shell +curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.rpm.sh' | sudo -E bash +``` + +Install Task: + +```shell +dnf install task +``` + + + + + + + + + +Set up the repository: + +```shell +curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.deb.sh' | sudo -E bash +``` + +Install Task: + +```shell +apt install task +``` + + + + + + + + + +Set up the repository: + +```shell +curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.alpine.sh' | sudo -E bash +``` + +Install Task: + +```shell +apk add task +``` + + + + + + + + ```shell sudo snap install task --classic ``` -### [npm](https://www.npmjs.com) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#npm} +Requires a Linux distribution with classic confinement support. -Npm can be used as cross-platform way to install Task globally or as a -dependency of your project -[[package](https://www.npmjs.com/package/@go-task/cli)] -[[source](https://github.com/go-task/task/blob/main/package.json)]: + + + + + + + ```shell npm install -g @go-task/cli ``` -### [WinGet](https://github.com/microsoft/winget-cli) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#winget} +Task is also available as a project dependency. -Task is available via the -[community repository](https://github.com/microsoft/winget-pkgs) -[[source](https://github.com/microsoft/winget-pkgs/tree/master/manifests/t/Task/Task)]: + + + + + + + ```shell winget install Task.Task ``` -## Community-Maintained Package Managers +Available through the +[WinGet community repository](https://github.com/microsoft/winget-pkgs). -::: warning Community Maintained + -These installation methods are maintained by the community and may not always be -up-to-date with the latest Task version. The Task team does not directly control -these packages. +

Package repository hosting for deb/rpm/apk is graciously provided by Cloudsmith.

-::: +## Community packages {#community-maintained-package-managers} -### [Mise](https://mise.jdx.dev/) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#mise} +Maintained by the community, outside the Task team's control. These packages may +lag behind the latest release. -Mise is a cross-platform package manager that acts as a "frontend" to a variety -of other package managers "backends" such as `asdf`, `aqua` and `ubi`. + -If using Mise, we recommend using the `aqua` or `ubi` backends to install Task -as these install directly from our GitHub releases. + + + + +```shell +mise use -g task ``` -```shell [ubi] -mise use -g ubi:go-task/task -mise install -``` +For a project-local installation, use `mise use task` instead. This adds Task to +your project's `mise.toml`. -::: + -### [Macports](https://macports.org) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) {#macports} + -Task repository is tracked by Macports -[[package](https://ports.macports.org/port/go-task/details/)] -[[source](https://github.com/macports/macports-ports/blob/master/devel/go-task/Portfile)]: + + + ```shell port install go-task ``` -### [pip](https://pip.pypa.io) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#pip} + -Like npm, pip can be used as a cross-platform way to install Task -[[package](https://pypi.org/project/go-task-bin)] -[[source](https://github.com/Bing-su/pip-binary-factory/tree/main/task)]: + + + + + ```shell pip install go-task-bin ``` -### [Chocolatey](https://chocolatey.org) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#chocolatey} + -[[package](https://community.chocolatey.org/packages/go-task)] -[[source](https://github.com/Starz0r/ChocolateyPackagingScripts/blob/master/src/go-task_gh_build.py)] + + + + + ```shell choco install go-task ``` -### [Scoop](https://scoop.sh) ![Windows](https://custom-icon-badges.demolab.com/badge/Windows-0078D6?logo=windows11&logoColor=white) {#scoop} + -[[source](https://github.com/ScoopInstaller/Main/blob/master/bucket/task.json)] + + + + + ```shell scoop install task ``` -### Arch ([pacman](https://wiki.archlinux.org/title/Pacman)) ![Arch Linux](https://img.shields.io/badge/Arch%20Linux-1793D1?logo=arch-linux&logoColor=fff) {#arch} + -[[package](https://archlinux.org/packages/extra/x86_64/go-task/)] -[[source](https://gitlab.archlinux.org/archlinux/packaging/packages/go-task)] + + + + + ```shell pacman -S go-task ``` -### Fedora ([dnf](https://docs.fedoraproject.org/en-US/quick-docs/dnf)) ![Fedora](https://img.shields.io/badge/Fedora-51A2DA?logo=fedora&logoColor=fff) {#fedora-community} + -[[package](https://packages.fedoraproject.org/pkgs/golang-github-task/go-task/)] -[[source](https://src.fedoraproject.org/rpms/golang-github-task)] + + + + + ```shell dnf install go-task ``` -### FreeBSD ([Ports](https://ports.freebsd.org/cgi/ports.cgi)) ![FreeBSD](https://img.shields.io/badge/FreeBSD-990000?logo=freebsd&logoColor=fff) {#freebsd} + -[[package](https://cgit.freebsd.org/ports/tree/devel/task)] -[[source](https://cgit.freebsd.org/ports/tree/devel/task/Makefile)] + + + + + ```shell pkg install task ``` -### [Nix](https://nixos.org) ![Nix](https://img.shields.io/badge/Nix-5277C3?logo=nixos&logoColor=fff) ![NixOS](https://img.shields.io/badge/NixOS-5277C3?logo=nixos&logoColor=fff) ![Linux](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black) ![macOS](https://img.shields.io/badge/MacOS-000000?logo=apple&logoColor=F0F0F0) {#nix} + -[[source](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix)] + + + + + ```shell nix-env -iA nixpkgs.go-task ``` -### [pacstall](https://github.com/pacstall/pacstall) ![Debian](https://img.shields.io/badge/Debian-A81D33?logo=debian&logoColor=fff) ![Ubuntu](https://img.shields.io/badge/Ubuntu-E95420?logo=ubuntu&logoColor=fff) {#pacstall} + -[[package](https://pacstall.dev/packages/go-task-deb)] -[[source](https://github.com/pacstall/pacstall-programs/blob/master/packages/go-task-deb/go-task-deb.pacscript)] + + + + + ```shell pacstall -I go-task-deb ``` -### [pkgx](https://pkgx.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) {#pkgx} + -[[package](https://pkgx.dev/pkgs/taskfile.dev)] -[[source](https://github.com/pkgxdev/pantry/blob/main/projects/taskfile.dev/package.yml)] + + + + + ```shell pkgx task @@ -250,75 +450,88 @@ or, if you have pkgx integration enabled: task ``` -## Get The Binary + -### Binary +
-You can download the binary from the -[releases page on GitHub](https://github.com/go-task/task/releases) and add to -your `$PATH`. +## Binaries & CI {#get-the-binary} -DEB, RPM and APK packages are also available. +Install Task without a package manager: download a binary, use the install +script, or add the setup action to your GitHub workflow. -The `task_checksums.txt` file contains the SHA-256 checksum for each file. +### Download a binary {#binary} -### Install Script +1. Open the [GitHub releases](https://github.com/go-task/task/releases) and + download the archive for your operating system and architecture. +2. Extract `task` (`task.exe` on Windows). +3. Move the executable to a directory on your `PATH`. -We also have an -[install script](https://github.com/go-task/task/blob/main/install-task.sh) -which is very useful in scenarios like CI. Many thanks to -[GoDownloader](https://github.com/goreleaser/godownloader) for enabling the easy -generation of this script. +Each release also includes DEB, RPM and APK packages, plus `task_checksums.txt` +with SHA-256 checksums for the release files. -By default, it installs on the `./bin` directory relative to the working -directory: +### Install with a script {#install-script} -```shell +Use the +[install script](https://github.com/go-task/task/blob/main/install-task.sh) for +a shell-based installation, including CI environments. It downloads a prebuilt +binary and verifies its checksum; no Go installation is needed. + +By default, the script installs the latest release into `./bin`, relative to +your current directory. Choose a different directory or pin a release: + +::: code-group + +```shell [Latest release] sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d ``` -It is possible to override the installation directory with the `-b` parameter. -On Linux, common choices are `~/.local/bin` and `~/bin` to install for the -current user or `/usr/local/bin` to install for all users: - -```shell +```shell [Custom directory] sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin ``` -::: warning - -On macOS and Windows, `~/.local/bin` and `~/bin` are not added to `$PATH` by -default. - -::: - -By default, it installs the latest version available. You can also specify a tag -(available in [releases](https://github.com/go-task/task/releases)) to install a -specific version: - -```shell -sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d v3.36.0 +```shell [Pinned version] +sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d v3.42.1 ``` -Parameters are order specific, to set both installation directory and version: - -```shell +```shell [Directory + version] sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin v3.42.1 ``` +::: + +When combining options, keep the +[release tag](https://github.com/go-task/task/releases) last. + +::: tip Make Task available in your shell + +Add the installation directory to your `PATH` to run `task` from anywhere. With +the default location, you can also run `./bin/task` directly. + +On Linux, `~/.local/bin` and `~/bin` are common per-user locations; +`/usr/local/bin` is a system-wide location and may require elevated permissions. +Do not assume these directories are already on your `PATH`, especially on macOS +and Windows. + +::: + ### GitHub Actions -We have an [official GitHub Action](https://github.com/go-task/setup-task) to -install Task in your GitHub workflows. This repository is forked from the -fantastic project by the Arduino team. Check out the repository for more -examples and configuration. +Add the [official setup action](https://github.com/go-task/setup-task) to your +job's `steps` before running Task: ```yaml - name: Install Task - uses: go-task/setup-task@v1 + uses: go-task/setup-task@v2 + +- name: Verify Task + run: task --version ``` -## Build From Source +Use the action's `version` input to pin a Task release. See the +[action documentation](https://github.com/go-task/setup-task#usage) for examples +and configuration. + +## Build from source Ensure that you have a supported version of [Go](https://golang.org) properly installed and setup. You can find the minimum required version of Go in the @@ -364,20 +577,39 @@ demand before calling it. go tool task {arguments...} ``` -## Setup completions +## Verify installation + +After installing, open a terminal and check that Task is available: + +```shell +task --version +``` + +If you installed Task with `go tool`, run `go tool task --version` instead. + +You're ready to [create your first Taskfile](./getting-started.md). You can also +enable shell completions below. + +## Shell completions {#setup-completions} Some installation methods will automatically install completions too, but if this isn't working for you or your chosen method doesn't include them, you can run `task --completion ` to output a completion script for any supported -shell. There are a couple of ways these completions can be added to your shell -config: +shell. + +Every shell shares a single source of truth: the script is a thin wrapper that +asks the `task` binary itself what to suggest, so Bash, Zsh, Fish, Nushell and +PowerShell all offer the same task names, aliases, flags, flag values and +`requires` vars. + +There are a couple of ways these completions can be added to your shell config: ### Option 1. Load the completions in your shell's startup config (Recommended) This method loads the completion script from the currently installed version of task every time you create a new shell. This ensures that your completions are -always up-to-date. -If your executable isn’t named task, set the `TASK_EXE` environment variable before running eval. +always up-to-date. If your executable isn’t named task, set the `TASK_EXE` +environment variable before running eval. ::: code-group @@ -446,9 +678,10 @@ task --completion nu | save --force ($nu.data-dir | path join "vendor/autoload/t ### Zsh customization -The Zsh completion supports the standard `verbose` zstyle to control whether task -descriptions are shown. By default, descriptions are displayed. To show only task -names without descriptions, add this to your `~/.zshrc` (after the completion is loaded): +The Zsh completion supports the standard `verbose` zstyle to control whether +task descriptions are shown. By default, descriptions are displayed. To show +only task names without descriptions, add this to your `~/.zshrc` (after the +completion is loaded): ```shell zstyle ':completion:*:*:task:*' verbose false @@ -465,24 +698,25 @@ zstyle ':completion:*:*:task:*' show-aliases false 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. +in sync with the installed version of Task, and 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: +Nushell shares a single external completer between every command, so the script +chains to the one already configured — carapace and friends keep working. Load it +from an autoload directory as shown above rather than from `config.nu`, so that +your own completer is the one being chained to. If you would rather wire it +yourself, the script also exposes a `task-external-completer` command: ```nu -use ($nu.data-dir | path join "vendor/autoload/task-completions.nu") * -alias go-task = task +$env.config.completions.external.completer = {|spans| + match ($spans | first) { + task => (task-external-completer $spans) + _ => (do $my_other_completer $spans) + } +} ``` + +Two engine directives behave differently under Nushell by design: it never +appends a space after an external completion (so `NoSpace` is a no-op) and never +re-sorts the results (so `KeepOrder` is always honoured). diff --git a/website/src/latest/docs/integrations.md b/website/src/latest/docs/integrations.md index 9d95151d..8d779146 100644 --- a/website/src/latest/docs/integrations.md +++ b/website/src/latest/docs/integrations.md @@ -3,6 +3,8 @@ title: Integrations description: Official and community integrations for Task, including VS Code, JSON schemas, and other tools +section: Getting Started +docType: guide outline: deep --- diff --git a/website/src/latest/docs/reference/cli.md b/website/src/latest/docs/reference/cli.md index 11a72bf6..16595296 100644 --- a/website/src/latest/docs/reference/cli.md +++ b/website/src/latest/docs/reference/cli.md @@ -2,6 +2,8 @@ title: Command Line Interface Reference description: Complete reference for Task CLI commands, flags, and exit codes permalink: /reference/cli/ +section: Reference +docType: reference outline: deep --- @@ -457,6 +459,10 @@ Task uses specific exit codes to indicate different types of errors: - **105** - Remote Taskfile fetch not secure - **106** - No cache for remote Taskfile in offline mode - **107** - No schema version defined in Taskfile +- **108** - Remote Taskfile network timeout +- **109** - Invalid Taskfile +- **110** - Taskfile cycle detected +- **111** - Taskfile does not match checksum ### Task Errors (200-255) @@ -468,6 +474,7 @@ Task uses specific exit codes to indicate different types of errors: - **205** - Task cancelled by user - **206** - Missing required variables - **207** - Variable has incorrect value +- **208** - Task timed out ::: info diff --git a/website/src/latest/docs/reference/config.md b/website/src/latest/docs/reference/config.md index ff694117..98376bc3 100644 --- a/website/src/latest/docs/reference/config.md +++ b/website/src/latest/docs/reference/config.md @@ -2,6 +2,8 @@ title: Configuration Reference description: Complete reference for the Task config files and env vars permalink: /reference/config/ +section: Reference +docType: reference outline: deep --- @@ -85,7 +87,7 @@ experiments: - **Type**: `boolean` - **Default**: `false` - **Description**: Enable verbose output for all tasks -- **CLI equivalent**: [`-v, --verbose`](./cli.md#-v---verbose) +- **CLI equivalent**: [`-v, --verbose`](./cli.md#v-verbose) - **Environment variable**: [`TASK_VERBOSE`](./environment.md#task-verbose) ```yaml @@ -97,7 +99,7 @@ verbose: true - **Type**: `boolean` - **Default**: `false` - **Description**: Disables echoing of commands -- **CLI equivalent**: [`-s, --silent`](./cli.md#-s---silent) +- **CLI equivalent**: [`-s, --silent`](./cli.md#s-silent) - **Environment variable**: [`TASK_SILENT`](./environment.md#task-silent) ```yaml @@ -110,7 +112,7 @@ silent: true - **Default**: `true` - **Description**: Enable colored output. Colors are automatically enabled in CI environments (`CI=true`). -- **CLI equivalent**: [`-c, --color`](./cli.md#-c---color) +- **CLI equivalent**: [`-c, --color`](./cli.md#c-color) - **Environment variable**: [`TASK_COLOR`](./environment.md#task-color) ```yaml @@ -123,7 +125,7 @@ color: false - **Default**: `false` - **Description**: Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name. -- **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy) +- **CLI equivalent**: [`--disable-fuzzy`](./cli.md#disable-fuzzy) - **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) @@ -136,7 +138,7 @@ disable-fuzzy: true - **Type**: `integer` - **Minimum**: `1` - **Description**: Number of concurrent tasks to run -- **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number) +- **CLI equivalent**: [`-C, --concurrency`](./cli.md#c-concurrency-number) - **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency) @@ -149,7 +151,7 @@ concurrency: 4 - **Type**: `boolean` - **Default**: `false` - **Description**: Stop executing dependencies as soon as one of them fail -- **CLI equivalent**: [`-F, --failfast`](./cli.md#-f---failfast) +- **CLI equivalent**: [`-F, --failfast`](./cli.md#f-failfast) - **Environment variable**: [`TASK_FAILFAST`](./environment.md#task-failfast) ```yaml @@ -164,7 +166,7 @@ failfast: true 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. -- **CLI equivalent**: [`--interactive`](./cli.md#--interactive) +- **CLI equivalent**: [`--interactive`](./cli.md#interactive) ```yaml interactive: true @@ -300,6 +302,81 @@ task --trusted-hosts github.com,gitlab.com -t https://github.com/user/repo.git// task --trusted-hosts example.com:8080 -t https://example.com:8080/Taskfile.yml ``` +#### `remote.headers` + +- **Type**: `array of objects` +- **Default**: `[]` (empty list) +- **Description**: HTTP headers to send when downloading a remote Taskfile from + a given host, including authentication and custom headers + +```yaml +remote: + headers: + - host: gitlab.com + headers: + PRIVATE-TOKEN: '{{env "GITLAB_TOKEN"}}' + - host: artifacts.example.com:8443 + headers: + Authorization: 'Bearer {{env "ARTIFACTS_TOKEN"}}' + Accept: application/yaml + X-Custom-Header: custom-value +``` + +Use this option for authentication, content negotiation or other headers your +server expects. For authentication, this is the recommended way to access a +remote Taskfile. Unlike a credential placed in the URL, the header never appears +in your Taskfile, in the confirmation prompt or in an error message, so the +include URL stays safe to commit. + +Each entry applies to a single host, matched exactly and including the port if +the URL has one — the same rule as +[`remote.trusted-hosts`](#remote-trusted-hosts). Header values may reference +[templating functions](./templating.md), evaluated when Task contacts the host. +Values starting with `{{` must be quoted, as YAML would +otherwise read them as a mapping. An undefined environment variable expands to +nothing, so the header is sent empty. For an authentication header, this may +cause the server to reject the request with a `401`. + +Functions compose, so an `Authorization` header needs no manual encoding: + +```yaml +remote: + headers: + - host: artifacts.example.com + headers: + Authorization: 'Basic {{ printf "%s:%s" (env "USER") (env "PASS") | b64enc }}' +``` + +::: warning + +Only functions are available here — `{{.GITLAB_TOKEN}}` and +other variable references resolve to nothing. The configuration file is read +before any Taskfile, so no variable exists yet. Use +`{{env "GITLAB_TOKEN"}}` instead. + +::: + +The header your server expects depends on the service: + +| Service | Header | +| ----------- | -------------------------------------- | +| GitLab API | `PRIVATE-TOKEN` (or `JOB-TOKEN` in CI) | +| GitHub API | `Authorization: Bearer ` | +| Artifactory | `X-JFrog-Art-Api` | + +There is no CLI flag or environment variable for this option: a token given on +the command line would be visible to any process listing it. + +::: warning + +Headers are only sent to the host they are configured for. If that host answers +with a redirect to another one, the request follows the redirect **without** +them, and will likely fail — point the URL at the final host instead. Headers +are also HTTP-only: a Taskfile fetched over `git` should authenticate with SSH +or a git credential helper. + +::: + #### `remote.cacert` - **Type**: `string` @@ -354,6 +431,10 @@ remote: trusted-hosts: - github.com - gitlab.com + headers: + - host: gitlab.com + headers: + PRIVATE-TOKEN: '{{env "GITLAB_TOKEN"}}' cacert: '' cert: '' cert-key: '' diff --git a/website/src/latest/docs/reference/environment.md b/website/src/latest/docs/reference/environment.md index 87bc29c7..5e2ce19e 100644 --- a/website/src/latest/docs/reference/environment.md +++ b/website/src/latest/docs/reference/environment.md @@ -1,6 +1,8 @@ --- title: Environment Reference description: A reference for the Taskfile environment variables +section: Reference +docType: reference outline: deep --- @@ -87,7 +89,7 @@ files > defaults. - **Type**: `string` (`interleaved`, `group`, `prefixed`) - **Description**: Sets the output style -- **CLI equivalent**: [`--output`](./cli.md#--output-string) +- **CLI equivalent**: [`--output`](./cli.md#o-output-mode) ### `TASK_OUTPUT_GROUP_BEGIN` @@ -95,7 +97,7 @@ files > defaults. - **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) + [`--output-group-begin`](./cli.md#output-group-begin-template) ### `TASK_OUTPUT_GROUP_END` @@ -103,7 +105,7 @@ files > defaults. - **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) + [`--output-group-end`](./cli.md#output-group-end-template) ### `TASK_OUTPUT_GROUP_ERROR_ONLY` @@ -112,7 +114,7 @@ files > defaults. - **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) + [`--output-group-error-only`](./cli.md#output-group-error-only) ### `TASK_TEMP_DIR` diff --git a/website/src/latest/docs/reference/package.md b/website/src/latest/docs/reference/package.md index 7f710124..cd3cc3c8 100644 --- a/website/src/latest/docs/reference/package.md +++ b/website/src/latest/docs/reference/package.md @@ -1,6 +1,8 @@ --- title: Package API Reference description: A reference for Task's Golang package API +section: Reference +docType: reference --- # Package API Reference diff --git a/website/src/latest/docs/reference/schema.md b/website/src/latest/docs/reference/schema.md index 471d9816..026017bd 100644 --- a/website/src/latest/docs/reference/schema.md +++ b/website/src/latest/docs/reference/schema.md @@ -1,6 +1,8 @@ --- title: Taskfile Schema Reference description: A reference for the Taskfile schema +section: Reference +docType: reference outline: deep --- @@ -420,7 +422,7 @@ value. For complete documentation on secret variables, including security considerations and best practices, see the -[Secret variables](/docs/guide#secret-variables) section in the Guide. +[Secret variables](../guide/secret-variables.md) section in the Guide. ::: @@ -786,7 +788,8 @@ tasks: # … ``` -See [Prompting for missing variables interactively](/docs/guide#prompting-for-missing-variables-interactively) +See +[Prompting for missing variables interactively](../guide/required-variables.md#prompting-for-missing-variables-interactively) for information on enabling interactive prompts for missing required variables. #### `watch` @@ -983,7 +986,7 @@ 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) +timed-out command reports [`EXIT_CODE`](./templating.md#exit-code) `124`, following the convention of `timeout(1)`. A dependency takes the same key: diff --git a/website/src/latest/docs/reference/templating.md b/website/src/latest/docs/reference/templating.md index 37bdbe94..3dac6396 100644 --- a/website/src/latest/docs/reference/templating.md +++ b/website/src/latest/docs/reference/templating.md @@ -3,6 +3,8 @@ title: Templating Reference description: Comprehensive guide to Task's templating system with Go text/template, special variables, and available functions +section: Reference +docType: reference outline: deep --- @@ -334,7 +336,7 @@ tasks: - **Type**: `int` - **Description**: Failed command exit code (only in `defer`, only when - non-zero). A command killed by its [`timeout`](/docs/reference/schema#command) + non-zero). A command killed by its [`timeout`](./schema.md#command) is reported as `124`, following the convention of `timeout(1)`. ```yaml diff --git a/website/src/latest/docs/releasing.md b/website/src/latest/docs/releasing.md index ac9452ff..0436703d 100644 --- a/website/src/latest/docs/releasing.md +++ b/website/src/latest/docs/releasing.md @@ -3,6 +3,8 @@ title: Releasing description: Task release process including GoReleaser, Homebrew, npm, Snapcraft, winget, and other package managers +section: Contributing +docType: contributing outline: deep --- @@ -16,20 +18,38 @@ of the Taskfile. artifacts automatically when a new Git tag is pushed to `main` branch (raw executables and DEB and RPM packages). -Raw executables can also be reproduced and verified locally by -checking out a specific tag and calling `goreleaser build`, using the Go version -defined in the above GitHub Actions. +The body of the GitHub release is the section of the `CHANGELOG.md` matching the +version being released, extracted by `go run ./cmd/release --notes`. A version +without changelog entries is released with an empty body. + +Raw executables can also be reproduced and verified locally by checking out a +specific tag and calling `goreleaser build`, using the Go version defined in the +above GitHub Actions. ## Website `task release:` promotes the documentation before tagging: the docs in -`website/src/next/docs`, their sidebar and the `next-*` JSON schemas are copied over -their published counterparts, so the released tag carries the docs of the +`website/src/next/docs`, their sidebar and the `next-*` JSON schemas are copied +over their published counterparts, so the released tag carries the docs of the version it ships. The release workflow then runs `task website:deploy:prod`. +A new blog post is a Markdown file in `website/src/next/blog` with no file at +the same relative path in `website/src/latest/blog`, excluding `index.md`. +Renaming a post therefore makes it new. On the `next` site, new posts display +the build date in UTC (`YYYY-MM-DD`) and are sorted using that date, without +changing the source files. The `latest` site uses only the stored dates. + +During release preparation, `cmd/release` replaces or adds the `date` in each +new post's frontmatter with the same local date used for the changelog. It +validates all new posts' frontmatter before writing; an error identifies the +file to fix. It then copies the blog to `latest`, so both copies carry the same +date in the release commit. This is the preparation date, even if publication on +GitHub happens later. Already published posts keep their dates, including when +their content changes. The `--version` and `--notes` flags do not write files. + Because taskfile.dev is built from the latest copy, it can be redeployed at any -time between releases - to publish a blog post or a documentation fix - -without exposing the docs of unreleased features: +time between releases - to publish a blog post or a documentation fix - without +exposing the docs of unreleased features: ```shell git checkout main && git pull @@ -40,24 +60,19 @@ task website:deploy:prod GoReleaser will automatically publish the release to most package managers: -* Cloudsmith (DEB and RPM repositories) -* Homebrew -* npm -* winget +- Cloudsmith (DEB and RPM repositories) +- Homebrew +- npm +- Snapcraft +- winget -A single package manager still require manual steps: - -* Snapcraft: - * Update the `version:` field on [snapcraft.yaml][snapcraftyaml] - * Trigger a new build on [Snapcraft -> Builds][snapcraftbuilds] - * Once finished, move the new build to "stable" on [Snapcraft -> Releases][snapcraftreleases] +Once the release is published, GoReleaser announces it on the +[Discord server](https://discord.gg/6TY36E39UK). Nightly releases are not +announced. These package managers are updated automatically by the community: -* [Scoop](https://github.com/ScoopInstaller/Main/blob/master/bucket/task.json) -* [Nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix) +- [Scoop](https://github.com/ScoopInstaller/Main/blob/master/bucket/task.json) +- [Nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/go/go-task/package.nix) [goreleaser]: https://goreleaser.com/ -[snapcraftyaml]: https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml#L2 -[snapcraftbuilds]: https://snapcraft.io/task/builds -[snapcraftreleases]: https://snapcraft.io/task/releases diff --git a/website/src/latest/docs/remote-taskfiles.md b/website/src/latest/docs/remote-taskfiles.md index 4d54918e..b75b57b7 100644 --- a/website/src/latest/docs/remote-taskfiles.md +++ b/website/src/latest/docs/remote-taskfiles.md @@ -1,57 +1,129 @@ --- +title: Remote Taskfiles +description: + Guide to loading and securely using Taskfiles from HTTP and Git sources +section: Guide +docType: guide outline: deep --- # Remote Taskfiles +Use a remote Taskfile to share tasks across projects without copying the file +into each repository. You can call it directly or include it under a namespace. + ::: danger -Never run remote Taskfiles from sources that you do not trust. +Only run remote Taskfiles from sources you trust. Their commands execute on your +machine, just like commands from a local Taskfile. ::: -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. +The examples use Task's public sample, whose `hello` task prints `Hello Task!`. +On first use, Task asks you to trust the downloaded file. Review it before +accepting; see [trust and checksums](#security) for subsequent changes and CI. -Task uses "nodes" to reference remote Taskfiles. There are a few different types -of node which you can use: +## Run a remote Taskfile {#specifying-a-remote-entrypoint} + +Pass the remote location to `--taskfile` (or `-t`). With no task name, Task runs +the remote file's `default` task. Choose a transport below: ::: code-group -```text [HTTP/HTTPS] -https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +```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! ``` -```text [Git over HTTP] -https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +```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! ``` -```text [Git over SSH] -git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +```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! ``` ::: -## Node Types +## Include shared tasks {#including-remote-taskfiles} + +Set the include location to a remote URL instead of a local path. The tasks +become available under the namespace you choose, just like +[local includes](./guide/includes.md): + +::: code-group + +```yaml [HTTP/HTTPS] +version: '3' + +includes: + shared: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml +``` + +```yaml [Git over HTTP] +version: '3' + +includes: + shared: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +```yaml [Git over SSH] +version: '3' + +includes: + shared: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main +``` + +::: + +```shell +$ task shared:hello +task: [hello] echo "Hello Task!" +Hello Task! +``` + +### Supply authentication {#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: + shared: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml +``` + +Prefer the [`remote.headers`](./reference/config.md#remote-headers) configuration +option when the server accepts a header. A credential in the URL ends up in +error messages and in the confirmation prompt, and the include can no longer be +committed as-is. + +## Choose a source {#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. +Use a direct URL when the server exposes the Taskfile as plain text. Task +downloads the file from that 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. +Use a Git URL to select a file from a 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. @@ -63,9 +135,9 @@ This is the same URL that you would use to clone the repo over HTTP. `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. +Use an SSH Git URL when repository access depends on your SSH credentials. 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. @@ -76,119 +148,24 @@ SSH keys added so that they can be used during authentication. `?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: +## Locate files and directories {#special-variables} -```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: +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 | +| `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 +## Review trust and changes {#security} -### Automatic checksums +### Review changed files {#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 @@ -221,7 +198,7 @@ in Task. You can also configure trusted hosts in your containing a commit hash) to prevent Task from automatically accepting a prompt that says a remote Taskfile has changed. -### Manual checksum pinning +### Pin reviewed contents {#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: @@ -231,14 +208,15 @@ version: '3' includes: included: - taskfile: https://taskfile.dev - checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9 + taskfile: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml + checksum: '' ``` -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: +Replace the placeholder with the SHA-256 checksum of the file you reviewed. A +pinned checksum disables 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 @@ -251,7 +229,7 @@ checksum. There are a couple of ways you can obtain this: will report the incorrect expected checksum and the actual checksum. You can copy the actual checksum and replace your temporary random value. -### TLS +### Use TLS {#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 @@ -260,7 +238,7 @@ 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 +#### Add certificates {#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 @@ -293,7 +271,17 @@ openssl rsa -in encrypted.key -out decrypted.key These options can also be configured in the [configuration file](#configuration). -## Caching & Running Offline +## Reuse cached files {#caching-running-offline} + +| What do you need? | Option | +| -------------------------------------------- | --------------- | +| Reuse a downloaded copy for one hour | `--expiry 1h` | +| Use an existing cache without network access | `--offline` | +| Fetch a fresh copy now | `--download` | +| Remove cached remote files | `--clear-cache` | + +For example, run `task --offline shared:hello` after downloading and trusting +the include above. Offline mode needs an existing cached copy. 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 @@ -306,8 +294,7 @@ version. However, the cache expiry duration can be modified by setting the 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. +An uncached remote file cannot run offline. 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 @@ -326,7 +313,7 @@ the `--download` flag. You can use the `--clear-cache` flag to clear all cached remote files. -## Configuration +## Set remote defaults {#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 diff --git a/website/src/latest/docs/security/incident-response-plan.md b/website/src/latest/docs/security/incident-response-plan.md index a1b35fae..4b79660b 100644 --- a/website/src/latest/docs/security/incident-response-plan.md +++ b/website/src/latest/docs/security/incident-response-plan.md @@ -1,5 +1,10 @@ --- title: Incident Response Plan +description: + Task's process for detecting, triaging, mitigating, and disclosing security + incidents +section: Project +docType: project outline: deep --- @@ -88,4 +93,4 @@ a "best-effort" attempt to help resolve the issue. - Make and document any changes that can be made to prevent similar issues from arising in the future. -[security-docs]: ../security/ +[security-docs]: ./index.md diff --git a/website/src/latest/docs/security/index.md b/website/src/latest/docs/security/index.md index a80aef94..d5338abb 100644 --- a/website/src/latest/docs/security/index.md +++ b/website/src/latest/docs/security/index.md @@ -1,5 +1,10 @@ --- title: Security +description: + How to report Task security vulnerabilities and how the project responds to + them +section: Project +docType: project outline: deep --- @@ -18,5 +23,5 @@ You can read more about how we handle security-related issues in our [Incident Response Plan][irp] and [Threat Model][tm]. [pvr]: https://github.com/go-task/task/security/advisories/new -[irp]: ./incident-response-plan -[tm]: ./threat-model +[irp]: ./incident-response-plan.md +[tm]: ./threat-model.md diff --git a/website/src/latest/docs/security/threat-model.md b/website/src/latest/docs/security/threat-model.md index 7cd40ed2..7ff8195f 100644 --- a/website/src/latest/docs/security/threat-model.md +++ b/website/src/latest/docs/security/threat-model.md @@ -1,5 +1,10 @@ --- title: Threat Model +description: + Threats, assets, trust boundaries, and mitigations for the Task project and + its release infrastructure +section: Project +docType: project outline: deep --- @@ -13,8 +18,8 @@ of our commitment to transparency. ### Critical Assets -- **Source Code:** The Task CLI, build scripts, and configuration files - (e.g., `Taskfile.yml`, `.goreleaser.yml`). +- **Source Code:** The Task CLI, build scripts, and configuration files (e.g., + `Taskfile.yml`, `.goreleaser.yml`). - **Build Artifacts:** Compiled binaries, packages, and containers distributed to users. - **Secrets:** API tokens, signing keys, and repository credentials used in @@ -75,8 +80,8 @@ of our commitment to transparency. #### Secrets Leakage -- Exposure of tokens, credentials, or signing keys in logs, error messages, - or artifacts +- Exposure of tokens, credentials, or signing keys in logs, error messages, or + artifacts - Hardcoded secrets in code or configuration - Improper secret management in CI/CD environments @@ -168,7 +173,7 @@ of our commitment to transparency. ## References - [Task Documentation](https://taskfile.dev/) -- [Incident Response Plan](./incident-response-plan) +- [Incident Response Plan](./incident-response-plan.md) - [OWASP Top 10](https://owasp.org/www-project-top-ten/) - [Supply Chain Security](https://slsa.dev/) - [GitHub Security Best Practices](https://docs.github.com/en/code-security) diff --git a/website/src/latest/docs/styleguide.md b/website/src/latest/docs/styleguide.md index f1061680..36d06c8e 100644 --- a/website/src/latest/docs/styleguide.md +++ b/website/src/latest/docs/styleguide.md @@ -3,6 +3,8 @@ title: Style Guide description: Official style guide for Taskfile.yml files with best practices and recommended conventions +section: Contributing +docType: contributing outline: deep --- diff --git a/website/src/latest/docs/taskfile-versions.md b/website/src/latest/docs/taskfile-versions.md index 44f90778..7c7ee612 100644 --- a/website/src/latest/docs/taskfile-versions.md +++ b/website/src/latest/docs/taskfile-versions.md @@ -3,6 +3,8 @@ title: Taskfile Versions description: How to use the Taskfile schema version to ensure users are using the correct versions of Task +section: Project +docType: project outline: deep --- diff --git a/website/src/next/blog/completion-engine.md b/website/src/next/blog/completion-engine.md index 1902f235..1481282c 100644 --- a/website/src/next/blog/completion-engine.md +++ b/website/src/next/blog/completion-engine.md @@ -4,7 +4,7 @@ description: A new completion engine that gives every shell the same suggestions, and that can finally complete your required variables. author: vmaerten -date: 2026-09-29 +date: 2026-10-01 tags: ['new-features', 'completion'] outline: deep editLink: false diff --git a/website/src/next/docs/changelog.md b/website/src/next/docs/changelog.md index edbd3cda..6fbc44eb 100644 --- a/website/src/next/docs/changelog.md +++ b/website/src/next/docs/changelog.md @@ -13,7 +13,54 @@ editLink: false ::: v-pre -## v3.53.0 - 2026-08-18 +## v3.54.0 - 2026-10-01 + +### 🚀 Features + +- Added versioned Homebrew casks (`go-task@.`) to install a + specific minor version of Task (#3023 by @vmaerten). +- Added a `remote.headers` config option to send HTTP headers when downloading a + remote Taskfile, configured per host. Header values support templating + functions, e.g. `{{env "GITLAB_TOKEN"}}`. This keeps the credential out of the + include URL, where it would leak into error messages and the confirmation + prompt (#2329 by @vmaerten). + +### 🐛 Fixes + +- Fixed remote Git Taskfile cache poisoning on shared hosts (GHSA-679p-658w-m3wr, + reported by @danielcadev, fixed by @vmaerten). +- Fixed tasks cancelled by the user returning exit code `201` instead of `205` + (#3040, #3041 by @r3wretrhy). +- Fixed a bug on Windows where watching source paths did not work as expected + (#2863, #3028 by @pd93). +- Fixed a remote Taskfile whose server refuses the credentials being reported as + a missing Taskfile. A `401` now stops the search and reports the status code, + instead of retrying every default Taskfile name and concluding that no + Taskfile exists (#2329 by @vmaerten). + +- `task --completion ` now serves a new completion engine that unifies + Bash, Fish, Zsh, Nushell and PowerShell behind a single `task __complete` + command, so every shell offers the same suggestions: task names, aliases, + flags, flag values and per-task CLI variables. The Zsh `show-aliases` and + `verbose` zstyles keep working, now backed by the `--no-aliases` and + `--no-descriptions` completion flags (#2897 by @vmaerten). + +### 📦 Package API + +- Bumped the minimum Go version to 1.26. Task follows Go's two-latest support + window, and is now tested against 1.26 and 1.27. This only affects projects + importing Task as a Go module (#2920 by @vmaerten). + +### Other + +- Refactored some functional options to always return a concrete type instead of + an interface and moved options into their own file (#3037 by @pd93). +- Refactored the execext package to use mvdan/sh's new BashOpts API (#3035 by + @pd93). + +## v3.53.1 - 2026-08-18 + +### 🚀 Features - **Remote Taskfiles are now generally available!** This has been an experimental feature for 3 years, but is now enabled by default. Massive @@ -21,21 +68,37 @@ editLink: false here). We've also given the [Remote Taskfiles documentation](https://taskfile.dev/docs/remote-taskfiles) a bit of a polish (#1317, #2906 by @pd93). +- 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). - 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). +- `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). +- 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). +- 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 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). + +### 🐛 Fixes + +- Fixed a pinned `checksum:` not being verified when a remote Taskfile came from + the cache (#2980 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 @@ -43,37 +106,31 @@ editLink: false 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 pressing `Esc` at an interactive variable prompt not cancelling the run + (#2942 by @anilnatha). +- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing + `http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin). - 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). + +### 📚 Documentation & Website + +- Updated taskfile versions doc to mention when version checks were introduced + (#2184 by @jubr). - Load the sidebar data and titles/excerpts from the blog post markdown document and its frontmatter on the website (#2981 by @pd93). +## v3.53.0 - 2026-08-18 + +- Failed due to an issue with our release process. + ## v3.52.0 - 2026-07-02 - Fixed --interactive prompts for required vars sometimes appearing in a random @@ -1638,4 +1695,4 @@ document, since it describes in depth what changed for this version. - Add LICENSE file -::: +::: \ No newline at end of file diff --git a/website/src/public/schema-taskrc.json b/website/src/public/schema-taskrc.json index d12f4460..a49043a2 100644 --- a/website/src/public/schema-taskrc.json +++ b/website/src/public/schema-taskrc.json @@ -49,6 +49,28 @@ "items": { "type": "string" } + }, + "headers": { + "type": "array", + "description": "HTTP headers to send when downloading remote Taskfiles, per host, including authentication and custom headers.", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "Host the headers apply to, including the port if the URL has one (e.g., 'gitlab.com', 'example.com:8080')." + }, + "headers": { + "type": "object", + "description": "Headers to send. Values support templating functions, e.g. {{env \"GITLAB_TOKEN\"}}.", + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["host", "headers"], + "additionalProperties": false + } } }, "additionalProperties": false