task
task copied to clipboard
Any variables experiment
[!WARNING] All experimental features are subject to breaking changes and/or removal at any time. We strongly recommend that you do not use these features in a production environment. They are intended for testing and feedback only.
[!NOTE] You can view the Any Variables experiment documentation on our website, including instructions on how to enable/disable it.
Context
This experiment attempts to solve the problems originally described by #140.
Currently, all Task variables are strings. You can define a variable as a YAML string
, bool
, int
, float
or null
value. However, when task interprets it, it will be decoded as a string regardless of the input type.
For example, the following Taskfile will always output "foo" even when BOOL
is false
because the variable is being interpreted as a string and an if
statement evaluates to true
when the string is not empty:
version: 3
tasks:
foo:
vars:
BOOL: false
cmds:
- '{{ if .BOOL }}echo foo{{ end}}'
Lists are also interpreted as strings and this has led to some annoying workarounds in the codebase. For example, the for
feature is great for running a task multiple times with different variables. However, if you want to loop over an arbitrary list of strings, you have to define the list as a delimiter separated string and then split it by specifying the delimiter in the for
statement. For example:
version: 3
tasks:
foo:
vars:
LIST: 'foo,bar,baz'
cmds:
- for:
var: LIST
split: ','
cmd: echo {{ .ITEM }}
This could be simplified if we supported variables as lists:
version: 3
tasks:
foo:
vars:
LIST: [foo, bar, baz]
cmds:
- for:
var: LIST
cmd: echo {{ .ITEM }}
Proposal
We propose to change the type of internal Task variables to any
(otherwise known as an empty interface{}
in Go). This will allow users to define variables as any type they want, and Task will interpret them properly when used in tasks. The following types should be supported:
-
string
-
bool
-
int
-
float
-
array
-
map
Adding support for these types is relatively simple by itself. However, there a few changes that will be needed to make the rest of Task's features work nicely with the new variable types:
- [ ]
for
should support iterating over arrays (and maybe maps?) https://github.com/go-task/task/pull/1436 - [ ]
sh
needs to be removed and replaced with a new syntax for dynamically defined variables (see backwards compatibility) - [ ] ...
Backwards Compatibility
The current implementation of Task variables allows for dynamic variables to be specified by using the sh
subkey. For example:
version: 3
task:
foo:
vars:
CALCULATED_VAR:
sh: 'echo hello'
cmds:
- 'echo {{ .CALCULATED_VAR }}'
Running task foo
will output the following:
task: [foo] echo hello
hello
Since we are adding support for map variables, this syntax will conflict and can no longer be supported. Instead, we should detect string variables that begin with a $
and interpret them as a command to run. For example:
version: 3
task:
foo:
vars:
CALCULATED_VAR: '$echo hello'
cmds:
- 'echo {{ .CALCULATED_VAR }}'
If a user wants a string variable that starts with $
, they can escape it with a backslash: \$
.
Removing the sh
subkey will break any Taskfiles that currently use it and it is possible that the new syntax will also break existing taskfiles that have variables that start with $
. For this reason, the functionality in this proposal will stay as an experiment until at least the next major version of Task.