This commit is contained in:
Andrey Nering
2025-04-21 13:50:40 -03:00
parent 0a6cd1ee42
commit c2123dc016
15 changed files with 686 additions and 472 deletions

View File

@@ -1,245 +0,0 @@
---
slug: /experiments/map-variables/
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Map Variables (#1585)
:::caution
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.
:::
Currently, Task supports all variable types except for maps. This experiment
adds two different proposals for map variables. Click on the tabs below to
switch between them.
<Tabs defaultValue="1" queryString="proposal"
values={[
{label: 'Proposal 1', value: '1'},
{label: 'Proposal 2', value: '2'}
]}>
<TabItem value="1">
:::warning
This experiment proposal breaks the following functionality:
- Dynamically defined variables (using the `sh` keyword)
:::
:::info
To enable this experiment, set the environment variable:
`TASK_X_MAP_VARIABLES=1`. Check out [our guide to enabling experiments
][enabling-experiments] for more information.
:::
This proposal removes support for the `sh` and `ref` keywords in favour of a new
syntax for dynamically defined variables and references. This allows you to
define a map directly as you would for any other type:
```yaml
version: 3
tasks:
foo:
vars:
FOO: {a: 1, b: 2, c: 3} # <-- Directly defined map on the `FOO` key
cmds:
- 'echo {{.FOO.a}}'
```
## Migration
Taskfiles with dynamically defined variables via the `sh` subkey or references
defined with `ref` will no longer work with this experiment enabled. In order to
keep using these features, you will need to migrate your Taskfile to use the new
syntax.
### Dynamic Variables
Previously, you had to define dynamic variables using the `sh` subkey. With this
experiment enabled, you will need to remove the `sh` subkey and define your
command as a string that begins with a `$`. This will instruct Task to interpret
the string as a command instead of a literal value and the variable will be
populated with the output of the command. For example:
<Tabs defaultValue="2"
values={[
{label: 'Before', value: '1'},
{label: 'After', value: '2'}
]}>
<TabItem value="1">
```yaml
version: 3
tasks:
foo:
vars:
CALCULATED_VAR:
sh: 'echo hello'
cmds:
- 'echo {{.CALCULATED_VAR}}'
```
</TabItem>
<TabItem value="2">
```yaml
version: 3
tasks:
foo:
vars:
CALCULATED_VAR: '$echo hello' # <-- Prefix dynamic variable with a `$`
cmds:
- 'echo {{.CALCULATED_VAR}}'
```
</TabItem></Tabs>
### References
<Tabs defaultValue="2"
values={[
{label: 'Before', value: '1'},
{label: 'After', value: '2'}
]}>
<TabItem value="1">
```yaml
version: 3
tasks:
foo:
vars:
VAR: 42
VAR_REF:
ref: '.FOO'
cmds:
- 'echo {{.VAR_REF}}'
```
</TabItem>
<TabItem value="2">
```yaml
version: 3
tasks:
foo:
vars:
VAR: 42
VAR_REF: '#.FOO' # <-- Prefix reference with a `#`
cmds:
- 'echo {{.VAR_REF}}'
```
</TabItem></Tabs>
If your current Taskfile contains a string variable that begins with a `$` or a
`#`, you will now need to escape it with a backslash (`\`) to stop Task from
interpreting it as a command or reference.
</TabItem>
<TabItem value="2">
:::info
To enable this experiment, set the environment variable:
`TASK_X_MAP_VARIABLES=2`. Check out [our guide to enabling experiments
][enabling-experiments] for more information.
:::
This proposal maintains backwards-compatibility and the `sh` subkey and adds
another new `map` subkey for defining map variables:
```yaml
version: 3
tasks:
foo:
vars:
FOO:
map: {a: 1, b: 2, c: 3} # <-- Defined using the `map' subkey instead of directly on 'FOO'
BAR: true # <-- Other types of variables are still defined directly on the key
BAZ:
sh: 'echo Hello Task' # <-- The `sh` subkey is still supported
QUX:
ref: '.BAZ' # <-- The `ref` subkey is still supported
cmds:
- 'echo {{.FOO.a}}'
```
</TabItem></Tabs>
## Looping over maps
This experiment also adds support for looping over maps using the `for` keyword,
just like arrays. In addition to the `{{.ITEM}}` variable being populated when
looping over a map, we also make an additional `{{.KEY}}` variable available
that holds the string value of the map key.
<Tabs defaultValue="1" queryString="proposal"
values={[
{label: 'Proposal 1', value: '1'},
{label: 'Proposal 2', value: '2'}
]}>
<TabItem value="1">
```yaml
version: 3
tasks:
foo:
vars:
MAP: {a: 1, b: 2, c: 3}
cmds:
- for:
var: MAP
cmd: 'echo "{{.KEY}}: {{.ITEM}}"'
```
</TabItem>
<TabItem value="2">
```yaml
version: 3
tasks:
foo:
vars:
map:
MAP: {a: 1, b: 2, c: 3}
cmds:
- for:
var: MAP
cmd: 'echo "{{.KEY}}: {{.ITEM}}"'
```
:::note
Remember that maps are unordered, so
the order in which the items are looped over is random.
:::
</TabItem></Tabs>
{/* prettier-ignore-start */}
[enabling-experiments]: ./experiments.mdx#enabling-experiments
{/* prettier-ignore-end */}

View File

@@ -2,6 +2,9 @@
slug: /experiments/remote-taskfiles/
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Remote Taskfiles (#1317)
:::caution
@@ -20,33 +23,151 @@ To enable this experiment, set the environment variable:
:::
This experiment allows you to specify a remote Taskfile URL when including a
Taskfile. For example:
:::danger
Never run remote Taskfiles from sources that you do not trust.
:::
```yaml
version: '3'
This experiment allows you to use Taskfiles which are stored in remote
locations. This applies to both the root Taskfile (aka. Entrypoint) and also
when including Taskfiles.
includes:
my-remote-namespace: https://raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml
```
Task uses "nodes" to reference remote Taskfiles. There are a few different types
of node which you can use:
This works exactly the same way that including a local file does. Any tasks in
the remote Taskfile will be available to run from your main Taskfile via the
namespace `my-remote-namespace`. For example, if the remote file contains the
following:
<Tabs groupId="method" queryString>
<TabItem value="http" label="HTTP/HTTPS">
`https://raw.githubusercontent.com/go-task/task/main/website/static/Taskfile.yml`
This is the most basic type of remote node and works by downloading the file
from the specified URL. The file must be a valid Taskfile and can be of any
name. If a file is not found at the specified URL, Task will append each of the
[supported file names][supported-file-names] in turn until it finds a valid
file. If it still does not find a valid Taskfile, an error is returned.
</TabItem>
<TabItem value="git-http" label="Git over HTTP">
`https://github.com/go-task/task.git//website/static/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over
HTTP/HTTPS. The first part of the URL is the base URL of the Git repository.
This is the same URL that you would use to clone the repo over HTTP.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default branch
will be used.
</TabItem>
<TabItem value="git-ssh" label="Git over SSH">
`git@github.com/go-task/task.git//website/static/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over SSH.
The first part of the URL is the user and base URL of the Git repository. This
is the same URL that you would use to clone the repo over SSH.
To use Git over SSH, you need to make sure that your SSH agent has your private
SSH keys added so that they can be used during authentication.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default branch
will be used.
</TabItem>
</Tabs>
Task has an [example remote Taskfile][example-remote-taskfile] in our repository
that you can use for testing and that we will use throughout this document:
```yaml
version: '3'
tasks:
hello:
silent: true
default:
cmds:
- echo "Hello from the remote Taskfile!"
- task: hello
hello:
cmds:
- echo "Hello Task!"
```
and you run `task my-remote-namespace:hello`, it will print the text: "Hello
from the remote Taskfile!" to your console.
## Specifying a remote entrypoint
By default, Task will look for one of the [supported file
names][supported-file-names] on your local filesystem. If you want to use a
remote file instead, you can pass its URI into the `--taskfile`/`-t` flag just
like you would to specify a different local file. For example:
<Tabs groupId="method" queryString>
<TabItem value="http" label="HTTP/HTTPS">
```shell
$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/static/Taskfile.yml
task: [hello] echo "Hello Task!"
Hello Task!
```
</TabItem>
<TabItem value="git-http" label="Git over HTTP">
```shell
$ task --taskfile https://github.com/go-task/task.git//website/static/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
</TabItem>
<TabItem value="git-ssh" label="Git over SSH">
```shell
$ task --taskfile git@github.com/go-task/task.git//website/static/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
</TabItem>
</Tabs>
## Including remote Taskfiles
Including a remote file works exactly the same way that including a local file
does. You just need to replace the local path with a remote URI. Any tasks in
the remote Taskfile will be available to run from your main Taskfile.
<Tabs groupId="method" queryString>
<TabItem value="http" label="HTTP/HTTPS">
```yaml
version: '3'
includes:
my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/static/Taskfile.yml
```
</TabItem>
<TabItem value="git-http" label="Git over HTTP">
```yaml
version: '3'
includes:
my-remote-namespace: https://github.com/go-task/task.git//website/static/Taskfile.yml?ref=main
```
</TabItem>
<TabItem value="git-ssh" label="Git over SSH">
```yaml
version: '3'
includes:
my-remote-namespace: git@github.com/go-task/task.git//website/static/Taskfile.yml?ref=main
```
</TabItem>
</Tabs>
```shell
$ task my-remote-namespace:hello
task: [hello] echo "Hello Task!"
Hello Task!
```
### Authenticating using environment variables
The Taskfile location is processed by the templating system, so you can
reference environment variables in your URL if you need to add authentication.
@@ -59,19 +180,6 @@ includes:
my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml
```
`TOKEN=my-token task my-remote-namespace:hello` will be resolved by Task to
`https://my-token@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml`
## Git nodes
You can also include a Taskfile from a Git node. We currently support ssh-style and http / https addresses like `git@example.com/foo/bar.git//Taskfiles.yml?ref=v1` and `https://example.com/foo/bar.git//Taskfiles.yml?ref=v1`.
You need to follow this pattern : `<baseUrl>.git//<path>?ref=<ref>`.
The `ref` parameter, optional, can be a branch name or a tag, if not provided it'll pick up the default branch.
The `path` is the path to the Taskfile in the repository.
If you want to use the SSH protocol, you need to make sure that your ssh-agent has your private ssh keys added so that they can be used during authentication.
## Security
Running commands from sources that you do not control is always a potential
@@ -104,20 +212,26 @@ flag. Before enabling this flag, you should:
Task currently supports both `http` and `https` URLs. However, the `http`
requests will not execute by default unless you run the task with the
`--insecure` flag. This is to protect you from accidentally running a remote
Taskfile that is via an unencrypted connection. Sources that are not protected
by TLS are vulnerable to [man-in-the-middle attacks][man-in-the-middle-attacks]
and should be avoided unless you know what you are doing.
Taskfile that is downloaded via an unencrypted connection. Sources that are not
protected by TLS are vulnerable to [man-in-the-middle
attacks][man-in-the-middle-attacks] and should be avoided unless you know what
you are doing.
## Caching & Running Offline
Whenever you run a remote Taskfile, the latest copy will be downloaded from the
internet and cached locally. If for whatever reason, you lose access to the
internet, you will still be able to run your tasks by specifying the `--offline`
flag. This will tell Task to use the latest cached version of the file instead
of trying to download it. You are able to use the `--download` flag to update
the cached version of the remote files without running any tasks. You are able
to use the `--clear-cache` flag to clear all cached version of the remote files
without running any tasks.
internet and cached locally. This cached file will be used for all future
invocations of the Taskfile until the cache expires. Once it expires, Task will
download the latest copy of the file and update the cache. By default, the cache
is set to expire immediately. This means that Task will always fetch the latest
version. However, the cache expiry duration can be modified by setting the
`--expiry` flag.
If for any reason you lose access to the internet or you are running Task in
offline mode (via the `--offline` flag or `TASK_OFFLINE` environment variable),
Task will run the any available cached files _even if they are expired_. This
means that you should never be stuck without the ability to run your tasks as
long as you have downloaded a remote Taskfile at least once.
By default, Task will timeout requests to download remote files after 10 seconds
and look for a cached copy instead. This timeout can be configured by setting
@@ -129,7 +243,14 @@ By default, the cache is stored in the Task temp directory, represented by the
override the location of the cache by setting the `TASK_REMOTE_DIR` environment
variable. This way, you can share the cache between different projects.
You can force Task to ignore the cache and download the latest version
by using the `--download` flag.
You can use the `--clear-cache` flag to clear all cached remote files.
{/* prettier-ignore-start */}
[enabling-experiments]: ./experiments.mdx#enabling-experiments
[man-in-the-middle-attacks]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
[supported-file-names]: https://taskfile.dev/usage/#supported-file-names
[example-remote-taskfile]: https://raw.githubusercontent.com/go-task/task/main/website/static/Taskfile.yml
{/* prettier-ignore-end */}