From 5aeb24e4175dd317013d15cd2be07edd30caa5d5 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 16:51:31 +0200 Subject: [PATCH 01/21] docs(site): split the guide into per-topic pages The guide had grown to 2950 lines and 27 sections, a fifth of the whole documentation in one file, and it was where every new feature ended up. Each section is now its own page. Two sections were rearranged rather than moved verbatim. "Prevent unnecessary work" covered two different questions - whether the work is already done (fingerprints, status) and whether it should happen at all (preconditions, if, requires) - so it becomes three pages. "Running a remote Taskfile" is dropped entirely: its prose, its danger admonition and its three samples already appeared word for word in the Remote Taskfiles page. Every other heading keeps its exact text, so section anchors still resolve; only the page they live on changed. --- website/.vitepress/sidebar/next.ts | 60 ++- website/src/next/docs/arguments.md | 111 +++++ .../src/next/docs/conditional-execution.md | 199 ++++++++ website/src/next/docs/defining-tasks.md | 202 ++++++++ website/src/next/docs/dependencies.md | 226 +++++++++ website/src/next/docs/environment.md | 133 +++++ website/src/next/docs/getting-started.md | 4 +- website/src/next/docs/includes.md | 291 +++++++++++ website/src/next/docs/loops.md | 324 +++++++++++++ website/src/next/docs/output.md | 269 +++++++++++ website/src/next/docs/platforms.md | 110 +++++ website/src/next/docs/reference/schema.md | 5 +- website/src/next/docs/required-variables.md | 296 ++++++++++++ website/src/next/docs/running-tasks.md | 139 ++++++ website/src/next/docs/up-to-date.md | 232 +++++++++ website/src/next/docs/variables.md | 457 ++++++++++++++++++ website/src/next/docs/watch.md | 62 +++ 17 files changed, 3115 insertions(+), 5 deletions(-) create mode 100644 website/src/next/docs/arguments.md create mode 100644 website/src/next/docs/conditional-execution.md create mode 100644 website/src/next/docs/defining-tasks.md create mode 100644 website/src/next/docs/dependencies.md create mode 100644 website/src/next/docs/environment.md create mode 100644 website/src/next/docs/includes.md create mode 100644 website/src/next/docs/loops.md create mode 100644 website/src/next/docs/output.md create mode 100644 website/src/next/docs/platforms.md create mode 100644 website/src/next/docs/required-variables.md create mode 100644 website/src/next/docs/running-tasks.md create mode 100644 website/src/next/docs/up-to-date.md create mode 100644 website/src/next/docs/variables.md create mode 100644 website/src/next/docs/watch.md diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index c7171547bc..f7936ed05c 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -14,7 +14,65 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ }, { text: 'Guide', - link: '/docs/guide' + link: '/docs/guide', + items: [ + { + text: 'Running tasks', + link: '/docs/running-tasks' + }, + { + text: 'Defining tasks', + link: '/docs/defining-tasks' + }, + { + text: 'Passing arguments', + link: '/docs/arguments' + }, + { + text: 'Variables', + link: '/docs/variables' + }, + { + text: 'Environment variables', + link: '/docs/environment' + }, + { + text: 'Required variables and prompts', + link: '/docs/required-variables' + }, + { + text: 'Dependencies and task calls', + link: '/docs/dependencies' + }, + { + text: 'Skipping work that is up to date', + link: '/docs/up-to-date' + }, + { + text: 'Conditional execution', + link: '/docs/conditional-execution' + }, + { + text: 'Loops', + link: '/docs/loops' + }, + { + text: 'Including other Taskfiles', + link: '/docs/includes' + }, + { + text: 'Output and logging', + link: '/docs/output' + }, + { + text: 'Platform-specific behaviour', + link: '/docs/platforms' + }, + { + text: 'Watch mode', + link: '/docs/watch' + } + ] }, { text: 'Remote Taskfiles', diff --git a/website/src/next/docs/arguments.md b/website/src/next/docs/arguments.md new file mode 100644 index 0000000000..a68ca0d2e0 --- /dev/null +++ b/website/src/next/docs/arguments.md @@ -0,0 +1,111 @@ +--- +title: Passing arguments +description: + Forward command line arguments to a task with `--`, and match part of a task's + name with a wildcard. +outline: deep +--- + +# Passing arguments + +Tasks can take input from the command line in two ways: everything after `--`, +or a pattern in the task name itself. + +## 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 +``` diff --git a/website/src/next/docs/conditional-execution.md b/website/src/next/docs/conditional-execution.md new file mode 100644 index 0000000000..99b55765c5 --- /dev/null +++ b/website/src/next/docs/conditional-execution.md @@ -0,0 +1,199 @@ +--- +title: Conditional execution +description: + Decide whether a task should run at all, using `preconditions`, `if`, and the + flags that limit when a task runs. +outline: deep +--- + +# Conditional execution + +Where up-to-date checks ask whether the work is already done, these controls ask +whether the work should happen in the first place. + +## 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 +``` diff --git a/website/src/next/docs/defining-tasks.md b/website/src/next/docs/defining-tasks.md new file mode 100644 index 0000000000..360a7fb898 --- /dev/null +++ b/website/src/next/docs/defining-tasks.md @@ -0,0 +1,202 @@ +--- +title: Defining tasks +description: + Task syntax shortcuts, internal tasks, aliases, the directory a task runs in, + and the help text Task shows for it. +outline: deep +--- + +# Defining tasks + +Beyond a name and a list of commands, a task carries a handful of properties +that control how it is written, named and presented. + +## 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 +``` + +## 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 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..." +``` + +## 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}}" +``` + +## 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_. diff --git a/website/src/next/docs/dependencies.md b/website/src/next/docs/dependencies.md new file mode 100644 index 0000000000..997631f82a --- /dev/null +++ b/website/src/next/docs/dependencies.md @@ -0,0 +1,226 @@ +--- +title: Dependencies and task calls +description: + Run tasks in parallel with `deps`, call another task from `cmds`, and schedule + cleanup with `defer`. +outline: deep +--- + +# Dependencies and task calls + +A task can pull in other tasks in three ways, and each has different ordering +guarantees. + +## 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`. + +## 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](./output.md#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](./includes.md), add a leading `:` like this: +`task: :task-name`. + +::: + +## 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 +``` diff --git a/website/src/next/docs/environment.md b/website/src/next/docs/environment.md new file mode 100644 index 0000000000..040af3fd1d --- /dev/null +++ b/website/src/next/docs/environment.md @@ -0,0 +1,133 @@ +--- +title: Environment variables +description: + Set environment variables on a single task or on every task, and load them + from `.env` files. +outline: deep +--- + +# Environment variables + +Environment variables are set with `env`, which works at the root of the +Taskfile and on individual tasks. + +## 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.md) 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. + +::: diff --git a/website/src/next/docs/getting-started.md b/website/src/next/docs/getting-started.md index a6e8f7d91a..e463a471b6 100644 --- a/website/src/next/docs/getting-started.md +++ b/website/src/next/docs/getting-started.md @@ -72,7 +72,7 @@ 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 +[supported file names](./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. @@ -131,5 +131,5 @@ 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 +[usage guide](./guide.md) next. Alternatively, you can check out our reference docs for the [Taskfile schema](reference/schema) and [CLI](reference/cli). diff --git a/website/src/next/docs/includes.md b/website/src/next/docs/includes.md new file mode 100644 index 0000000000..46a74877db --- /dev/null +++ b/website/src/next/docs/includes.md @@ -0,0 +1,291 @@ +--- +title: Including other Taskfiles +description: + Reuse tasks across projects with `includes` — namespaces, optional and + internal includes, flattening, and per-include variables. +outline: deep +--- + +# 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 [Internal tasks](./defining-tasks.md#internal-tasks)). +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](./defining-tasks.md#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"}}'`. + +::: diff --git a/website/src/next/docs/loops.md b/website/src/next/docs/loops.md new file mode 100644 index 0000000000..ea49990a34 --- /dev/null +++ b/website/src/next/docs/loops.md @@ -0,0 +1,324 @@ +--- +title: Loops +description: + Repeat a command over a static list, a matrix, a variable, your task's + sources, or other tasks. +outline: deep +--- + +# Loops + +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 +``` diff --git a/website/src/next/docs/output.md b/website/src/next/docs/output.md new file mode 100644 index 0000000000..e643602a7b --- /dev/null +++ b/website/src/next/docs/output.md @@ -0,0 +1,269 @@ +--- +title: Output and logging +description: + Choose how Task prints command output, silence it, ignore errors, and annotate + failures in CI. +outline: deep +--- + +# Output and logging + +By default Task streams each command's output straight through. These settings +change what reaches the terminal and how it is grouped. + +## 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. + +::: + +## 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 +``` + +## 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`! + +## 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. diff --git a/website/src/next/docs/platforms.md b/website/src/next/docs/platforms.md new file mode 100644 index 0000000000..9c33bd1ada --- /dev/null +++ b/website/src/next/docs/platforms.md @@ -0,0 +1,110 @@ +--- +title: Platform-specific behaviour +description: + Restrict tasks and commands to an operating system or architecture, and set + shell options with `set` and `shopt`. +outline: deep +--- + +# Platform-specific behaviour + +The same Taskfile often has to behave differently depending on where it runs. + +## 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' +``` + +## `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. + +::: diff --git a/website/src/next/docs/reference/schema.md b/website/src/next/docs/reference/schema.md index 737ef2e951..d69d261d19 100644 --- a/website/src/next/docs/reference/schema.md +++ b/website/src/next/docs/reference/schema.md @@ -420,7 +420,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](../variables.md#secret-variables) section in the Guide. ::: @@ -786,7 +786,8 @@ tasks: # … ``` -See [Prompting for missing variables interactively](/docs/guide#prompting-for-missing-variables-interactively) +See +[Prompting for missing variables interactively](../required-variables.md#prompting-for-missing-variables-interactively) for information on enabling interactive prompts for missing required variables. #### `watch` diff --git a/website/src/next/docs/required-variables.md b/website/src/next/docs/required-variables.md new file mode 100644 index 0000000000..1bb7d658e6 --- /dev/null +++ b/website/src/next/docs/required-variables.md @@ -0,0 +1,296 @@ +--- +title: Required variables and prompts +description: + Require variables to be set, restrict them to a list of allowed values, and + prompt for them interactively. +outline: deep +--- + +# Required variables and prompts + +A task can refuse to run until it has what it needs, and it can ask the caller +for it. + +## 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`. + +::: + +## 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. + +::: diff --git a/website/src/next/docs/running-tasks.md b/website/src/next/docs/running-tasks.md new file mode 100644 index 0000000000..691dcca445 --- /dev/null +++ b/website/src/next/docs/running-tasks.md @@ -0,0 +1,139 @@ +--- +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. +outline: deep +--- + +# Running tasks + +Task looks for a Taskfile in the current directory, but it can run one from +almost anywhere else too. + +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 - +``` + +## 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. + +## Interactive CLI application + +When running interactive CLI applications inside Task they can sometimes behave +weirdly, especially when the [output mode](./output.md#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. diff --git a/website/src/next/docs/up-to-date.md b/website/src/next/docs/up-to-date.md new file mode 100644 index 0000000000..871c5c5668 --- /dev/null +++ b/website/src/next/docs/up-to-date.md @@ -0,0 +1,232 @@ +--- +title: Skipping work that is up to date +description: + Stop a task from running again when nothing has changed, using source and + generated file fingerprints or your own `status` checks. +outline: deep +--- + +# Skipping work that is up to date + +Task can skip a task entirely when its work is already done. There are two +mechanisms: let Task compare files for you, or tell it yourself. + +## 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 +``` diff --git a/website/src/next/docs/variables.md b/website/src/next/docs/variables.md new file mode 100644 index 0000000000..e41a9f6399 --- /dev/null +++ b/website/src/next/docs/variables.md @@ -0,0 +1,457 @@ +--- +title: Variables +description: + Static, dynamic, map and secret variables, how they are scoped, and how they + reference each other. +outline: deep +--- + +# 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](./dependencies.md#calling-another-task)) +- Variables of the [included Taskfile](./includes.md) (when the task is + included) +- Variables of the + [inclusion of the Taskfile](./includes.md#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 +``` + +::: diff --git a/website/src/next/docs/watch.md b/website/src/next/docs/watch.md new file mode 100644 index 0000000000..aba4ba2787 --- /dev/null +++ b/website/src/next/docs/watch.md @@ -0,0 +1,62 @@ +--- +title: Watch mode +description: Re-run a task automatically whenever its sources change. +outline: deep +--- + +# Watch mode + +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 From c3b5b58f6336c5a537716099a07aa55a4c4f8901 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 16:53:32 +0200 Subject: [PATCH 02/21] docs(site): turn the guide into an index with anchor redirects /docs/guide keeps its URL and becomes a grouped index of the pages the guide was split into, so the many links to it in issues, blog posts and Stack Overflow answers still land somewhere useful. Their fragments need more than that. Netlify never receives the part of a URL after the #, so a _redirects rule cannot route an anchor; GuideRedirect.vue reads location.hash and resolves it in the browser against a table of the 72 anchors the old page defined. Every entry was checked against the anchors VitePress actually emits. --- .../.vitepress/components/GuideRedirect.vue | 30 + website/.vitepress/guideAnchors.ts | 99 + website/.vitepress/theme/index.ts | 2 + website/src/next/docs/guide.md | 2974 +---------------- 4 files changed, 171 insertions(+), 2934 deletions(-) create mode 100644 website/.vitepress/components/GuideRedirect.vue create mode 100644 website/.vitepress/guideAnchors.ts diff --git a/website/.vitepress/components/GuideRedirect.vue b/website/.vitepress/components/GuideRedirect.vue new file mode 100644 index 0000000000..2a98182de8 --- /dev/null +++ b/website/.vitepress/components/GuideRedirect.vue @@ -0,0 +1,30 @@ + + + diff --git a/website/.vitepress/guideAnchors.ts b/website/.vitepress/guideAnchors.ts new file mode 100644 index 0000000000..bf5b4dea6f --- /dev/null +++ b/website/.vitepress/guideAnchors.ts @@ -0,0 +1,99 @@ +// Where each section of the old single-page guide went when it was +// split up. Netlify never sees the URL fragment, so a _redirects rule +// cannot route these; GuideRedirect.vue resolves them in the browser. +export const guideAnchors: Record = { + 'running-taskfiles': '/docs/running-tasks', + 'supported-file-names': '/docs/running-tasks#supported-file-names', + 'running-a-taskfile-from-a-subdirectory': + '/docs/running-tasks#running-a-taskfile-from-a-subdirectory', + 'running-a-global-taskfile': '/docs/running-tasks#running-a-global-taskfile', + 'running-a-taskfile-from-stdin': + '/docs/running-tasks#running-a-taskfile-from-stdin', + 'running-a-remote-taskfile': + '/docs/remote-taskfiles#specifying-a-remote-entrypoint', + 'environment-variables': '/docs/environment', + task: '/docs/environment#task', + 'env-files': '/docs/environment#env-files', + 'including-other-taskfiles': '/docs/includes', + 'remote-taskfiles': '/docs/includes#remote-taskfiles', + 'os-specific-taskfiles': '/docs/includes#os-specific-taskfiles', + 'directory-of-included-taskfile': + '/docs/includes#directory-of-included-taskfile', + 'optional-includes': '/docs/includes#optional-includes', + 'internal-includes': '/docs/includes#internal-includes', + 'flatten-includes': '/docs/includes#flatten-includes', + 'exclude-tasks-from-being-included': + '/docs/includes#exclude-tasks-from-being-included', + 'vars-of-included-taskfiles': '/docs/includes#vars-of-included-taskfiles', + 'namespace-aliases': '/docs/includes#namespace-aliases', + 'internal-tasks': '/docs/defining-tasks#internal-tasks', + 'task-directory': '/docs/defining-tasks#task-directory', + 'task-dependencies': '/docs/dependencies#task-dependencies', + 'fail-fast-dependencies': '/docs/dependencies#fail-fast-dependencies', + 'platform-specific-tasks-and-commands': + '/docs/platforms#platform-specific-tasks-and-commands', + 'calling-another-task': '/docs/dependencies#calling-another-task', + 'prevent-unnecessary-work': '/docs/up-to-date', + 'by-fingerprinting-locally-generated-files-and-their-sources': + '/docs/up-to-date#by-fingerprinting-locally-generated-files-and-their-sources', + 'using-programmatic-checks-to-indicate-a-task-is-up-to-date': + '/docs/up-to-date#using-programmatic-checks-to-indicate-a-task-is-up-to-date', + 'using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies': + '/docs/conditional-execution#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies', + 'conditional-execution-with-if': + '/docs/conditional-execution#conditional-execution-with-if', + 'task-level-if': '/docs/conditional-execution#task-level-if', + 'command-level-if': '/docs/conditional-execution#command-level-if', + 'using-templates-in-if-conditions': + '/docs/conditional-execution#using-templates-in-if-conditions', + 'using-if-with-for-loops': + '/docs/conditional-execution#using-if-with-for-loops', + 'if-vs-preconditions': '/docs/conditional-execution#if-vs-preconditions', + 'limiting-when-tasks-run': + '/docs/conditional-execution#limiting-when-tasks-run', + 'ensuring-required-variables-are-set': + '/docs/required-variables#ensuring-required-variables-are-set', + 'ensuring-required-variables-have-allowed-values': + '/docs/required-variables#ensuring-required-variables-have-allowed-values', + 'using-variable-references-for-enum-values': + '/docs/required-variables#using-variable-references-for-enum-values', + 'prompting-for-missing-variables-interactively': + '/docs/required-variables#prompting-for-missing-variables-interactively', + variables: '/docs/variables', + 'dynamic-variables': '/docs/variables#dynamic-variables', + 'referencing-other-variables': '/docs/variables#referencing-other-variables', + 'parsing-json-yaml-into-map-variables': + '/docs/variables#parsing-json-yaml-into-map-variables', + 'secret-variables': '/docs/variables#secret-variables', + 'looping-over-values': '/docs/loops', + 'looping-over-a-static-list': '/docs/loops#looping-over-a-static-list', + 'looping-over-a-matrix': '/docs/loops#looping-over-a-matrix', + 'looping-over-your-task-s-sources-or-generated-files': + '/docs/loops#looping-over-your-task-s-sources-or-generated-files', + 'looping-over-variables': '/docs/loops#looping-over-variables', + 'renaming-variables': '/docs/loops#renaming-variables', + 'looping-over-tasks': '/docs/loops#looping-over-tasks', + 'looping-over-dependencies': '/docs/loops#looping-over-dependencies', + 'forwarding-cli-arguments-to-commands': + '/docs/arguments#forwarding-cli-arguments-to-commands', + 'wildcard-arguments': '/docs/arguments#wildcard-arguments', + 'doing-task-cleanup-with-defer': + '/docs/dependencies#doing-task-cleanup-with-defer', + help: '/docs/defining-tasks#help', + 'display-summary-of-task': '/docs/defining-tasks#display-summary-of-task', + 'task-aliases': '/docs/defining-tasks#task-aliases', + 'overriding-task-name': '/docs/defining-tasks#overriding-task-name', + 'warning-prompts': '/docs/required-variables#warning-prompts', + 'silent-mode': '/docs/output#silent-mode', + 'dry-run-mode': '/docs/running-tasks#dry-run-mode', + 'ignore-errors': '/docs/output#ignore-errors', + 'output-syntax': '/docs/output#output-syntax', + 'ci-integration': '/docs/output#ci-integration', + 'colored-output': '/docs/output#colored-output', + 'error-annotations': '/docs/output#error-annotations', + 'interactive-cli-application': + '/docs/running-tasks#interactive-cli-application', + 'short-task-syntax': '/docs/defining-tasks#short-task-syntax', + 'set-and-shopt': '/docs/platforms#set-and-shopt', + 'watch-tasks': '/docs/watch' +}; diff --git a/website/.vitepress/theme/index.ts b/website/.vitepress/theme/index.ts index 495bf7dc67..e3509b2616 100644 --- a/website/.vitepress/theme/index.ts +++ b/website/.vitepress/theme/index.ts @@ -6,6 +6,7 @@ import AuthorCard from '../components/AuthorCard.vue'; import BlogPost from '../components/BlogPost.vue'; import Version from '../components/Version.vue'; import Adopters from '../components/Adopters.vue'; +import GuideRedirect from '../components/GuideRedirect.vue'; import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client'; import { h } from 'vue'; import 'virtual:group-icons.css'; @@ -23,6 +24,7 @@ export default { app.component('BlogPost', BlogPost); app.component('Version', Version); app.component('Adopters', Adopters); + app.component('GuideRedirect', GuideRedirect); app.component('CopyOrDownloadAsMarkdownButtons', CopyOrDownloadAsMarkdownButtons); enhanceAppWithTabs(app); } diff --git a/website/src/next/docs/guide.md b/website/src/next/docs/guide.md index f9243013d7..efa0097100 100644 --- a/website/src/next/docs/guide.md +++ b/website/src/next/docs/guide.md @@ -1,2952 +1,58 @@ --- +title: Guide description: - Guide to running Taskfiles and using Task features in real-world workflows + An index of every topic in the Task guide, from running your first task to + composing Taskfiles across repositories. outline: deep --- # Guide -## Running Taskfiles +The guide covers everything Task can do once you have written your first +Taskfile. Each page below is self-contained; start wherever your problem is. -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 +## Writing and running tasks -Task looks for files with the following names, in order of priority: +- [Running tasks](./running-tasks.md) — how Task finds a Taskfile, and how to + run one from a subdirectory, your home directory, standard input or a dry run. +- [Defining tasks](./defining-tasks.md) — syntax shortcuts, internal tasks, + aliases, the directory a task runs in, and its help text. +- [Passing arguments](./arguments.md) — forwarding command line arguments with + `--`, and matching part of a task's name with a wildcard. -- `Taskfile.yml` -- `taskfile.yml` -- `Taskfile.yaml` -- `taskfile.yaml` -- `Taskfile.dist.yml` -- `taskfile.dist.yml` -- `Taskfile.dist.yaml` -- `taskfile.dist.yaml` +## Variables and environment -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`). +- [Variables](./variables.md) — static, dynamic, map and secret variables, their + scope, and how they reference each other. +- [Environment variables](./environment.md) — setting them per task or globally, + and loading them from `.env` files. +- [Required variables and prompts](./required-variables.md) — requiring + variables, restricting them to allowed values, and prompting for them. -### Running a Taskfile from a subdirectory +## Controlling what runs -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. +- [Dependencies and task calls](./dependencies.md) — `deps`, calling a task from + `cmds`, and cleanup with `defer`. +- [Skipping work that is up to date](./up-to-date.md) — source and generated + file fingerprints, and your own `status` checks. +- [Conditional execution](./conditional-execution.md) — `preconditions`, `if`, + and the flags that limit when a task runs. +- [Loops](./loops.md) — repeating a command over a list, a matrix, a variable, + your sources, or other tasks. -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: +## Composing Taskfiles -```yaml -version: '3' +- [Including other Taskfiles](./includes.md) — namespaces, optional and internal + includes, flattening, and per-include variables. +- [Remote Taskfiles](./remote-taskfiles.md) — running and including Taskfiles + served over HTTP or Git, and the checksum rules that guard them. -tasks: - up: - dir: '{{.USER_WORKING_DIR}}' - preconditions: - - test -f docker-compose.yml - cmds: - - docker-compose up -d -``` +## Execution environment -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 +- [Output and logging](./output.md) — output modes, silent mode, ignoring + errors, and CI annotations. +- [Platform-specific behaviour](./platforms.md) — restricting tasks to an OS or + architecture, and shell options. +- [Watch mode](./watch.md) — re-running a task when its sources change. From 7e036aa8dc54a83ab9e748dbf14dda384a60e2a4 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 17:47:04 +0200 Subject: [PATCH 03/21] docs(site): add a docs landing page /docs was not a page: a Netlify rule caught it and sent visitors to /docs/guide, so the section had no entry point of its own for the nav, the sitemap or llms.txt to point at. It is now a short hub that routes by intent - install it, learn it, look something up, keep up - rather than a second copy of the sidebar. The _redirects rule stays as it is: Netlify only applies an unforced rule when no static file matches, so it goes quiet here while continuing to serve the released channel, which has no such page yet. --- website/.vitepress/config.ts | 2 +- website/.vitepress/sidebar/next.ts | 4 +++ website/src/next/docs/index.md | 45 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 website/src/next/docs/index.md diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index e9c4837525..04ff9bc499 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -381,7 +381,7 @@ export default defineConfig({ { text: 'Home', link: '/' }, { text: 'Docs', - link: '/docs/guide', + link: '/docs/', activeMatch: '^/docs' }, { text: 'Blog', link: '/blog', activeMatch: '^/blog' }, diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index f7936ed05c..fa55b07d2a 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -4,6 +4,10 @@ import type { DefaultTheme } from 'vitepress'; // cmd/release copies it over latest.ts alongside the content it describes. See // the "Documentation channels" section of website/src/next/docs/contributing.md. export const sidebar: DefaultTheme.SidebarItem[] = [ + { + text: 'Overview', + link: '/docs/' + }, { text: 'Installation', link: '/docs/installation' diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md new file mode 100644 index 0000000000..28f5ea6b7b --- /dev/null +++ b/website/src/next/docs/index.md @@ -0,0 +1,45 @@ +--- +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. +outline: deep +--- + +# Documentation + +Task is a task runner and build tool that aims to be simpler and easier to use +than [GNU Make](https://www.gnu.org/software/make/). You describe your tasks in +a YAML file called a `Taskfile`, and Task runs them. + +## New to Task + +Install the binary, then write your first Taskfile. It takes about five minutes. + +- [Installation](./installation.md) — package managers, prebuilt binaries, + building from source, and shell completions. +- [Getting Started](./getting-started.md) — your first Taskfile, run end to end. + +## Using Task + +The [Guide](./guide.md) covers everything Task can do, one topic per page: +running and defining tasks, variables, dependencies, up-to-date checks, +conditional execution, loops, includes, output modes and watch mode. + +## Looking something up + +- [Taskfile Schema](./reference/schema.md) — every key you can put in a + Taskfile. +- [CLI](./reference/cli.md) — commands, flags and exit codes. +- [Templating](./reference/templating.md) — template functions and special + variables. +- [Configuration](./reference/config.md) and + [Environment](./reference/environment.md) — settings outside the Taskfile. + +## Keeping up + +- [Changelog](./changelog.md) — what shipped, and when. +- [Experiments](./experiments/) and [Deprecations](./deprecations/) — 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. From 06dde89d968ae1d20f8959356a29659326b43851 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 17:48:07 +0200 Subject: [PATCH 04/21] docs(site): fill in missing page titles and descriptions Eight pages were missing a title, a description or both. The description feeds two things at once: the meta tag the DocSearch crawler reads, and the entry a page gets in llms.txt. Without one, a page is indexed and listed with whatever text happens to come first. Every page under docs/ now carries both. --- website/src/next/docs/experiments/remote-taskfiles.md | 1 + website/src/next/docs/experiments/template.md | 1 + website/src/next/docs/remote-taskfiles.md | 1 + website/src/next/docs/security/threat-model.md | 8 ++++---- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/website/src/next/docs/experiments/remote-taskfiles.md b/website/src/next/docs/experiments/remote-taskfiles.md index 2e83b46598..3e89cfe58a 100644 --- a/website/src/next/docs/experiments/remote-taskfiles.md +++ b/website/src/next/docs/experiments/remote-taskfiles.md @@ -1,4 +1,5 @@ --- +title: Remote Taskfiles (#1317) description: Experimentation for using Taskfiles stored in remote locations outline: deep --- diff --git a/website/src/next/docs/experiments/template.md b/website/src/next/docs/experiments/template.md index 9df41586b6..c1a56fdb76 100644 --- a/website/src/next/docs/experiments/template.md +++ b/website/src/next/docs/experiments/template.md @@ -1,5 +1,6 @@ --- title: '--- Template ---' +description: Template for documenting a new experiment. --- # \{Name of Experiment\} (#\{Issue\}) diff --git a/website/src/next/docs/remote-taskfiles.md b/website/src/next/docs/remote-taskfiles.md index 5c5335be8a..e65fc6cbba 100644 --- a/website/src/next/docs/remote-taskfiles.md +++ b/website/src/next/docs/remote-taskfiles.md @@ -1,4 +1,5 @@ --- +title: Remote Taskfiles description: Guide to loading and securely using Taskfiles from HTTP and Git sources outline: deep diff --git a/website/src/next/docs/security/threat-model.md b/website/src/next/docs/security/threat-model.md index 3c62dde084..a7a529e557 100644 --- a/website/src/next/docs/security/threat-model.md +++ b/website/src/next/docs/security/threat-model.md @@ -16,8 +16,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 @@ -78,8 +78,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 From 2dfe7826793575d6fd7f769a4be7f5865c5d8d38 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 17:49:34 +0200 Subject: [PATCH 05/21] docs(site): use relative links with extensions throughout Three conventions were in use: relative with .md, absolute without an extension, and relative without one. Only the first is resolved and verified by VitePress at build time, which makes it the only form that cannot rot silently - and with no link checker in CI, that check is the only one there is. Also fixes two links that were already wrong: remote-taskfiles.md reached for ../docs/reference from inside docs/, and the security incident response plan pointed at ../security/ from inside security/. --- website/src/next/blog/windows-core-utils.md | 2 +- website/src/next/docs/contributing.md | 12 ++++++------ website/src/next/docs/dependencies.md | 2 +- .../src/next/docs/deprecations/completion-scripts.md | 2 +- .../src/next/docs/experiments/remote-taskfiles.md | 2 +- website/src/next/docs/experiments/template.md | 2 +- website/src/next/docs/faq.md | 2 +- website/src/next/docs/getting-started.md | 6 ++++-- website/src/next/docs/index.md | 5 +++-- website/src/next/docs/loops.md | 2 +- website/src/next/docs/reference/schema.md | 2 +- website/src/next/docs/reference/templating.md | 2 +- website/src/next/docs/remote-taskfiles.md | 2 +- website/src/next/docs/required-variables.md | 2 +- .../src/next/docs/security/incident-response-plan.md | 2 +- website/src/next/docs/security/index.md | 4 ++-- website/src/next/docs/security/threat-model.md | 2 +- website/src/next/docs/up-to-date.md | 2 +- website/src/next/docs/watch.md | 4 ++-- 19 files changed, 31 insertions(+), 28 deletions(-) diff --git a/website/src/next/blog/windows-core-utils.md b/website/src/next/blog/windows-core-utils.md index 3650bb3657..945845b711 100644 --- a/website/src/next/blog/windows-core-utils.md +++ b/website/src/next/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/moreinterp/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/next/docs/contributing.md b/website/src/next/docs/contributing.md index 993f570b0e..a24c1069b0 100644 --- a/website/src/next/docs/contributing.md +++ b/website/src/next/docs/contributing.md @@ -253,9 +253,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.md diff --git a/website/src/next/docs/dependencies.md b/website/src/next/docs/dependencies.md index 997631f82a..62999284fd 100644 --- a/website/src/next/docs/dependencies.md +++ b/website/src/next/docs/dependencies.md @@ -210,7 +210,7 @@ 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 +[exit code](./reference/cli.md#exit-codes). You can check its presence to know if the task completed successfully or not: ```yaml diff --git a/website/src/next/docs/deprecations/completion-scripts.md b/website/src/next/docs/deprecations/completion-scripts.md index d1cfbbc855..55e6a74a22 100644 --- a/website/src/next/docs/deprecations/completion-scripts.md +++ b/website/src/next/docs/deprecations/completion-scripts.md @@ -21,5 +21,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/next/docs/experiments/remote-taskfiles.md b/website/src/next/docs/experiments/remote-taskfiles.md index 3e89cfe58a..6008947721 100644 --- a/website/src/next/docs/experiments/remote-taskfiles.md +++ b/website/src/next/docs/experiments/remote-taskfiles.md @@ -12,4 +12,4 @@ check out our [blog post][blog-post]. [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/next/docs/experiments/template.md b/website/src/next/docs/experiments/template.md index c1a56fdb76..6b4ccfece6 100644 --- a/website/src/next/docs/experiments/template.md +++ b/website/src/next/docs/experiments/template.md @@ -34,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/next/docs/faq.md b/website/src/next/docs/faq.md index 1efdbda771..95d6108450 100644 --- a/website/src/next/docs/faq.md +++ b/website/src/next/docs/faq.md @@ -104,7 +104,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/next/docs/getting-started.md b/website/src/next/docs/getting-started.md index e463a471b6..afd168f390 100644 --- a/website/src/next/docs/getting-started.md +++ b/website/src/next/docs/getting-started.md @@ -8,7 +8,8 @@ outline: deep 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 @@ -132,4 +133,5 @@ 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](./guide.md) next. Alternatively, you can check out our reference -docs for the [Taskfile schema](reference/schema) and [CLI](reference/cli). +docs for the [Taskfile schema](./reference/schema.md) and +[CLI](./reference/cli.md). diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md index 28f5ea6b7b..bb43c0e1e1 100644 --- a/website/src/next/docs/index.md +++ b/website/src/next/docs/index.md @@ -39,7 +39,8 @@ conditional execution, loops, includes, output modes and watch mode. ## Keeping up - [Changelog](./changelog.md) — what shipped, and when. -- [Experiments](./experiments/) and [Deprecations](./deprecations/) — what is - coming, and what is going away. +- [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. diff --git a/website/src/next/docs/loops.md b/website/src/next/docs/loops.md index ea49990a34..41ce67f8f5 100644 --- a/website/src/next/docs/loops.md +++ b/website/src/next/docs/loops.md @@ -121,7 +121,7 @@ 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 +[special variables](./reference/templating.md#special-variables) that you may find useful for this. ::: code-group diff --git a/website/src/next/docs/reference/schema.md b/website/src/next/docs/reference/schema.md index d69d261d19..dd30f3b271 100644 --- a/website/src/next/docs/reference/schema.md +++ b/website/src/next/docs/reference/schema.md @@ -984,7 +984,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/next/docs/reference/templating.md b/website/src/next/docs/reference/templating.md index 37bdbe941d..c267bc0d54 100644 --- a/website/src/next/docs/reference/templating.md +++ b/website/src/next/docs/reference/templating.md @@ -334,7 +334,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/next/docs/remote-taskfiles.md b/website/src/next/docs/remote-taskfiles.md index e65fc6cbba..92972851f9 100644 --- a/website/src/next/docs/remote-taskfiles.md +++ b/website/src/next/docs/remote-taskfiles.md @@ -176,7 +176,7 @@ includes: ## Special Variables -The file-path [special variables](../docs/reference/templating.md#file-paths) +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: diff --git a/website/src/next/docs/required-variables.md b/website/src/next/docs/required-variables.md index 1bb7d658e6..edc113403d 100644 --- a/website/src/next/docs/required-variables.md +++ b/website/src/next/docs/required-variables.md @@ -271,7 +271,7 @@ tasks: ``` Warning prompts are called before executing a task. If a prompt is denied Task -will exit with [exit code](/docs/reference/cli#exit-codes) 205. If approved, +will exit with [exit code](./reference/cli.md#exit-codes) 205. If approved, Task will continue as normal. ```shell diff --git a/website/src/next/docs/security/incident-response-plan.md b/website/src/next/docs/security/incident-response-plan.md index 816d0e1420..e64f087f89 100644 --- a/website/src/next/docs/security/incident-response-plan.md +++ b/website/src/next/docs/security/incident-response-plan.md @@ -91,4 +91,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/next/docs/security/index.md b/website/src/next/docs/security/index.md index 84583ad2e8..8ddf735df5 100644 --- a/website/src/next/docs/security/index.md +++ b/website/src/next/docs/security/index.md @@ -21,5 +21,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/next/docs/security/threat-model.md b/website/src/next/docs/security/threat-model.md index a7a529e557..86b153ef99 100644 --- a/website/src/next/docs/security/threat-model.md +++ b/website/src/next/docs/security/threat-model.md @@ -171,7 +171,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/next/docs/up-to-date.md b/website/src/next/docs/up-to-date.md index 871c5c5668..c13f052a0c 100644 --- a/website/src/next/docs/up-to-date.md +++ b/website/src/next/docs/up-to-date.md @@ -203,7 +203,7 @@ 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 +[exit code](./reference/cli.md#exit-codes) if any of the tasks are not up-to-date. `status` can be combined with the diff --git a/website/src/next/docs/watch.md b/website/src/next/docs/watch.md index aba4ba2787..814cbf9193 100644 --- a/website/src/next/docs/watch.md +++ b/website/src/next/docs/watch.md @@ -57,6 +57,6 @@ to us. ::: -[config]: /docs/reference/config +[config]: ./reference/config.md [gotemplate]: https://golang.org/pkg/text/template/ -[templating-reference]: /docs/reference/templating +[templating-reference]: ./reference/templating.md From 337aea830214ebde88fa0fc7d34afd64e555c7ce Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 17:56:39 +0200 Subject: [PATCH 06/21] docs(site): restore the link definitions the split stranded Markdown link definitions are file-scoped. The three the guide used sat at the very bottom of the file, inside the last section, so the split handed all of them to watch.md - which uses none - and left dependencies.md and variables.md rendering [`.taskrc.yml`][config] and [templates][templating-reference] as literal text. Each definition now lives on the page that uses it. [gotemplate] is dropped: nothing referenced it, in the old guide either. --- website/src/next/docs/dependencies.md | 2 ++ website/src/next/docs/variables.md | 2 ++ website/src/next/docs/watch.md | 4 ---- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/src/next/docs/dependencies.md b/website/src/next/docs/dependencies.md index 62999284fd..831d718b01 100644 --- a/website/src/next/docs/dependencies.md +++ b/website/src/next/docs/dependencies.md @@ -224,3 +224,5 @@ tasks: {{.EXIT_CODE}}!{{else}}Success!{{end}}' - exit 1 ``` + +[config]: ./reference/config.md diff --git a/website/src/next/docs/variables.md b/website/src/next/docs/variables.md index e41a9f6399..71bc8dd6ff 100644 --- a/website/src/next/docs/variables.md +++ b/website/src/next/docs/variables.md @@ -455,3 +455,5 @@ vars: ``` ::: + +[templating-reference]: ./reference/templating.md diff --git a/website/src/next/docs/watch.md b/website/src/next/docs/watch.md index 814cbf9193..106bd3f798 100644 --- a/website/src/next/docs/watch.md +++ b/website/src/next/docs/watch.md @@ -56,7 +56,3 @@ live-reloading, like [Air](https://github.com/air-verse/air/). Also, be sure to to us. ::: - -[config]: ./reference/config.md -[gotemplate]: https://golang.org/pkg/text/template/ -[templating-reference]: ./reference/templating.md From 4bb2aa4dd16a0c23d07c0f206448ad2d6c31fbb2 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 18:49:54 +0200 Subject: [PATCH 07/21] docs(site): keep the released channel out of the docs landing page The nav is shared by both channels, so pointing Docs at /docs/ sent taskfile.dev to a page that only exists on next until cmd/release promotes it. The _redirects rule that used to catch this is written /docs, without the trailing slash the nav emits, so it would not have saved the link. --- website/.vitepress/config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 04ff9bc499..89d1f12e5e 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -381,7 +381,9 @@ export default defineConfig({ { text: 'Home', link: '/' }, { text: 'Docs', - link: '/docs/', + // The landing page only exists on next until cmd/release promotes it; + // the released channel still has to enter the section at the guide. + link: isLatest ? '/docs/guide' : '/docs/', activeMatch: '^/docs' }, { text: 'Blog', link: '/blog', activeMatch: '^/blog' }, From 55aaa2be693932f54d9e90c1b1af7cea40458294 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 17:52:48 +0200 Subject: [PATCH 08/21] docs(site): group the sidebar by reader intent Chosen after building this grouping and a product-area one side by side and comparing them on the rendered site. The sidebar was a flat list of 16 entries in which contributor material sat at the same level as user material. It is now five groups named for what the reader is doing: Getting Started, Guide, Reference, Project, Contributing. The guide pages move under /docs/guide/ so the URLs say the same thing as the navigation. Only the pages created by the split are moved. Everything else keeps its URL, because src/public/_redirects is shared between the two channels and any rule added here would take effect on the released site, which still serves the old structure. The DocSearch crawler puts the active sidebar section into hierarchy.lvl0, so these five labels become the breadcrumbs on every search result. --- website/.vitepress/guideAnchors.ts | 147 ++++++------ website/.vitepress/sidebar/next.ts | 220 ++++++++++-------- website/src/next/docs/contributing.md | 2 +- website/src/next/docs/getting-started.md | 4 +- .../src/next/docs/{ => guide}/arguments.md | 0 .../docs/{ => guide}/conditional-execution.md | 0 .../next/docs/{ => guide}/defining-tasks.md | 0 .../src/next/docs/{ => guide}/dependencies.md | 4 +- .../src/next/docs/{ => guide}/environment.md | 0 website/src/next/docs/{ => guide}/includes.md | 2 +- .../next/docs/{guide.md => guide/index.md} | 2 +- website/src/next/docs/{ => guide}/loops.md | 2 +- website/src/next/docs/{ => guide}/output.md | 0 .../src/next/docs/{ => guide}/platforms.md | 0 .../docs/{ => guide}/required-variables.md | 2 +- .../next/docs/{ => guide}/running-tasks.md | 0 .../src/next/docs/{ => guide}/up-to-date.md | 2 +- .../src/next/docs/{ => guide}/variables.md | 2 +- website/src/next/docs/{ => guide}/watch.md | 0 website/src/next/docs/index.md | 2 +- website/src/next/docs/reference/schema.md | 4 +- 21 files changed, 211 insertions(+), 184 deletions(-) rename website/src/next/docs/{ => guide}/arguments.md (100%) rename website/src/next/docs/{ => guide}/conditional-execution.md (100%) rename website/src/next/docs/{ => guide}/defining-tasks.md (100%) rename website/src/next/docs/{ => guide}/dependencies.md (97%) rename website/src/next/docs/{ => guide}/environment.md (100%) rename website/src/next/docs/{ => guide}/includes.md (99%) rename website/src/next/docs/{guide.md => guide/index.md} (96%) rename website/src/next/docs/{ => guide}/loops.md (98%) rename website/src/next/docs/{ => guide}/output.md (100%) rename website/src/next/docs/{ => guide}/platforms.md (100%) rename website/src/next/docs/{ => guide}/required-variables.md (98%) rename website/src/next/docs/{ => guide}/running-tasks.md (100%) rename website/src/next/docs/{ => guide}/up-to-date.md (98%) rename website/src/next/docs/{ => guide}/variables.md (99%) rename website/src/next/docs/{ => guide}/watch.md (100%) diff --git a/website/.vitepress/guideAnchors.ts b/website/.vitepress/guideAnchors.ts index bf5b4dea6f..d5ce370995 100644 --- a/website/.vitepress/guideAnchors.ts +++ b/website/.vitepress/guideAnchors.ts @@ -2,98 +2,103 @@ // split up. Netlify never sees the URL fragment, so a _redirects rule // cannot route these; GuideRedirect.vue resolves them in the browser. export const guideAnchors: Record = { - 'running-taskfiles': '/docs/running-tasks', - 'supported-file-names': '/docs/running-tasks#supported-file-names', + 'running-taskfiles': '/docs/guide/running-tasks', + 'supported-file-names': '/docs/guide/running-tasks#supported-file-names', 'running-a-taskfile-from-a-subdirectory': - '/docs/running-tasks#running-a-taskfile-from-a-subdirectory', - 'running-a-global-taskfile': '/docs/running-tasks#running-a-global-taskfile', + '/docs/guide/running-tasks#running-a-taskfile-from-a-subdirectory', + 'running-a-global-taskfile': + '/docs/guide/running-tasks#running-a-global-taskfile', 'running-a-taskfile-from-stdin': - '/docs/running-tasks#running-a-taskfile-from-stdin', + '/docs/guide/running-tasks#running-a-taskfile-from-stdin', 'running-a-remote-taskfile': '/docs/remote-taskfiles#specifying-a-remote-entrypoint', - 'environment-variables': '/docs/environment', - task: '/docs/environment#task', - 'env-files': '/docs/environment#env-files', - 'including-other-taskfiles': '/docs/includes', - 'remote-taskfiles': '/docs/includes#remote-taskfiles', - 'os-specific-taskfiles': '/docs/includes#os-specific-taskfiles', + 'environment-variables': '/docs/guide/environment', + task: '/docs/guide/environment#task', + 'env-files': '/docs/guide/environment#env-files', + 'including-other-taskfiles': '/docs/guide/includes', + 'remote-taskfiles': '/docs/guide/includes#remote-taskfiles', + 'os-specific-taskfiles': '/docs/guide/includes#os-specific-taskfiles', 'directory-of-included-taskfile': - '/docs/includes#directory-of-included-taskfile', - 'optional-includes': '/docs/includes#optional-includes', - 'internal-includes': '/docs/includes#internal-includes', - 'flatten-includes': '/docs/includes#flatten-includes', + '/docs/guide/includes#directory-of-included-taskfile', + 'optional-includes': '/docs/guide/includes#optional-includes', + 'internal-includes': '/docs/guide/includes#internal-includes', + 'flatten-includes': '/docs/guide/includes#flatten-includes', 'exclude-tasks-from-being-included': - '/docs/includes#exclude-tasks-from-being-included', - 'vars-of-included-taskfiles': '/docs/includes#vars-of-included-taskfiles', - 'namespace-aliases': '/docs/includes#namespace-aliases', - 'internal-tasks': '/docs/defining-tasks#internal-tasks', - 'task-directory': '/docs/defining-tasks#task-directory', - 'task-dependencies': '/docs/dependencies#task-dependencies', - 'fail-fast-dependencies': '/docs/dependencies#fail-fast-dependencies', + '/docs/guide/includes#exclude-tasks-from-being-included', + 'vars-of-included-taskfiles': + '/docs/guide/includes#vars-of-included-taskfiles', + 'namespace-aliases': '/docs/guide/includes#namespace-aliases', + 'internal-tasks': '/docs/guide/defining-tasks#internal-tasks', + 'task-directory': '/docs/guide/defining-tasks#task-directory', + 'task-dependencies': '/docs/guide/dependencies#task-dependencies', + 'fail-fast-dependencies': '/docs/guide/dependencies#fail-fast-dependencies', 'platform-specific-tasks-and-commands': - '/docs/platforms#platform-specific-tasks-and-commands', - 'calling-another-task': '/docs/dependencies#calling-another-task', - 'prevent-unnecessary-work': '/docs/up-to-date', + '/docs/guide/platforms#platform-specific-tasks-and-commands', + 'calling-another-task': '/docs/guide/dependencies#calling-another-task', + 'prevent-unnecessary-work': '/docs/guide/up-to-date', 'by-fingerprinting-locally-generated-files-and-their-sources': - '/docs/up-to-date#by-fingerprinting-locally-generated-files-and-their-sources', + '/docs/guide/up-to-date#by-fingerprinting-locally-generated-files-and-their-sources', 'using-programmatic-checks-to-indicate-a-task-is-up-to-date': - '/docs/up-to-date#using-programmatic-checks-to-indicate-a-task-is-up-to-date', + '/docs/guide/up-to-date#using-programmatic-checks-to-indicate-a-task-is-up-to-date', 'using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies': - '/docs/conditional-execution#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies', + '/docs/guide/conditional-execution#using-programmatic-checks-to-cancel-the-execution-of-a-task-and-its-dependencies', 'conditional-execution-with-if': - '/docs/conditional-execution#conditional-execution-with-if', - 'task-level-if': '/docs/conditional-execution#task-level-if', - 'command-level-if': '/docs/conditional-execution#command-level-if', + '/docs/guide/conditional-execution#conditional-execution-with-if', + 'task-level-if': '/docs/guide/conditional-execution#task-level-if', + 'command-level-if': '/docs/guide/conditional-execution#command-level-if', 'using-templates-in-if-conditions': - '/docs/conditional-execution#using-templates-in-if-conditions', + '/docs/guide/conditional-execution#using-templates-in-if-conditions', 'using-if-with-for-loops': - '/docs/conditional-execution#using-if-with-for-loops', - 'if-vs-preconditions': '/docs/conditional-execution#if-vs-preconditions', + '/docs/guide/conditional-execution#using-if-with-for-loops', + 'if-vs-preconditions': + '/docs/guide/conditional-execution#if-vs-preconditions', 'limiting-when-tasks-run': - '/docs/conditional-execution#limiting-when-tasks-run', + '/docs/guide/conditional-execution#limiting-when-tasks-run', 'ensuring-required-variables-are-set': - '/docs/required-variables#ensuring-required-variables-are-set', + '/docs/guide/required-variables#ensuring-required-variables-are-set', 'ensuring-required-variables-have-allowed-values': - '/docs/required-variables#ensuring-required-variables-have-allowed-values', + '/docs/guide/required-variables#ensuring-required-variables-have-allowed-values', 'using-variable-references-for-enum-values': - '/docs/required-variables#using-variable-references-for-enum-values', + '/docs/guide/required-variables#using-variable-references-for-enum-values', 'prompting-for-missing-variables-interactively': - '/docs/required-variables#prompting-for-missing-variables-interactively', - variables: '/docs/variables', - 'dynamic-variables': '/docs/variables#dynamic-variables', - 'referencing-other-variables': '/docs/variables#referencing-other-variables', + '/docs/guide/required-variables#prompting-for-missing-variables-interactively', + variables: '/docs/guide/variables', + 'dynamic-variables': '/docs/guide/variables#dynamic-variables', + 'referencing-other-variables': + '/docs/guide/variables#referencing-other-variables', 'parsing-json-yaml-into-map-variables': - '/docs/variables#parsing-json-yaml-into-map-variables', - 'secret-variables': '/docs/variables#secret-variables', - 'looping-over-values': '/docs/loops', - 'looping-over-a-static-list': '/docs/loops#looping-over-a-static-list', - 'looping-over-a-matrix': '/docs/loops#looping-over-a-matrix', + '/docs/guide/variables#parsing-json-yaml-into-map-variables', + 'secret-variables': '/docs/guide/variables#secret-variables', + 'looping-over-values': '/docs/guide/loops', + 'looping-over-a-static-list': '/docs/guide/loops#looping-over-a-static-list', + 'looping-over-a-matrix': '/docs/guide/loops#looping-over-a-matrix', 'looping-over-your-task-s-sources-or-generated-files': - '/docs/loops#looping-over-your-task-s-sources-or-generated-files', - 'looping-over-variables': '/docs/loops#looping-over-variables', - 'renaming-variables': '/docs/loops#renaming-variables', - 'looping-over-tasks': '/docs/loops#looping-over-tasks', - 'looping-over-dependencies': '/docs/loops#looping-over-dependencies', + '/docs/guide/loops#looping-over-your-task-s-sources-or-generated-files', + 'looping-over-variables': '/docs/guide/loops#looping-over-variables', + 'renaming-variables': '/docs/guide/loops#renaming-variables', + 'looping-over-tasks': '/docs/guide/loops#looping-over-tasks', + 'looping-over-dependencies': '/docs/guide/loops#looping-over-dependencies', 'forwarding-cli-arguments-to-commands': - '/docs/arguments#forwarding-cli-arguments-to-commands', - 'wildcard-arguments': '/docs/arguments#wildcard-arguments', + '/docs/guide/arguments#forwarding-cli-arguments-to-commands', + 'wildcard-arguments': '/docs/guide/arguments#wildcard-arguments', 'doing-task-cleanup-with-defer': - '/docs/dependencies#doing-task-cleanup-with-defer', - help: '/docs/defining-tasks#help', - 'display-summary-of-task': '/docs/defining-tasks#display-summary-of-task', - 'task-aliases': '/docs/defining-tasks#task-aliases', - 'overriding-task-name': '/docs/defining-tasks#overriding-task-name', - 'warning-prompts': '/docs/required-variables#warning-prompts', - 'silent-mode': '/docs/output#silent-mode', - 'dry-run-mode': '/docs/running-tasks#dry-run-mode', - 'ignore-errors': '/docs/output#ignore-errors', - 'output-syntax': '/docs/output#output-syntax', - 'ci-integration': '/docs/output#ci-integration', - 'colored-output': '/docs/output#colored-output', - 'error-annotations': '/docs/output#error-annotations', + '/docs/guide/dependencies#doing-task-cleanup-with-defer', + help: '/docs/guide/defining-tasks#help', + 'display-summary-of-task': + '/docs/guide/defining-tasks#display-summary-of-task', + 'task-aliases': '/docs/guide/defining-tasks#task-aliases', + 'overriding-task-name': '/docs/guide/defining-tasks#overriding-task-name', + 'warning-prompts': '/docs/guide/required-variables#warning-prompts', + 'silent-mode': '/docs/guide/output#silent-mode', + 'dry-run-mode': '/docs/guide/running-tasks#dry-run-mode', + 'ignore-errors': '/docs/guide/output#ignore-errors', + 'output-syntax': '/docs/guide/output#output-syntax', + 'ci-integration': '/docs/guide/output#ci-integration', + 'colored-output': '/docs/guide/output#colored-output', + 'error-annotations': '/docs/guide/output#error-annotations', 'interactive-cli-application': - '/docs/running-tasks#interactive-cli-application', - 'short-task-syntax': '/docs/defining-tasks#short-task-syntax', - 'set-and-shopt': '/docs/platforms#set-and-shopt', - 'watch-tasks': '/docs/watch' + '/docs/guide/running-tasks#interactive-cli-application', + 'short-task-syntax': '/docs/guide/defining-tasks#short-task-syntax', + 'set-and-shopt': '/docs/guide/platforms#set-and-shopt', + 'watch-tasks': '/docs/guide/watch' }; diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index fa55b07d2a..fc7bc1b73a 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -3,101 +3,107 @@ 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: 'Overview', link: '/docs/' }, - { - text: 'Installation', - link: '/docs/installation' - }, { 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', + link: '/docs/guide/', items: [ { text: 'Running tasks', - link: '/docs/running-tasks' + link: '/docs/guide/running-tasks' }, { text: 'Defining tasks', - link: '/docs/defining-tasks' + link: '/docs/guide/defining-tasks' }, { text: 'Passing arguments', - link: '/docs/arguments' + link: '/docs/guide/arguments' }, { text: 'Variables', - link: '/docs/variables' + link: '/docs/guide/variables' }, { text: 'Environment variables', - link: '/docs/environment' + link: '/docs/guide/environment' }, { text: 'Required variables and prompts', - link: '/docs/required-variables' + link: '/docs/guide/required-variables' }, { text: 'Dependencies and task calls', - link: '/docs/dependencies' + link: '/docs/guide/dependencies' }, { text: 'Skipping work that is up to date', - link: '/docs/up-to-date' + link: '/docs/guide/up-to-date' }, { text: 'Conditional execution', - link: '/docs/conditional-execution' + link: '/docs/guide/conditional-execution' }, { text: 'Loops', - link: '/docs/loops' + link: '/docs/guide/loops' }, { text: 'Including other Taskfiles', - link: '/docs/includes' + link: '/docs/guide/includes' + }, + { + text: 'Remote Taskfiles', + link: '/docs/remote-taskfiles' }, { text: 'Output and logging', - link: '/docs/output' + link: '/docs/guide/output' }, { text: 'Platform-specific behaviour', - link: '/docs/platforms' + link: '/docs/guide/platforms' }, { text: 'Watch mode', - link: '/docs/watch' + link: '/docs/guide/watch' } ] }, - { - 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' @@ -107,94 +113,110 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ link: '/docs/reference/templating' }, { - text: 'Package API', - link: '/docs/reference/package' - } - ] - }, - { - text: 'Experiments', - collapsed: true, - link: '/docs/experiments/', - items: [ - { - text: 'Env Precedence (#1038)', - link: '/docs/experiments/env-precedence' + text: 'Environment', + link: '/docs/reference/environment' }, { - text: 'Gentle Force (#1200)', - link: '/docs/experiments/gentle-force' + text: 'Configuration', + link: '/docs/reference/config' }, { - text: 'Remote Taskfiles (#1317)', - link: '/docs/experiments/remote-taskfiles' + text: 'Package API', + link: '/docs/reference/package' } ] }, { - text: 'Deprecations', + text: 'Project', 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: 'Changelog', + link: '/docs/changelog' + }, + { + text: 'FAQ', + link: '/docs/faq' + }, + { + 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: '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: 'Style Guide', + link: '/docs/styleguide' }, { - text: 'Threat Model', - link: '/docs/security/threat-model' + text: 'Releasing', + link: '/docs/releasing' } ] - }, - { - text: 'Changelog', - link: '/docs/changelog' - }, - { - text: 'FAQ', - link: '/docs/faq' } ]; diff --git a/website/src/next/docs/contributing.md b/website/src/next/docs/contributing.md index a24c1069b0..b2c71bd0b0 100644 --- a/website/src/next/docs/contributing.md +++ b/website/src/next/docs/contributing.md @@ -258,4 +258,4 @@ If you have questions, feel free to ask them in the `#help` forum channel on our [styleguide]: ./styleguide.md [cli-reference]: ./reference/cli.md [schema-reference]: ./reference/schema.md -[usage-guide]: ./guide.md +[usage-guide]: ./guide/index.md diff --git a/website/src/next/docs/getting-started.md b/website/src/next/docs/getting-started.md index afd168f390..32b8be9220 100644 --- a/website/src/next/docs/getting-started.md +++ b/website/src/next/docs/getting-started.md @@ -73,7 +73,7 @@ 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](./running-tasks.md#supported-file-names)) in the current +[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. @@ -132,6 +132,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](./guide.md) next. Alternatively, you can check out our reference +[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/next/docs/arguments.md b/website/src/next/docs/guide/arguments.md similarity index 100% rename from website/src/next/docs/arguments.md rename to website/src/next/docs/guide/arguments.md diff --git a/website/src/next/docs/conditional-execution.md b/website/src/next/docs/guide/conditional-execution.md similarity index 100% rename from website/src/next/docs/conditional-execution.md rename to website/src/next/docs/guide/conditional-execution.md diff --git a/website/src/next/docs/defining-tasks.md b/website/src/next/docs/guide/defining-tasks.md similarity index 100% rename from website/src/next/docs/defining-tasks.md rename to website/src/next/docs/guide/defining-tasks.md diff --git a/website/src/next/docs/dependencies.md b/website/src/next/docs/guide/dependencies.md similarity index 97% rename from website/src/next/docs/dependencies.md rename to website/src/next/docs/guide/dependencies.md index 831d718b01..ed6d147644 100644 --- a/website/src/next/docs/dependencies.md +++ b/website/src/next/docs/guide/dependencies.md @@ -210,7 +210,7 @@ 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](./reference/cli.md#exit-codes). You can check its presence to know +[exit code](../reference/cli.md#exit-codes). You can check its presence to know if the task completed successfully or not: ```yaml @@ -225,4 +225,4 @@ tasks: - exit 1 ``` -[config]: ./reference/config.md +[config]: ../reference/config.md diff --git a/website/src/next/docs/environment.md b/website/src/next/docs/guide/environment.md similarity index 100% rename from website/src/next/docs/environment.md rename to website/src/next/docs/guide/environment.md diff --git a/website/src/next/docs/includes.md b/website/src/next/docs/guide/includes.md similarity index 99% rename from website/src/next/docs/includes.md rename to website/src/next/docs/guide/includes.md index 46a74877db..77aeb3486e 100644 --- a/website/src/next/docs/includes.md +++ b/website/src/next/docs/guide/includes.md @@ -38,7 +38,7 @@ 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). +[remote Taskfiles documentation](../remote-taskfiles.md). ```yaml version: '3' diff --git a/website/src/next/docs/guide.md b/website/src/next/docs/guide/index.md similarity index 96% rename from website/src/next/docs/guide.md rename to website/src/next/docs/guide/index.md index efa0097100..af71eb369d 100644 --- a/website/src/next/docs/guide.md +++ b/website/src/next/docs/guide/index.md @@ -46,7 +46,7 @@ Taskfile. Each page below is self-contained; start wherever your problem is. - [Including other Taskfiles](./includes.md) — namespaces, optional and internal includes, flattening, and per-include variables. -- [Remote Taskfiles](./remote-taskfiles.md) — running and including Taskfiles +- [Remote Taskfiles](../remote-taskfiles.md) — running and including Taskfiles served over HTTP or Git, and the checksum rules that guard them. ## Execution environment diff --git a/website/src/next/docs/loops.md b/website/src/next/docs/guide/loops.md similarity index 98% rename from website/src/next/docs/loops.md rename to website/src/next/docs/guide/loops.md index 41ce67f8f5..2947ffffef 100644 --- a/website/src/next/docs/loops.md +++ b/website/src/next/docs/guide/loops.md @@ -121,7 +121,7 @@ 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](./reference/templating.md#special-variables) that you may +[special variables](../reference/templating.md#special-variables) that you may find useful for this. ::: code-group diff --git a/website/src/next/docs/output.md b/website/src/next/docs/guide/output.md similarity index 100% rename from website/src/next/docs/output.md rename to website/src/next/docs/guide/output.md diff --git a/website/src/next/docs/platforms.md b/website/src/next/docs/guide/platforms.md similarity index 100% rename from website/src/next/docs/platforms.md rename to website/src/next/docs/guide/platforms.md diff --git a/website/src/next/docs/required-variables.md b/website/src/next/docs/guide/required-variables.md similarity index 98% rename from website/src/next/docs/required-variables.md rename to website/src/next/docs/guide/required-variables.md index edc113403d..30543ce5a7 100644 --- a/website/src/next/docs/required-variables.md +++ b/website/src/next/docs/guide/required-variables.md @@ -271,7 +271,7 @@ tasks: ``` Warning prompts are called before executing a task. If a prompt is denied Task -will exit with [exit code](./reference/cli.md#exit-codes) 205. If approved, +will exit with [exit code](../reference/cli.md#exit-codes) 205. If approved, Task will continue as normal. ```shell diff --git a/website/src/next/docs/running-tasks.md b/website/src/next/docs/guide/running-tasks.md similarity index 100% rename from website/src/next/docs/running-tasks.md rename to website/src/next/docs/guide/running-tasks.md diff --git a/website/src/next/docs/up-to-date.md b/website/src/next/docs/guide/up-to-date.md similarity index 98% rename from website/src/next/docs/up-to-date.md rename to website/src/next/docs/guide/up-to-date.md index c13f052a0c..2a25859aa7 100644 --- a/website/src/next/docs/up-to-date.md +++ b/website/src/next/docs/guide/up-to-date.md @@ -203,7 +203,7 @@ 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](./reference/cli.md#exit-codes) if any of the tasks are not +[exit code](../reference/cli.md#exit-codes) if any of the tasks are not up-to-date. `status` can be combined with the diff --git a/website/src/next/docs/variables.md b/website/src/next/docs/guide/variables.md similarity index 99% rename from website/src/next/docs/variables.md rename to website/src/next/docs/guide/variables.md index 71bc8dd6ff..df6665989b 100644 --- a/website/src/next/docs/variables.md +++ b/website/src/next/docs/guide/variables.md @@ -456,4 +456,4 @@ vars: ::: -[templating-reference]: ./reference/templating.md +[templating-reference]: ../reference/templating.md diff --git a/website/src/next/docs/watch.md b/website/src/next/docs/guide/watch.md similarity index 100% rename from website/src/next/docs/watch.md rename to website/src/next/docs/guide/watch.md diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md index bb43c0e1e1..eb91dce623 100644 --- a/website/src/next/docs/index.md +++ b/website/src/next/docs/index.md @@ -22,7 +22,7 @@ Install the binary, then write your first Taskfile. It takes about five minutes. ## Using Task -The [Guide](./guide.md) covers everything Task can do, one topic per page: +The [Guide](./guide/index.md) covers everything Task can do, one topic per page: running and defining tasks, variables, dependencies, up-to-date checks, conditional execution, loops, includes, output modes and watch mode. diff --git a/website/src/next/docs/reference/schema.md b/website/src/next/docs/reference/schema.md index dd30f3b271..9259371397 100644 --- a/website/src/next/docs/reference/schema.md +++ b/website/src/next/docs/reference/schema.md @@ -420,7 +420,7 @@ value. For complete documentation on secret variables, including security considerations and best practices, see the -[Secret variables](../variables.md#secret-variables) section in the Guide. +[Secret variables](../guide/variables.md#secret-variables) section in the Guide. ::: @@ -787,7 +787,7 @@ tasks: ``` See -[Prompting for missing variables interactively](../required-variables.md#prompting-for-missing-variables-interactively) +[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` From 498d7b188114835de2e7a8b059b7dad45f305976 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:12:00 +0200 Subject: [PATCH 09/21] docs(site): explain variable resolution order The guide says how to declare each kind of variable but never says which one wins, and that is what people file issues about: seven of them are about precedence or evaluation order, one titled "Documentation: Clarify dotenv file precedence when multiple files are specified". The page states the order once, and guide/variables.md now links to it instead of carrying its own list. Two owners of the same rules would drift, and nothing in CI compares the docs to the Go code. Every claim was checked by running the built binary, not read off the source. Three are worth calling out because they contradict what people expect: - A task's own vars cannot be overridden from the command line; `task greet NAME=x` loses to a `vars:` on the task. - `vars:` on an `includes:` entry are defaults, not overrides: the included Taskfile's own `vars:` are applied after them and win. - Global variable names are shared across every Taskfile in a run, so a name declared in both the entrypoint and an included file resolves to the included one, even for entrypoint tasks. --- website/.vitepress/sidebar/next.ts | 10 ++ .../next/docs/concepts/variable-resolution.md | 131 ++++++++++++++++++ website/src/next/docs/guide/variables.md | 20 +-- 3 files changed, 147 insertions(+), 14 deletions(-) create mode 100644 website/src/next/docs/concepts/variable-resolution.md diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index fc7bc1b73a..aa36093c4e 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -96,6 +96,16 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ } ] }, + { + text: 'Concepts', + collapsed: true, + items: [ + { + text: 'Variable resolution', + link: '/docs/concepts/variable-resolution' + } + ] + }, { text: 'Reference', collapsed: false, diff --git a/website/src/next/docs/concepts/variable-resolution.md b/website/src/next/docs/concepts/variable-resolution.md new file mode 100644 index 0000000000..61a4fa65b0 --- /dev/null +++ b/website/src/next/docs/concepts/variable-resolution.md @@ -0,0 +1,131 @@ +--- +title: Variable resolution +description: + The single order Task uses to resolve a variable, and the consequences that + surprise people most often. +outline: deep +--- + +# Variable resolution + +Task builds one flat set of variables for each task, just before running it. +Every source is applied to that set in a fixed order, and each one overwrites +what came before. There is no per-source scoping and no lookup chain at render +time: by the time a template runs, a name has exactly one value. + +Understanding that single order explains almost every surprise on this page. + +## The 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 | + +## What this means in practice + +### 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 — 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 +``` + +### Variables on an `includes:` entry are defaults, not overrides + +Step 6 comes after step 5, so the included Taskfile's own `vars:` win over the +values supplied where it is included. Passing `vars:` on an `includes:` entry +only takes effect for names the included Taskfile does not define itself. + +If you are writing a Taskfile meant to be included and configured, leave the +configurable names out of `vars:` and give the default at the point of use +instead: + +```yaml +version: '3' + +tasks: + build: + cmds: + - echo "building {{.DOCKER_IMAGE | default "app"}}" +``` + +Declaring `DOCKER_IMAGE` in that file's `vars:` would make every include site +that sets it silently get the declared value instead. + +### 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. + +### `env:` and `vars:` are not the same thing + +Both end up in the same set, so `{{.FOO}}` finds a name set +by `env:`. The difference is on the way out: only `env:` entries are exported to +the environment of the commands Task runs. A `vars:` entry exists for templates +only, and `$FOO` in a command will not see it. + +## When values are computed + +Dynamic variables (`sh:`) are executed while the set is being built, in the +order above. A `sh:` command can therefore only reference variables from an +earlier step, never a later one. + +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, a map — use `ref:` +instead of `{{ }}`. A template renders a string; `ref:` +preserves the type. + +## Related + +- [Variables](../guide/variables.md) — how to declare each kind. +- [Environment variables](../guide/environment.md) — `env:` and `.env` files. +- [Including other Taskfiles](../guide/includes.md) — namespaces and includes. +- [Taskfile Schema](../reference/schema.md) — every key, with its type. diff --git a/website/src/next/docs/guide/variables.md b/website/src/next/docs/guide/variables.md index df6665989b..61b6fe5f88 100644 --- a/website/src/next/docs/guide/variables.md +++ b/website/src/next/docs/guide/variables.md @@ -48,20 +48,12 @@ tasks: - '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](./dependencies.md#calling-another-task)) -- Variables of the [included Taskfile](./includes.md) (when the task is - included) -- Variables of the - [inclusion of the Taskfile](./includes.md#vars-of-included-taskfiles) (when - the task is included) -- Global variables (those declared in the `vars:` option in the Taskfile) -- Environment variables +Variables can be set in many places in a Taskfile, and when the same name is set +twice, one of them wins. The order is the same everywhere and it is described +once, in [Variable resolution](../concepts/variable-resolution.md#the-order) — +including the two cases that surprise people most: a task's own `vars:` cannot +be overridden from the command line, and `vars:` given on an `includes:` entry +act as defaults rather than overrides. Example of sending parameters with environment variables: From e2162ee8ab172e28d0030aae28ff46b6530abf33 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:12:16 +0200 Subject: [PATCH 10/21] docs(site): explain dependencies and concurrency Three issues ask about execution order (`the order of task under deps is random`, `Glob-based matching and sequential or parallel execution`, `Default concurrency`), and two of the four FAQ entries are really questions about the execution model rather than about a procedure. The guide is organised one feature per page, so nothing owns the part that cuts across them: what runs together, what waits, and in which order cleanup happens. Behaviour verified by running the built binary: deps start together and all finish before cmds; a task reference inside cmds runs at its position; `run: once` collapses a shared dependency from two executions to one; deferred commands run in reverse order of declaration. --- website/.vitepress/sidebar/next.ts | 4 + .../concepts/dependencies-and-concurrency.md | 123 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 website/src/next/docs/concepts/dependencies-and-concurrency.md diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index aa36093c4e..68df219ad4 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -103,6 +103,10 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ { text: 'Variable resolution', link: '/docs/concepts/variable-resolution' + }, + { + text: 'Dependencies and concurrency', + link: '/docs/concepts/dependencies-and-concurrency' } ] }, diff --git a/website/src/next/docs/concepts/dependencies-and-concurrency.md b/website/src/next/docs/concepts/dependencies-and-concurrency.md new file mode 100644 index 0000000000..37e69dc1fc --- /dev/null +++ b/website/src/next/docs/concepts/dependencies-and-concurrency.md @@ -0,0 +1,123 @@ +--- +title: Dependencies and concurrency +description: + What runs in parallel, what runs in order, and why the output of a Taskfile is + not always in the order you wrote it. +outline: deep +--- + +# Dependencies and concurrency + +A task can pull in other tasks two ways, and they behave differently. Choosing +the wrong one is the most common cause of a Taskfile that works on one machine +and not another. + +## `deps` run together, `cmds` run in order + +Everything in `deps` starts at once. Task waits for all of them to finish, then +runs `cmds`: + +```yaml +version: '3' + +tasks: + build: + deps: [compile, generate-assets] + cmds: + - echo "packaging" +``` + +`compile` and `generate-assets` run concurrently in an unspecified order, and +`packaging` is printed only once both have finished. Nothing orders the +dependencies relative to each other — if `generate-assets` needs `compile` to +have run, it must say so itself, with its own `deps`. + +A task reference inside `cmds` is different: it runs at its position in the +list, and the next command waits for it. + +```yaml +version: '3' + +tasks: + release: + cmds: + - task: build + - task: publish +``` + +Here `build` finishes before `publish` starts. + +**The rule of thumb:** `deps` expresses "these must have happened", `cmds` +expresses "do this, then this". If order matters, it belongs in `cmds`. + +## Interleaved output is expected + +Because dependencies run concurrently, their output arrives interleaved and in a +different order between runs. That is not a bug, and it is why the default +output mode can look scrambled on a parallel build. + +Set `output: prefixed` to label each line with the task it came from, or +`output: group` to hold each task's output and print it in one block when it +finishes. See [Output and logging](../guide/output.md). + +## Limiting how much runs at once + +`--concurrency` / `-C` caps how many tasks run simultaneously. The default is +`0`, meaning no limit. It is the setting to reach for when parallel tasks +compete for the same resource — a database, a port, the network. + +## When one dependency fails + +By default Task waits for the other dependencies to finish before reporting the +failure. `--failfast` / `-F` stops everything as soon as one of them fails. + +## Running a task only once + +A task marked `run: once` executes a single time per invocation of `task`, no +matter how many other tasks depend on it: + +```yaml +version: '3' + +tasks: + setup: + run: once + cmds: + - echo "setting up" + + test: + deps: [setup] + lint: + deps: [setup] + + check: + deps: [test, lint] +``` + +`task check` prints `setting up` once, not twice. Without `run: once`, a shared +dependency runs for each dependent that asks for it. + +## Cleanup runs in reverse + +`defer` schedules a command to run when the task ends, whether it succeeded or +failed. Deferred commands run in reverse order of declaration, so the first +thing you set up is the last thing torn down: + +```yaml +version: '3' + +tasks: + deploy: + cmds: + - defer: echo "stop the tunnel" + - defer: echo "remove the temp dir" + - echo "deploying" +``` + +That prints `deploying`, then `remove the temp dir`, then `stop the tunnel`. + +## Related + +- [Dependencies and task calls](../guide/dependencies.md) — the syntax for each. +- [Output and logging](../guide/output.md) — output modes for parallel runs. +- [CLI](../reference/cli.md) — `--concurrency`, `--failfast`. From a7b8683f2d65c4b6095b4de2712ba903532cf748 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:15:38 +0200 Subject: [PATCH 11/21] fix(site): stop the llms plugin from flattening output paths vitepress-plugin-llms names its Markdown output by running the file through VitePress's own `rewrites`. On the object form it matches `/:path*`, gets `:path*` back as an array of segments, and compiles it without separators - so every page landed at the root as dist/docsreferencecli.md instead of dist/docs/reference/cli.md, and the relative links inside them pointed nowhere. Expressing the same rewrite as a function takes the plugin's other code path and keeps the segments. The Markdown mirror is now addressable by appending .md to a page's URL, which is what /llms.txt claims. It also fixes the table of contents as a side effect: with paths that match the sidebar again, llms.txt groups pages under their section instead of listing all of them under a single "Other". --- website/.vitepress/config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 89d1f12e5e..00acedf1c5 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -297,6 +297,11 @@ export default defineConfig({ srcDir: 'src', cleanUrls: true, srcExclude: [`${other}/**`, `${channel}/docs/**/template.md`], + // A function rather than the equivalent `{ '/:path*': ':path*' }`. + // vitepress-plugin-llms reuses this config to name its Markdown output, and + // on the object form it compiles the `:path*` array parameter back without + // separators, producing dist/docsreferencecli.md instead of + // dist/docs/reference/cli.md and breaking every relative link in them. rewrites: (id) => id.startsWith(`${channel}/`) ? id.slice(channel.length + 1) : id, markdown: { From fdbd089164ba2bf71708b3731fe15b7206822673 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:19:31 +0200 Subject: [PATCH 12/21] docs(site): add an entry point for coding agents /agents is a compact map of the documentation plus the ten semantics an agent is most likely to get wrong when writing a Taskfile: vars against env, what deps guarantee, that each command gets its own shell, status against preconditions, and the reverse order of defer. Each claim was checked by running the built binary. Two of them are counterintuitive enough to be worth stating outright - a task's own vars cannot be overridden from the command line, and vars on an includes entry are defaults rather than overrides. Links are relative so VitePress checks them at build; they resolve the same way for an agent reading the raw /agents.md. --- website/src/next/agents.md | 66 ++++++++++++++++++++++++++++++++++ website/src/next/docs/index.md | 7 ++++ 2 files changed, 73 insertions(+) create mode 100644 website/src/next/agents.md diff --git a/website/src/next/agents.md b/website/src/next/agents.md new file mode 100644 index 0000000000..0be6a76ce7 --- /dev/null +++ b/website/src/next/agents.md @@ -0,0 +1,66 @@ +--- +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 + +- [Getting Started](./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/) — one page per topic, for how to do a thing. +- [Variable resolution](./docs/concepts/variable-resolution.md) and + [Dependencies and concurrency](./docs/concepts/dependencies-and-concurrency.md) + — for when the behaviour matters more than the procedure. + +## Semantics that are easy to get wrong + +1. `vars` are template values. `env` values are template values **and** are + exported to the commands Task runs. `$FOO` in a command does not see a `vars` + entry. +2. A task's own `vars:` cannot be overridden from the command line. Put the + default in global `vars:` if the caller needs to supply a value. +3. `vars:` given on an `includes:` entry are defaults, not overrides — the + included Taskfile's own `vars:` are applied after them and win. +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`, 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 `env:` or a secret manager, and mark + them `secret: true` so they are masked in logs. +- Give tasks a `desc:` so they show up in `task --list`, and validate inputs + with `requires:` or `preconditions:`. diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md index eb91dce623..5d1ea77ec4 100644 --- a/website/src/next/docs/index.md +++ b/website/src/next/docs/index.md @@ -44,3 +44,10 @@ conditional execution, loops, includes, output modes and watch mode. 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). From 82df461460877fc40ea6611f24bddaa9b0e7b0d7 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:25:33 +0200 Subject: [PATCH 13/21] feat(site): emit section and type metadata for search The DocSearch crawler builds hierarchy.lvl0 - the breadcrumb shown on every search result - from whichever sidebar link is active in the DOM. That reads the navigation through the theme's markup, so it breaks quietly on a theme upgrade and cannot be reviewed from this repo, where the crawler configuration does not live. Each page now states its own section and documentary type, and the crawler can be pointed at meta[name="docsearch:section"] instead. The frontmatter is derived from sidebar/next.ts rather than written by hand, since the sidebar is what defines a section; the two cannot drift. 46 pages carry it. The only pages left without one are the two authoring templates, which are already kept out of llms.txt and the sitemap. --- website/.vitepress/config.ts | 17 +++++++++++++++++ website/src/next/docs/changelog.md | 2 ++ website/src/next/docs/community.md | 2 ++ .../concepts/dependencies-and-concurrency.md | 2 ++ .../next/docs/concepts/variable-resolution.md | 2 ++ website/src/next/docs/contributing.md | 2 ++ .../docs/deprecations/completion-scripts.md | 2 ++ website/src/next/docs/deprecations/index.md | 2 ++ .../docs/deprecations/template-functions.md | 2 ++ .../next/docs/deprecations/version-2-schema.md | 2 ++ .../src/next/docs/experiments/env-precedence.md | 2 ++ .../src/next/docs/experiments/gentle-force.md | 2 ++ website/src/next/docs/experiments/index.md | 2 ++ .../next/docs/experiments/remote-taskfiles.md | 2 ++ website/src/next/docs/faq.md | 2 ++ website/src/next/docs/getting-started.md | 2 ++ website/src/next/docs/guide/arguments.md | 2 ++ .../next/docs/guide/conditional-execution.md | 2 ++ website/src/next/docs/guide/defining-tasks.md | 2 ++ website/src/next/docs/guide/dependencies.md | 2 ++ website/src/next/docs/guide/environment.md | 2 ++ website/src/next/docs/guide/includes.md | 2 ++ website/src/next/docs/guide/index.md | 2 ++ website/src/next/docs/guide/loops.md | 2 ++ website/src/next/docs/guide/output.md | 2 ++ website/src/next/docs/guide/platforms.md | 2 ++ .../src/next/docs/guide/required-variables.md | 2 ++ website/src/next/docs/guide/running-tasks.md | 2 ++ website/src/next/docs/guide/up-to-date.md | 2 ++ website/src/next/docs/guide/variables.md | 2 ++ website/src/next/docs/guide/watch.md | 2 ++ website/src/next/docs/index.md | 2 ++ website/src/next/docs/installation.md | 2 ++ website/src/next/docs/integrations.md | 2 ++ website/src/next/docs/reference/cli.md | 2 ++ website/src/next/docs/reference/config.md | 2 ++ website/src/next/docs/reference/environment.md | 2 ++ website/src/next/docs/reference/package.md | 2 ++ website/src/next/docs/reference/schema.md | 2 ++ website/src/next/docs/reference/templating.md | 2 ++ website/src/next/docs/releasing.md | 2 ++ website/src/next/docs/remote-taskfiles.md | 2 ++ .../docs/security/incident-response-plan.md | 2 ++ website/src/next/docs/security/index.md | 2 ++ website/src/next/docs/security/threat-model.md | 2 ++ website/src/next/docs/styleguide.md | 2 ++ website/src/next/docs/taskfile-versions.md | 2 ++ 47 files changed, 109 insertions(+) diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 00acedf1c5..ddae200d29 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -144,6 +144,23 @@ export default defineConfig({ ).href; head.push(['link', { rel: 'canonical', href: canonicalUrl }]); + // The DocSearch crawler otherwise has to infer a record's section from the + // active sidebar link in the DOM. Stating it on the page is steadier: it + // survives a theme upgrade, and it is what hierarchy.lvl0 - the breadcrumb + // on every search result - should be set from. + if (pageData.frontmatter.section) { + head.push([ + 'meta', + { name: 'docsearch:section', content: pageData.frontmatter.section } + ]) + } + if (pageData.frontmatter.docType) { + head.push([ + 'meta', + { name: 'docsearch:type', content: pageData.frontmatter.docType } + ]) + } + // Dynamic Open Graph and Twitter meta tags const isHome = new URL(canonicalUrl).pathname === '/'; let pageTitle = pageData.frontmatter.title || pageData.title || taskName; diff --git a/website/src/next/docs/changelog.md b/website/src/next/docs/changelog.md index 5f9d3e0ccf..edbd3cda61 100644 --- a/website/src/next/docs/changelog.md +++ b/website/src/next/docs/changelog.md @@ -3,6 +3,8 @@ title: Changelog description: Release history for Task, including new features, improvements, fixes, and breaking changes +section: Project +docType: project outline: deep editLink: false --- diff --git a/website/src/next/docs/community.md b/website/src/next/docs/community.md index 53beb7f20c..807608cc9b 100644 --- a/website/src/next/docs/community.md +++ b/website/src/next/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/next/docs/concepts/dependencies-and-concurrency.md b/website/src/next/docs/concepts/dependencies-and-concurrency.md index 37e69dc1fc..b4135c4572 100644 --- a/website/src/next/docs/concepts/dependencies-and-concurrency.md +++ b/website/src/next/docs/concepts/dependencies-and-concurrency.md @@ -3,6 +3,8 @@ title: Dependencies and concurrency description: What runs in parallel, what runs in order, and why the output of a Taskfile is not always in the order you wrote it. +section: Concepts +docType: concept outline: deep --- diff --git a/website/src/next/docs/concepts/variable-resolution.md b/website/src/next/docs/concepts/variable-resolution.md index 61a4fa65b0..5969275a6d 100644 --- a/website/src/next/docs/concepts/variable-resolution.md +++ b/website/src/next/docs/concepts/variable-resolution.md @@ -3,6 +3,8 @@ title: Variable resolution description: The single order Task uses to resolve a variable, and the consequences that surprise people most often. +section: Concepts +docType: concept outline: deep --- diff --git a/website/src/next/docs/contributing.md b/website/src/next/docs/contributing.md index b2c71bd0b0..9b7723ed43 100644 --- a/website/src/next/docs/contributing.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/deprecations/completion-scripts.md b/website/src/next/docs/deprecations/completion-scripts.md index 55e6a74a22..d0e6ca7041 100644 --- a/website/src/next/docs/deprecations/completion-scripts.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/deprecations/index.md b/website/src/next/docs/deprecations/index.md index d58ee2d335..4b8d4c778e 100644 --- a/website/src/next/docs/deprecations/index.md +++ b/website/src/next/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/next/docs/deprecations/template-functions.md b/website/src/next/docs/deprecations/template-functions.md index 6437418881..36a7b3372d 100644 --- a/website/src/next/docs/deprecations/template-functions.md +++ b/website/src/next/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/next/docs/deprecations/version-2-schema.md b/website/src/next/docs/deprecations/version-2-schema.md index 15be1dfc55..e1c2f4417b 100644 --- a/website/src/next/docs/deprecations/version-2-schema.md +++ b/website/src/next/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/next/docs/experiments/env-precedence.md b/website/src/next/docs/experiments/env-precedence.md index 5df9f3ca82..ae9e4b23a8 100644 --- a/website/src/next/docs/experiments/env-precedence.md +++ b/website/src/next/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/next/docs/experiments/gentle-force.md b/website/src/next/docs/experiments/gentle-force.md index cd303106e5..870e0f166b 100644 --- a/website/src/next/docs/experiments/gentle-force.md +++ b/website/src/next/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/next/docs/experiments/index.md b/website/src/next/docs/experiments/index.md index 6ba48d89f3..3d4a1feaa5 100644 --- a/website/src/next/docs/experiments/index.md +++ b/website/src/next/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/next/docs/experiments/remote-taskfiles.md b/website/src/next/docs/experiments/remote-taskfiles.md index 6008947721..ef508cddc2 100644 --- a/website/src/next/docs/experiments/remote-taskfiles.md +++ b/website/src/next/docs/experiments/remote-taskfiles.md @@ -1,6 +1,8 @@ --- title: Remote Taskfiles (#1317) description: Experimentation for using Taskfiles stored in remote locations +section: Project +docType: project outline: deep --- diff --git a/website/src/next/docs/faq.md b/website/src/next/docs/faq.md index 95d6108450..783d138f5b 100644 --- a/website/src/next/docs/faq.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/getting-started.md b/website/src/next/docs/getting-started.md index 32b8be9220..4558215be9 100644 --- a/website/src/next/docs/getting-started.md +++ b/website/src/next/docs/getting-started.md @@ -1,6 +1,8 @@ --- title: Getting Started description: Guide for getting started with Task +section: Getting Started +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/arguments.md b/website/src/next/docs/guide/arguments.md index a68ca0d2e0..ee35d8a54c 100644 --- a/website/src/next/docs/guide/arguments.md +++ b/website/src/next/docs/guide/arguments.md @@ -3,6 +3,8 @@ title: Passing arguments description: Forward command line arguments to a task with `--`, and match part of a task's name with a wildcard. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/conditional-execution.md b/website/src/next/docs/guide/conditional-execution.md index 99b55765c5..8a16d39b05 100644 --- a/website/src/next/docs/guide/conditional-execution.md +++ b/website/src/next/docs/guide/conditional-execution.md @@ -3,6 +3,8 @@ title: Conditional execution description: Decide whether a task should run at all, using `preconditions`, `if`, and the flags that limit when a task runs. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/defining-tasks.md b/website/src/next/docs/guide/defining-tasks.md index 360a7fb898..945fdef157 100644 --- a/website/src/next/docs/guide/defining-tasks.md +++ b/website/src/next/docs/guide/defining-tasks.md @@ -3,6 +3,8 @@ 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 --- diff --git a/website/src/next/docs/guide/dependencies.md b/website/src/next/docs/guide/dependencies.md index ed6d147644..e81a17a23a 100644 --- a/website/src/next/docs/guide/dependencies.md +++ b/website/src/next/docs/guide/dependencies.md @@ -3,6 +3,8 @@ title: Dependencies and task calls description: Run tasks in parallel with `deps`, call another task from `cmds`, and schedule cleanup with `defer`. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/environment.md b/website/src/next/docs/guide/environment.md index 040af3fd1d..d83156a19d 100644 --- a/website/src/next/docs/guide/environment.md +++ b/website/src/next/docs/guide/environment.md @@ -3,6 +3,8 @@ 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 --- diff --git a/website/src/next/docs/guide/includes.md b/website/src/next/docs/guide/includes.md index 77aeb3486e..c3e1e21af5 100644 --- a/website/src/next/docs/guide/includes.md +++ b/website/src/next/docs/guide/includes.md @@ -3,6 +3,8 @@ title: Including other Taskfiles description: Reuse tasks across projects with `includes` — namespaces, optional and internal includes, flattening, and per-include variables. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/index.md b/website/src/next/docs/guide/index.md index af71eb369d..0305b680bf 100644 --- a/website/src/next/docs/guide/index.md +++ b/website/src/next/docs/guide/index.md @@ -3,6 +3,8 @@ title: Guide description: An index of every topic in the Task guide, from running your first task to composing Taskfiles across repositories. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/loops.md b/website/src/next/docs/guide/loops.md index 2947ffffef..208b0f17dc 100644 --- a/website/src/next/docs/guide/loops.md +++ b/website/src/next/docs/guide/loops.md @@ -3,6 +3,8 @@ 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 --- diff --git a/website/src/next/docs/guide/output.md b/website/src/next/docs/guide/output.md index e643602a7b..195c7082e1 100644 --- a/website/src/next/docs/guide/output.md +++ b/website/src/next/docs/guide/output.md @@ -3,6 +3,8 @@ title: Output and logging description: Choose how Task prints command output, silence it, ignore errors, and annotate failures in CI. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/platforms.md b/website/src/next/docs/guide/platforms.md index 9c33bd1ada..a070027212 100644 --- a/website/src/next/docs/guide/platforms.md +++ b/website/src/next/docs/guide/platforms.md @@ -3,6 +3,8 @@ title: Platform-specific behaviour 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 --- diff --git a/website/src/next/docs/guide/required-variables.md b/website/src/next/docs/guide/required-variables.md index 30543ce5a7..66022e4353 100644 --- a/website/src/next/docs/guide/required-variables.md +++ b/website/src/next/docs/guide/required-variables.md @@ -3,6 +3,8 @@ title: Required variables and prompts description: Require variables to be set, restrict them to a list of allowed values, and prompt for them interactively. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/running-tasks.md b/website/src/next/docs/guide/running-tasks.md index 691dcca445..0df2fa2d49 100644 --- a/website/src/next/docs/guide/running-tasks.md +++ b/website/src/next/docs/guide/running-tasks.md @@ -3,6 +3,8 @@ 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 --- diff --git a/website/src/next/docs/guide/up-to-date.md b/website/src/next/docs/guide/up-to-date.md index 2a25859aa7..0c7e2f5036 100644 --- a/website/src/next/docs/guide/up-to-date.md +++ b/website/src/next/docs/guide/up-to-date.md @@ -3,6 +3,8 @@ title: Skipping work that is up to date description: Stop a task from running again when nothing has changed, using source and generated file fingerprints or your own `status` checks. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/variables.md b/website/src/next/docs/guide/variables.md index 61b6fe5f88..4e87d58360 100644 --- a/website/src/next/docs/guide/variables.md +++ b/website/src/next/docs/guide/variables.md @@ -3,6 +3,8 @@ title: Variables description: Static, dynamic, map and secret variables, how they are scoped, and how they reference each other. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/guide/watch.md b/website/src/next/docs/guide/watch.md index 106bd3f798..7d81d5d27b 100644 --- a/website/src/next/docs/guide/watch.md +++ b/website/src/next/docs/guide/watch.md @@ -1,6 +1,8 @@ --- title: Watch mode description: Re-run a task automatically whenever its sources change. +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md index 5d1ea77ec4..2f1ee3d68a 100644 --- a/website/src/next/docs/index.md +++ b/website/src/next/docs/index.md @@ -3,6 +3,8 @@ 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 outline: deep --- diff --git a/website/src/next/docs/installation.md b/website/src/next/docs/installation.md index 05658d04c7..a36b29f779 100644 --- a/website/src/next/docs/installation.md +++ b/website/src/next/docs/installation.md @@ -1,6 +1,8 @@ --- title: Installation description: Installation methods for Task +section: Getting Started +docType: guide outline: deep --- diff --git a/website/src/next/docs/integrations.md b/website/src/next/docs/integrations.md index 9d95151d61..8d779146f6 100644 --- a/website/src/next/docs/integrations.md +++ b/website/src/next/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/next/docs/reference/cli.md b/website/src/next/docs/reference/cli.md index 0051797355..1659529616 100644 --- a/website/src/next/docs/reference/cli.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/reference/config.md b/website/src/next/docs/reference/config.md index be606b876b..ee76043a1d 100644 --- a/website/src/next/docs/reference/config.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/reference/environment.md b/website/src/next/docs/reference/environment.md index fefe10ae7d..5e2ce19e26 100644 --- a/website/src/next/docs/reference/environment.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/reference/package.md b/website/src/next/docs/reference/package.md index 7f710124b3..cd3cc3c856 100644 --- a/website/src/next/docs/reference/package.md +++ b/website/src/next/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/next/docs/reference/schema.md b/website/src/next/docs/reference/schema.md index 9259371397..f3c9558d87 100644 --- a/website/src/next/docs/reference/schema.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/reference/templating.md b/website/src/next/docs/reference/templating.md index c267bc0d54..3dac6396fa 100644 --- a/website/src/next/docs/reference/templating.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/releasing.md b/website/src/next/docs/releasing.md index a0c4396791..54c02f4500 100644 --- a/website/src/next/docs/releasing.md +++ b/website/src/next/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 --- diff --git a/website/src/next/docs/remote-taskfiles.md b/website/src/next/docs/remote-taskfiles.md index 92972851f9..b880e59cd4 100644 --- a/website/src/next/docs/remote-taskfiles.md +++ b/website/src/next/docs/remote-taskfiles.md @@ -2,6 +2,8 @@ title: Remote Taskfiles description: Guide to loading and securely using Taskfiles from HTTP and Git sources +section: Guide +docType: guide outline: deep --- diff --git a/website/src/next/docs/security/incident-response-plan.md b/website/src/next/docs/security/incident-response-plan.md index e64f087f89..4b79660b62 100644 --- a/website/src/next/docs/security/incident-response-plan.md +++ b/website/src/next/docs/security/incident-response-plan.md @@ -3,6 +3,8 @@ title: Incident Response Plan description: Task's process for detecting, triaging, mitigating, and disclosing security incidents +section: Project +docType: project outline: deep --- diff --git a/website/src/next/docs/security/index.md b/website/src/next/docs/security/index.md index 8ddf735df5..d5338abb67 100644 --- a/website/src/next/docs/security/index.md +++ b/website/src/next/docs/security/index.md @@ -3,6 +3,8 @@ title: Security description: How to report Task security vulnerabilities and how the project responds to them +section: Project +docType: project outline: deep --- diff --git a/website/src/next/docs/security/threat-model.md b/website/src/next/docs/security/threat-model.md index 86b153ef99..7ff8195f8d 100644 --- a/website/src/next/docs/security/threat-model.md +++ b/website/src/next/docs/security/threat-model.md @@ -3,6 +3,8 @@ title: Threat Model description: Threats, assets, trust boundaries, and mitigations for the Task project and its release infrastructure +section: Project +docType: project outline: deep --- diff --git a/website/src/next/docs/styleguide.md b/website/src/next/docs/styleguide.md index f106168082..36d06c8e53 100644 --- a/website/src/next/docs/styleguide.md +++ b/website/src/next/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/next/docs/taskfile-versions.md b/website/src/next/docs/taskfile-versions.md index 44f907786a..7c7ee61208 100644 --- a/website/src/next/docs/taskfile-versions.md +++ b/website/src/next/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 --- From 86a99c32e4f19c72d28f293453d47cc3354d79f5 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:25:54 +0200 Subject: [PATCH 14/21] fix(site): clean the right dist directory The clean task removed ./vitepress/dist. The build writes to ./.vitepress/dist, with a leading dot, so the task has never deleted anything since it was written. --- website/Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/Taskfile.yml b/website/Taskfile.yml index bbb7ca9324..bf8bad85eb 100644 --- a/website/Taskfile.yml +++ b/website/Taskfile.yml @@ -75,7 +75,7 @@ tasks: clean: desc: Clean temp directories cmds: - - rm -rf ./vitepress/dist + - rm -rf ./.vitepress/dist # --no-build is what makes the channel stick: the CLI builds by default, and # that build would come from netlify.toml, which knows nothing about the From 77705d0eced209d34026ddc8a73a8bccc76b43c5 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:26:49 +0200 Subject: [PATCH 15/21] docs(site): define the missing link reference in the any-variables post "[Map Variables][map-variables]" had no matching definition, so it rendered as literal text with the brackets showing. The post shipped that way in 2024 and the same text is in both channels. Map support has landed since, so the reference now points at the section that documents it. --- website/src/next/blog/any-variables.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/src/next/blog/any-variables.md b/website/src/next/blog/any-variables.md index 3868fc6361..c1121df760 100644 --- a/website/src/next/blog/any-variables.md +++ b/website/src/next/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 From f4f052eddce6a2dee250d29081a78a2dcb4dc5f2 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:30:48 +0200 Subject: [PATCH 16/21] docs(site): drop em dashes from the documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List entries of the form "[Link](x) — gloss" become "[Link](x): gloss". Prose uses were rewritten one at a time, since the right replacement depends on what the dash was standing in for: a colon before a list, a comma around an aside, a full stop between two sentences. Also removes the two that predate this branch, in the Nushell completions note and the remote variables table. --- website/src/next/agents.md | 20 ++++++------- .../concepts/dependencies-and-concurrency.md | 10 +++---- .../next/docs/concepts/variable-resolution.md | 16 +++++----- website/src/next/docs/guide/includes.md | 2 +- website/src/next/docs/guide/index.md | 30 +++++++++---------- website/src/next/docs/guide/variables.md | 2 +- website/src/next/docs/index.md | 20 ++++++------- website/src/next/docs/installation.md | 5 ++-- website/src/next/docs/remote-taskfiles.md | 2 +- 9 files changed, 54 insertions(+), 53 deletions(-) diff --git a/website/src/next/agents.md b/website/src/next/agents.md index 0be6a76ce7..71d13f7d43 100644 --- a/website/src/next/agents.md +++ b/website/src/next/agents.md @@ -17,16 +17,16 @@ URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at ## Where to look -- [Getting Started](./docs/getting-started.md) — the shape of a Taskfile. -- [Taskfile Schema](./docs/reference/schema.md) — the source of truth for keys, +- [Getting Started](./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 +- [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/) — one page per topic, for how to do a thing. +- [Guide](./docs/guide/): one page per topic, for how to do a thing. - [Variable resolution](./docs/concepts/variable-resolution.md) and - [Dependencies and concurrency](./docs/concepts/dependencies-and-concurrency.md) - — for when the behaviour matters more than the procedure. + [Dependencies and concurrency](./docs/concepts/dependencies-and-concurrency.md): + for when the behaviour matters more than the procedure. ## Semantics that are easy to get wrong @@ -35,13 +35,13 @@ URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at entry. 2. A task's own `vars:` cannot be overridden from the command line. Put the default in global `vars:` if the caller needs to supply a value. -3. `vars:` given on an `includes:` entry are defaults, not overrides — the +3. `vars:` given on an `includes:` entry are defaults, not overrides: the included Taskfile's own `vars:` are applied after them and win. 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`, not an exported variable. Use Task's `dir:` and `env:` instead. +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 diff --git a/website/src/next/docs/concepts/dependencies-and-concurrency.md b/website/src/next/docs/concepts/dependencies-and-concurrency.md index b4135c4572..db0765f7fc 100644 --- a/website/src/next/docs/concepts/dependencies-and-concurrency.md +++ b/website/src/next/docs/concepts/dependencies-and-concurrency.md @@ -31,7 +31,7 @@ tasks: `compile` and `generate-assets` run concurrently in an unspecified order, and `packaging` is printed only once both have finished. Nothing orders the -dependencies relative to each other — if `generate-assets` needs `compile` to +dependencies relative to each other. If `generate-assets` needs `compile` to have run, it must say so itself, with its own `deps`. A task reference inside `cmds` is different: it runs at its position in the @@ -66,7 +66,7 @@ finishes. See [Output and logging](../guide/output.md). `--concurrency` / `-C` caps how many tasks run simultaneously. The default is `0`, meaning no limit. It is the setting to reach for when parallel tasks -compete for the same resource — a database, a port, the network. +compete for the same resource: a database, a port, the network. ## When one dependency fails @@ -120,6 +120,6 @@ That prints `deploying`, then `remove the temp dir`, then `stop the tunnel`. ## Related -- [Dependencies and task calls](../guide/dependencies.md) — the syntax for each. -- [Output and logging](../guide/output.md) — output modes for parallel runs. -- [CLI](../reference/cli.md) — `--concurrency`, `--failfast`. +- [Dependencies and task calls](../guide/dependencies.md): the syntax for each. +- [Output and logging](../guide/output.md): output modes for parallel runs. +- [CLI](../reference/cli.md): `--concurrency`, `--failfast`. diff --git a/website/src/next/docs/concepts/variable-resolution.md b/website/src/next/docs/concepts/variable-resolution.md index 5969275a6d..831b063413 100644 --- a/website/src/next/docs/concepts/variable-resolution.md +++ b/website/src/next/docs/concepts/variable-resolution.md @@ -54,8 +54,8 @@ $ task greet NAME=from-cli from-task ``` -To let a caller supply a value, give the default somewhere earlier — global -`vars:` — or use a template default: +To let a caller supply a value, give the default somewhere earlier, in global +`vars:`, or use a template default: ```yaml version: '3' @@ -99,7 +99,7 @@ that sets it silently get the declared value instead. ### 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 — +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 @@ -121,13 +121,13 @@ earlier step, never a later one. 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, a map — use `ref:` +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. ## Related -- [Variables](../guide/variables.md) — how to declare each kind. -- [Environment variables](../guide/environment.md) — `env:` and `.env` files. -- [Including other Taskfiles](../guide/includes.md) — namespaces and includes. -- [Taskfile Schema](../reference/schema.md) — every key, with its type. +- [Variables](../guide/variables.md): how to declare each kind. +- [Environment variables](../guide/environment.md): `env:` and `.env` files. +- [Including other Taskfiles](../guide/includes.md): namespaces and includes. +- [Taskfile Schema](../reference/schema.md): every key, with its type. diff --git a/website/src/next/docs/guide/includes.md b/website/src/next/docs/guide/includes.md index c3e1e21af5..913205b87a 100644 --- a/website/src/next/docs/guide/includes.md +++ b/website/src/next/docs/guide/includes.md @@ -1,7 +1,7 @@ --- title: Including other Taskfiles description: - Reuse tasks across projects with `includes` — namespaces, optional and + Reuse tasks across projects with `includes`, covering namespaces, optional and internal includes, flattening, and per-include variables. section: Guide docType: guide diff --git a/website/src/next/docs/guide/index.md b/website/src/next/docs/guide/index.md index 0305b680bf..33366560eb 100644 --- a/website/src/next/docs/guide/index.md +++ b/website/src/next/docs/guide/index.md @@ -17,44 +17,44 @@ Taskfile. Each page below is self-contained; start wherever your problem is. ## Writing and running tasks -- [Running tasks](./running-tasks.md) — how Task finds a Taskfile, and how to +- [Running tasks](./running-tasks.md): how Task finds a Taskfile, and how to run one from a subdirectory, your home directory, standard input or a dry run. -- [Defining tasks](./defining-tasks.md) — syntax shortcuts, internal tasks, +- [Defining tasks](./defining-tasks.md): syntax shortcuts, internal tasks, aliases, the directory a task runs in, and its help text. -- [Passing arguments](./arguments.md) — forwarding command line arguments with +- [Passing arguments](./arguments.md): forwarding command line arguments with `--`, and matching part of a task's name with a wildcard. ## Variables and environment -- [Variables](./variables.md) — static, dynamic, map and secret variables, their +- [Variables](./variables.md): static, dynamic, map and secret variables, their scope, and how they reference each other. -- [Environment variables](./environment.md) — setting them per task or globally, +- [Environment variables](./environment.md): setting them per task or globally, and loading them from `.env` files. -- [Required variables and prompts](./required-variables.md) — requiring +- [Required variables and prompts](./required-variables.md): requiring variables, restricting them to allowed values, and prompting for them. ## Controlling what runs -- [Dependencies and task calls](./dependencies.md) — `deps`, calling a task from +- [Dependencies and task calls](./dependencies.md): `deps`, calling a task from `cmds`, and cleanup with `defer`. -- [Skipping work that is up to date](./up-to-date.md) — source and generated +- [Skipping work that is up to date](./up-to-date.md): source and generated file fingerprints, and your own `status` checks. -- [Conditional execution](./conditional-execution.md) — `preconditions`, `if`, +- [Conditional execution](./conditional-execution.md): `preconditions`, `if`, and the flags that limit when a task runs. -- [Loops](./loops.md) — repeating a command over a list, a matrix, a variable, +- [Loops](./loops.md): repeating a command over a list, a matrix, a variable, your sources, or other tasks. ## Composing Taskfiles -- [Including other Taskfiles](./includes.md) — namespaces, optional and internal +- [Including other Taskfiles](./includes.md): namespaces, optional and internal includes, flattening, and per-include variables. -- [Remote Taskfiles](../remote-taskfiles.md) — running and including Taskfiles +- [Remote Taskfiles](../remote-taskfiles.md): running and including Taskfiles served over HTTP or Git, and the checksum rules that guard them. ## Execution environment -- [Output and logging](./output.md) — output modes, silent mode, ignoring +- [Output and logging](./output.md): output modes, silent mode, ignoring errors, and CI annotations. -- [Platform-specific behaviour](./platforms.md) — restricting tasks to an OS or +- [Platform-specific behaviour](./platforms.md): restricting tasks to an OS or architecture, and shell options. -- [Watch mode](./watch.md) — re-running a task when its sources change. +- [Watch mode](./watch.md): re-running a task when its sources change. diff --git a/website/src/next/docs/guide/variables.md b/website/src/next/docs/guide/variables.md index 4e87d58360..fc1e36500b 100644 --- a/website/src/next/docs/guide/variables.md +++ b/website/src/next/docs/guide/variables.md @@ -52,7 +52,7 @@ tasks: Variables can be set in many places in a Taskfile, and when the same name is set twice, one of them wins. The order is the same everywhere and it is described -once, in [Variable resolution](../concepts/variable-resolution.md#the-order) — +once, in [Variable resolution](../concepts/variable-resolution.md#the-order), including the two cases that surprise people most: a task's own `vars:` cannot be overridden from the command line, and `vars:` given on an `includes:` entry act as defaults rather than overrides. diff --git a/website/src/next/docs/index.md b/website/src/next/docs/index.md index 2f1ee3d68a..08635054bc 100644 --- a/website/src/next/docs/index.md +++ b/website/src/next/docs/index.md @@ -18,9 +18,9 @@ a YAML file called a `Taskfile`, and Task runs them. Install the binary, then write your first Taskfile. It takes about five minutes. -- [Installation](./installation.md) — package managers, prebuilt binaries, +- [Installation](./installation.md): package managers, prebuilt binaries, building from source, and shell completions. -- [Getting Started](./getting-started.md) — your first Taskfile, run end to end. +- [Getting Started](./getting-started.md): your first Taskfile, run end to end. ## Using Task @@ -30,22 +30,22 @@ conditional execution, loops, includes, output modes and watch mode. ## Looking something up -- [Taskfile Schema](./reference/schema.md) — every key you can put in a +- [Taskfile Schema](./reference/schema.md): every key you can put in a Taskfile. -- [CLI](./reference/cli.md) — commands, flags and exit codes. -- [Templating](./reference/templating.md) — template functions and special +- [CLI](./reference/cli.md): commands, flags and exit codes. +- [Templating](./reference/templating.md): template functions and special variables. - [Configuration](./reference/config.md) and - [Environment](./reference/environment.md) — settings outside the Taskfile. + [Environment](./reference/environment.md): settings outside the Taskfile. ## Keeping up -- [Changelog](./changelog.md) — what shipped, and when. +- [Changelog](./changelog.md): what shipped, and when. - [Experiments](./experiments/index.md) and - [Deprecations](./deprecations/index.md) — what is coming, and what is going + [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. +- [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 diff --git a/website/src/next/docs/installation.md b/website/src/next/docs/installation.md index a36b29f779..fc7921d4d0 100644 --- a/website/src/next/docs/installation.md +++ b/website/src/next/docs/installation.md @@ -467,8 +467,9 @@ 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: diff --git a/website/src/next/docs/remote-taskfiles.md b/website/src/next/docs/remote-taskfiles.md index b880e59cd4..648041943b 100644 --- a/website/src/next/docs/remote-taskfiles.md +++ b/website/src/next/docs/remote-taskfiles.md @@ -185,7 +185,7 @@ 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 From f4b51481bc143f0c780baf30fa6f3524b163ae55 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:50:38 +0200 Subject: [PATCH 17/21] docs(site): make the concurrency examples runnable Both snippets referenced tasks they did not define, so copying either one and running it failed with "Task ... does not exist" and exit 201. Every other example in the docs defines what it references. The behaviour they describe was right; only the snippets were short. --- .../concepts/dependencies-and-concurrency.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/website/src/next/docs/concepts/dependencies-and-concurrency.md b/website/src/next/docs/concepts/dependencies-and-concurrency.md index db0765f7fc..27dc874556 100644 --- a/website/src/next/docs/concepts/dependencies-and-concurrency.md +++ b/website/src/next/docs/concepts/dependencies-and-concurrency.md @@ -27,6 +27,14 @@ tasks: deps: [compile, generate-assets] cmds: - echo "packaging" + + compile: + cmds: + - go build -o ./bin/app . + + generate-assets: + cmds: + - esbuild --bundle --minify css/index.css > public/bundle.css ``` `compile` and `generate-assets` run concurrently in an unspecified order, and @@ -45,6 +53,14 @@ tasks: cmds: - task: build - task: publish + + build: + cmds: + - go build -o ./bin/app . + + publish: + cmds: + - ./scripts/publish.sh ./bin/app ``` Here `build` finishes before `publish` starts. From e9634986bcdf70b585595af7be399c9dc76e4d56 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:51:34 +0200 Subject: [PATCH 18/21] docs(site): correct what secret and env actually do Two claims were wrong, and one of them was dangerous. The agent guidance said to keep credentials in `env:` and mark them `secret: true` so they are masked. `secret: true` has no effect on `env:` at all, and it never masks what a command itself prints - testdata/secrets/Taskfile.yml has a case named for that limitation. Following the advice would have produced Taskfiles that leak tokens into CI logs while looking as though they did not. The second claim was that a template sees any `env:` value. That holds for `env:` at the root of the Taskfile, but a task's own `env:` is assembled after the variable set is resolved, so `{{.FOO}}` renders empty while `$FOO` works. Both pages now say which is which. --- website/src/next/agents.md | 12 +++++++----- .../next/docs/concepts/variable-resolution.md | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/website/src/next/agents.md b/website/src/next/agents.md index 71d13f7d43..09e384d988 100644 --- a/website/src/next/agents.md +++ b/website/src/next/agents.md @@ -30,9 +30,9 @@ URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at ## Semantics that are easy to get wrong -1. `vars` are template values. `env` values are template values **and** are - exported to the commands Task runs. `$FOO` in a command does not see a `vars` - entry. +1. `vars` are template values only: `$FOO` in a command never sees one. `env` is + exported, so `$FOO` works. A template also sees `env` declared at the root of + the Taskfile, but **not** `env` declared on a task, which renders empty. 2. A task's own `vars:` cannot be overridden from the command line. Put the default in global `vars:` if the caller needs to supply a value. 3. `vars:` given on an `includes:` entry are defaults, not overrides: the @@ -60,7 +60,9 @@ URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at - 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 `env:` or a secret manager, and mark - them `secret: true` so they are masked in logs. +- 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/next/docs/concepts/variable-resolution.md b/website/src/next/docs/concepts/variable-resolution.md index 831b063413..292fbb531c 100644 --- a/website/src/next/docs/concepts/variable-resolution.md +++ b/website/src/next/docs/concepts/variable-resolution.md @@ -107,10 +107,20 @@ them onto the tasks that use them, where step 8 keeps them local. ### `env:` and `vars:` are not the same thing -Both end up in the same set, so `{{.FOO}}` finds a name set -by `env:`. The difference is on the way out: only `env:` entries are exported to -the environment of the commands Task runs. A `vars:` entry exists for templates -only, and `$FOO` in a command will not see it. +A `vars:` entry exists for templates only. `$FOO` in a command will not see it, +whichever level it was declared at. + +`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 | **no, it renders empty** | 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. Read a task-level value with `$FOO`, +or declare it in `vars:` if a template needs it. ## When values are computed From 44e6f951b0e8032ccbe97cca57f5462fb47791c3 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 19:56:16 +0200 Subject: [PATCH 19/21] docs(site): fold the concepts pages into the guide Two pages made a section of their own for subjects the guide already owns, and gave Algolia a second set of records competing with Variables and Dependencies for the same queries. The resolution order, and what it means in practice, now sit in guide/variables.md. Interleaved output, --concurrency, run: once and the reverse order of defer join guide/dependencies.md. Nothing is dropped; fail-fast and defer were already covered there and are not repeated. Also quotes a command in the secret variables example. A plain YAML scalar cannot contain ": ", so `curl -H "Authorization: {{.API_KEY}}"` made the whole file unloadable - the example predates this branch and was the only one of 115 Taskfile blocks in the docs that Task refuses to parse. Quoted, it runs and prints the masked value the comment promises. --- website/.vitepress/sidebar/next.ts | 14 -- website/src/next/agents.md | 6 +- .../concepts/dependencies-and-concurrency.md | 141 ----------------- .../next/docs/concepts/variable-resolution.md | 143 ------------------ website/src/next/docs/guide/dependencies.md | 48 +++++- website/src/next/docs/guide/variables.md | 127 +++++++++++++++- 6 files changed, 171 insertions(+), 308 deletions(-) delete mode 100644 website/src/next/docs/concepts/dependencies-and-concurrency.md delete mode 100644 website/src/next/docs/concepts/variable-resolution.md diff --git a/website/.vitepress/sidebar/next.ts b/website/.vitepress/sidebar/next.ts index 68df219ad4..fc7bc1b73a 100644 --- a/website/.vitepress/sidebar/next.ts +++ b/website/.vitepress/sidebar/next.ts @@ -96,20 +96,6 @@ export const sidebar: DefaultTheme.SidebarItem[] = [ } ] }, - { - text: 'Concepts', - collapsed: true, - items: [ - { - text: 'Variable resolution', - link: '/docs/concepts/variable-resolution' - }, - { - text: 'Dependencies and concurrency', - link: '/docs/concepts/dependencies-and-concurrency' - } - ] - }, { text: 'Reference', collapsed: false, diff --git a/website/src/next/agents.md b/website/src/next/agents.md index 09e384d988..f189f0828c 100644 --- a/website/src/next/agents.md +++ b/website/src/next/agents.md @@ -24,9 +24,9 @@ URL. The curated index is at [/llms.txt](/llms.txt) and the full corpus at - [Templating](./docs/reference/templating.md): every template function and special variable. Check here before inventing one. - [Guide](./docs/guide/): one page per topic, for how to do a thing. -- [Variable resolution](./docs/concepts/variable-resolution.md) and - [Dependencies and concurrency](./docs/concepts/dependencies-and-concurrency.md): - for when the behaviour matters more than the procedure. +- [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 diff --git a/website/src/next/docs/concepts/dependencies-and-concurrency.md b/website/src/next/docs/concepts/dependencies-and-concurrency.md deleted file mode 100644 index 27dc874556..0000000000 --- a/website/src/next/docs/concepts/dependencies-and-concurrency.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Dependencies and concurrency -description: - What runs in parallel, what runs in order, and why the output of a Taskfile is - not always in the order you wrote it. -section: Concepts -docType: concept -outline: deep ---- - -# Dependencies and concurrency - -A task can pull in other tasks two ways, and they behave differently. Choosing -the wrong one is the most common cause of a Taskfile that works on one machine -and not another. - -## `deps` run together, `cmds` run in order - -Everything in `deps` starts at once. Task waits for all of them to finish, then -runs `cmds`: - -```yaml -version: '3' - -tasks: - build: - deps: [compile, generate-assets] - cmds: - - echo "packaging" - - compile: - cmds: - - go build -o ./bin/app . - - generate-assets: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css -``` - -`compile` and `generate-assets` run concurrently in an unspecified order, and -`packaging` is printed only once both have finished. Nothing orders the -dependencies relative to each other. If `generate-assets` needs `compile` to -have run, it must say so itself, with its own `deps`. - -A task reference inside `cmds` is different: it runs at its position in the -list, and the next command waits for it. - -```yaml -version: '3' - -tasks: - release: - cmds: - - task: build - - task: publish - - build: - cmds: - - go build -o ./bin/app . - - publish: - cmds: - - ./scripts/publish.sh ./bin/app -``` - -Here `build` finishes before `publish` starts. - -**The rule of thumb:** `deps` expresses "these must have happened", `cmds` -expresses "do this, then this". If order matters, it belongs in `cmds`. - -## Interleaved output is expected - -Because dependencies run concurrently, their output arrives interleaved and in a -different order between runs. That is not a bug, and it is why the default -output mode can look scrambled on a parallel build. - -Set `output: prefixed` to label each line with the task it came from, or -`output: group` to hold each task's output and print it in one block when it -finishes. See [Output and logging](../guide/output.md). - -## Limiting how much runs at once - -`--concurrency` / `-C` caps how many tasks run simultaneously. The default is -`0`, meaning no limit. It is the setting to reach for when parallel tasks -compete for the same resource: a database, a port, the network. - -## When one dependency fails - -By default Task waits for the other dependencies to finish before reporting the -failure. `--failfast` / `-F` stops everything as soon as one of them fails. - -## Running a task only once - -A task marked `run: once` executes a single time per invocation of `task`, no -matter how many other tasks depend on it: - -```yaml -version: '3' - -tasks: - setup: - run: once - cmds: - - echo "setting up" - - test: - deps: [setup] - lint: - deps: [setup] - - check: - deps: [test, lint] -``` - -`task check` prints `setting up` once, not twice. Without `run: once`, a shared -dependency runs for each dependent that asks for it. - -## Cleanup runs in reverse - -`defer` schedules a command to run when the task ends, whether it succeeded or -failed. Deferred commands run in reverse order of declaration, so the first -thing you set up is the last thing torn down: - -```yaml -version: '3' - -tasks: - deploy: - cmds: - - defer: echo "stop the tunnel" - - defer: echo "remove the temp dir" - - echo "deploying" -``` - -That prints `deploying`, then `remove the temp dir`, then `stop the tunnel`. - -## Related - -- [Dependencies and task calls](../guide/dependencies.md): the syntax for each. -- [Output and logging](../guide/output.md): output modes for parallel runs. -- [CLI](../reference/cli.md): `--concurrency`, `--failfast`. diff --git a/website/src/next/docs/concepts/variable-resolution.md b/website/src/next/docs/concepts/variable-resolution.md deleted file mode 100644 index 292fbb531c..0000000000 --- a/website/src/next/docs/concepts/variable-resolution.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: Variable resolution -description: - The single order Task uses to resolve a variable, and the consequences that - surprise people most often. -section: Concepts -docType: concept -outline: deep ---- - -# Variable resolution - -Task builds one flat set of variables for each task, just before running it. -Every source is applied to that set in a fixed order, and each one overwrites -what came before. There is no per-source scoping and no lookup chain at render -time: by the time a template runs, a name has exactly one value. - -Understanding that single order explains almost every surprise on this page. - -## The 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 | - -## What this means in practice - -### 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 -``` - -### Variables on an `includes:` entry are defaults, not overrides - -Step 6 comes after step 5, so the included Taskfile's own `vars:` win over the -values supplied where it is included. Passing `vars:` on an `includes:` entry -only takes effect for names the included Taskfile does not define itself. - -If you are writing a Taskfile meant to be included and configured, leave the -configurable names out of `vars:` and give the default at the point of use -instead: - -```yaml -version: '3' - -tasks: - build: - cmds: - - echo "building {{.DOCKER_IMAGE | default "app"}}" -``` - -Declaring `DOCKER_IMAGE` in that file's `vars:` would make every include site -that sets it silently get the declared value instead. - -### 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. - -### `env:` and `vars:` are not the same thing - -A `vars:` entry exists for templates only. `$FOO` in a command will not see it, -whichever level it was declared at. - -`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 | **no, it renders empty** | 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. Read a task-level value with `$FOO`, -or declare it in `vars:` if a template needs it. - -## When values are computed - -Dynamic variables (`sh:`) are executed while the set is being built, in the -order above. A `sh:` command can therefore only reference variables from an -earlier step, never a later one. - -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. - -## Related - -- [Variables](../guide/variables.md): how to declare each kind. -- [Environment variables](../guide/environment.md): `env:` and `.env` files. -- [Including other Taskfiles](../guide/includes.md): namespaces and includes. -- [Taskfile Schema](../reference/schema.md): every key, with its type. diff --git a/website/src/next/docs/guide/dependencies.md b/website/src/next/docs/guide/dependencies.md index e81a17a23a..3cadce5a8d 100644 --- a/website/src/next/docs/guide/dependencies.md +++ b/website/src/next/docs/guide/dependencies.md @@ -11,7 +11,8 @@ outline: deep # Dependencies and task calls A task can pull in other tasks in three ways, and each has different ordering -guarantees. +guarantees. The rule of thumb: `deps` says "these must have happened", `cmds` +says "do this, then this". If order matters, it belongs in `cmds`. ## Task dependencies @@ -113,6 +114,48 @@ tasks: Alternatively, you can use `--failfast`, which also work for `--parallel`. +### Interleaved output is expected + +Because dependencies run concurrently, their output arrives interleaved and in a +different order between runs. That is not a bug, and it is why the default +output mode can look scrambled on a parallel build. + +Set `output: prefixed` to label each line with the task it came from, or +`output: group` to hold each task's output and print it in one block when it +finishes. See [Output and logging](./output.md). + +### Limiting how much runs at once + +`--concurrency` / `-C` caps how many tasks run simultaneously. The default is +`0`, meaning no limit. It is the setting to reach for when parallel tasks +compete for the same resource: a database, a port, the network. + +### Running a task only once + +A task marked `run: once` executes a single time per invocation of `task`, no +matter how many other tasks depend on it: + +```yaml +version: '3' + +tasks: + setup: + run: once + cmds: + - echo "setting up" + + test: + deps: [setup] + lint: + deps: [setup] + + check: + deps: [test, lint] +``` + +`task check` prints `setting up` once, not twice. Without `run: once`, a shared +dependency runs for each dependent that asks for it. + ## Calling another task When a task has many dependencies, they are executed concurrently. This will @@ -174,6 +217,9 @@ 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. +Deferred commands run in reverse order of declaration, so the first thing you +set up is the last thing torn down. + In the example below, `rm -rf tmpdir/` will run even if the third command fails: ```yaml diff --git a/website/src/next/docs/guide/variables.md b/website/src/next/docs/guide/variables.md index fc1e36500b..a20973da43 100644 --- a/website/src/next/docs/guide/variables.md +++ b/website/src/next/docs/guide/variables.md @@ -51,11 +51,8 @@ tasks: ``` Variables can be set in many places in a Taskfile, and when the same name is set -twice, one of them wins. The order is the same everywhere and it is described -once, in [Variable resolution](../concepts/variable-resolution.md#the-order), -including the two cases that surprise people most: a task's own `vars:` cannot -be overridden from the command line, and `vars:` given on an `includes:` entry -act as defaults rather than overrides. +twice, one of them wins. [Resolution order](#resolution-order) below settles +that, once, for every case. Example of sending parameters with environment variables: @@ -127,6 +124,124 @@ task: [greet_user] echo "Hello, Bob!" Hello, Bob! ``` +## 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 | + +## What this means in practice + +### 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 +``` + +### Variables on an `includes:` entry are defaults, not overrides + +Step 6 comes after step 5, so the included Taskfile's own `vars:` win over the +values supplied where it is included. Passing `vars:` on an `includes:` entry +only takes effect for names the included Taskfile does not define itself. + +If you are writing a Taskfile meant to be included and configured, leave the +configurable names out of `vars:` and give the default at the point of use +instead: + +```yaml +version: '3' + +tasks: + build: + cmds: + - echo "building {{.DOCKER_IMAGE | default "app"}}" +``` + +Declaring `DOCKER_IMAGE` in that file's `vars:` would make every include site +that sets it silently get the declared value instead. + +### 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. + +### `env:` and `vars:` are not the same thing + +A `vars:` entry exists for templates only. `$FOO` in a command will not see it, +whichever level it was declared at. + +`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 | **no, it renders empty** | 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. Read a task-level value with `$FOO`, +or declare it in `vars:` if a template needs it. + +## When values are computed + +Dynamic variables (`sh:`) are executed while the set is being built, in the +order above. A `sh:` command can therefore only reference variables from an +earlier step, never a later one. + +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. + ## Dynamic variables The below syntax (`sh:` prop in a variable) is considered a dynamic variable. @@ -300,7 +415,7 @@ vars: tasks: deploy: cmds: - - curl -H "Authorization: {{.API_KEY}}" api.example.com + - 'curl -H "Authorization: {{.API_KEY}}" api.example.com' # Logged as: task: [deploy] curl -H "Authorization: *****" api.example.com ``` From d3642a7d5d0cb6e462ac6e3b40bd125e17bd9d0c Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 30 Aug 2026 20:14:10 +0200 Subject: [PATCH 20/21] feat(site): put the DocSearch crawler configuration in the repository The crawler that fills the `taskfile` index has never been described here: `git log --all -- '*algolia*' '*docsearch*'` returns nothing, so the only copy lives in a web form. That is also why it still carries the Docusaurus-era setup, years after the site moved to VitePress and every selector and URL changed. website/docsearch.config.js now holds it. It still has to be pasted into the dashboard, which is where the crawler runs, but it can now be read, reviewed and changed in a pull request. The write key is not in it. Every selector was checked against the 46 built pages: - lvl0 comes from meta[name="docsearch:section"] rather than from the active sidebar link in the DOM, so the breadcrumbs no longer depend on the theme's markup. - Everything else is scoped to .vp-doc. VitePress renders the sidebar section labels as

inside