diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d6f8ac..f822a017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Added the ability to + [loop over commands and tasks](https://taskfile.dev/usage/#looping-over-values) + using `for` (#82, #1220 by @pd93). - Fixed variable propagation in multi-level includes (#778, #996, #1256 by @hudclark). - Fixed a bug where the `--exit-code` code flag was not returning the correct diff --git a/docs/docs/api_reference.md b/docs/docs/api_reference.md index 61e54aac..06dd4e21 100644 --- a/docs/docs/api_reference.md +++ b/docs/docs/api_reference.md @@ -126,12 +126,13 @@ There are some special variables that is available on the templating system: | `TASKFILE_DIR` | The absolute path of the included Taskfile. | | `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. | | `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. | -| `TIMESTAMP` | The date object of the greatest timestamp of the files listes in `sources`. Only available within the `status` prop and if method is set to `timestamp`. | +| `TIMESTAMP` | The date object of the greatest timestamp of the files listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. | | `TASK_VERSION` | The current version of task. | +| `ITEM` | The value of the current iteration when using the `for` property. | ## ENV -Some environment variables can be overriden to adjust Task behavior. +Some environment variables can be overridden to adjust Task behavior. | ENV | Default | Description | | -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- | @@ -262,8 +263,9 @@ tasks: | Attribute | Type | Default | Description | | -------------- | ---------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `cmd` | `string` | | The shell command to be executed. | -| `silent` | `bool` | `false` | Skips some output for this command. Note that STDOUT and STDERR of the commands will still be redirected. | | `task` | `string` | | Set this to trigger execution of another task instead of running a command. This cannot be set together with `cmd`. | +| `for` | [`For`](#for) | | Runs the command once for each given value. | +| `silent` | `bool` | `false` | Skips some output for this command. Note that STDOUT and STDERR of the commands will still be redirected. | | `vars` | [`map[string]Variable`](#variable) | | Optional additional variables to be passed to the referenced task. Only relevant when setting `task` instead of `cmd`. | | `ignore_error` | `bool` | `false` | Continue execution if errors happen while executing the command. | | `defer` | `string` | | Alternative to `cmd`, but schedules the command to be executed at the end of this task instead of immediately. This cannot be used together with `cmd`. | @@ -306,6 +308,26 @@ tasks: ::: +#### For + +The `for` parameter can be defined as a string, a list of strings or a map. If +it is defined as a string, you can give it any of the following values: + +- `source` - Will run the command for each source file defined on the task. + (Glob patterns will be resolved, so `*.go` will run for every Go file that + matches). + +If it is defined as a list of strings, the command will be run for each value. + +Finally, the `for` parameter can be defined as a map when you want to use a +variable to define the values to loop over: + +| Attribute | Type | Default | Description | +| --------- | -------- | ---------------- | -------------------------------------------- | +| `var` | `string` | | The name of the variable to use as an input. | +| `split` | `string` | (any whitespace) | What string the variable should be split on. | +| `as` | `string` | `ITEM` | The name of the iterator variable. | + #### Precondition | Attribute | Type | Default | Description | diff --git a/docs/docs/usage.md b/docs/docs/usage.md index b34dd415..3dcb978b 100644 --- a/docs/docs/usage.md +++ b/docs/docs/usage.md @@ -1000,6 +1000,161 @@ tasks: This works for all types of variables. +## 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 your task's sources + +You are also able to loop over the sources of your task: + +```yaml +version: '3' + +tasks: + default: + sources: + - foo.txt + - bar.txt + cmds: + - for: sources + cmd: cat {{ .ITEM }} +``` + +This will also work if you use globbing syntax in your sources. For example, if +you specify a source for `*.txt`, the loop will iterate over all files that +match that glob. + +### Looping over variables + +To loop over the contents of a variable, you simply need to specify the variable +you want to loop over. By default, 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 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 }} +``` + +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' +``` + ## Forwarding CLI arguments to commands If `--` is given in the CLI, all following parameters are added to a special