Skip to content

Any variables experiment #1415

Closed
@pd93

Description

Note

This experiment has been released and is now generally available since Task v3.37.0. This issue is kept for historical purposes only. For up-to-date information, you can read our blog post or check the variables documentation.

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:

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    area: variablesChanges related to variables.experiment: releasedExperimental feature - Now the default behavior in Task and is no longer an experiment.

    Projects

    • Status

      Released

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions