From f693484b986972c67a91112f0b287f39b9d5bf1f Mon Sep 17 00:00:00 2001 From: Michele Cereda Date: Mon, 3 Mar 2025 21:46:31 +0100 Subject: [PATCH] chore(task): expand on concepts and usage --- knowledge base/task.md | 208 +++++++++++++++++++++++++++++++++++++---- templates/Taskfile.yml | 7 ++ 2 files changed, 198 insertions(+), 17 deletions(-) diff --git a/knowledge base/task.md b/knowledge base/task.md index b559f81..40f32df 100644 --- a/knowledge base/task.md +++ b/knowledge base/task.md @@ -3,6 +3,12 @@ Task runner aiming to be simpler and easier to use than [GNU Make]. 1. [TL;DR](#tldr) +1. [Usage](#usage) +1. [Variables](#variables) +1. [Call other tasks](#call-other-tasks) + 1. [Call root tasks from non-flattened included files](#call-root-tasks-from-non-flattened-included-files) +1. [Troubleshooting](#troubleshooting) + 1. [Dry run does not print the commands that would be executed](#dry-run-does-not-print-the-commands-that-would-be-executed) 1. [Further readings](#further-readings) 1. [Sources](#sources) @@ -12,7 +18,7 @@ Taskfiles are Task's Makefile counterpart.
Taskfiles are written in YAML. Task leverages `mvdan.cc/sh` to run commands, which is a native Go shell interpreter.
-This allows to write `sh`/`bash` commands and have them work even where `sh` or `bash` are usually not available (e.g.: +It allows to write `sh`/`bash` commands and have them work even where `sh` or `bash` are usually not available (e.g.: Windows) as long as any called executable is available in `PATH`. Pros: @@ -30,6 +36,12 @@ Cons: That makes them very much similar to \[[Gitlab] / [Azure Devops]]'s pipelines, and if one has any experience with them one knows what a pain that can be. +Uses Go's [text/template] package to interpolate values. + +Environment variables (`env: {}, dotenv: []`) are available in the shell used by commands.
+Variables (`vars: {}`) are **only** available to Task while executing templates, but **will default to environment +variables** with the same name. +
Setup @@ -46,39 +58,200 @@ zypper install 'https://github.com/go-task/task/releases/download/v3.39.2/task_l task --completion 'fish' > ~/'.config/fish/completions/task.fish' task --completion 'zsh' > '/usr/local/share/zsh/site-functions/_task' task --completion 'bash' > '/etc/bash_completion.d/task' + +# Create a new 'Taskfile.yml' file in the current folder. +task --init ```
Usage +```sh +# Run tasks. +# No tasks given --> assumed one named 'default' +task +task 'assets' +task -v 'build:python' 'deploy:app' + +# Simulate running tasks. +task -n 'bootstrap' +task --dry --verbose 'lint' 'validate:ansible' +``` + +
+ +## Usage + 1. Create a file called `Taskfile.yml`, `taskfile.yml`, `Taskfile.yaml`, `taskfile.yaml`, `Taskfile.dist.yml`, `taskfile.dist.yml`, `Taskfile.dist.yaml`, or `taskfile.dist.yaml` (ordered by priority) in the root of one's - project.
- The `cmds` keys shall contain the commands for their own tasks: - - ```yaml - version: '3' - - tasks: - build: - cmds: - - go build -v -i main.go - - assets: - cmds: - - esbuild --bundle --minify css/index.css > public/bundle.css - ``` + project. 1. Run tasks by their name: ```sh - task 'assets' 'build' + task 'assets' 'build:python' task --dry 'bootstrap' ``` If task names are omitted, a task named `default` will be assumed. +## Variables + +Set **environment** variables at global or task level with `env: {}`.
+They are made available in the shell used by commands. + +
+ +```yml +env: + SOME_VAR: some DEFAULT value +tasks: + env_vars:test: + env: + SOME_VAR: some value + cmds: + - echo $SOME_VAR +``` + +
+ +**Exported** and **command-specific** shell variables **take precedence** over the ones defined in the Taskfile. + +
+ +```sh +$ task env_vars:test +some value + +$ set SOME_VAR 'some OTHER value' +$ task env_vars:test +some value + +$ set -x SOME_VAR 'some OTHER value' +$ task env_vars:test +some OTHER value + +$ SOME_VAR='some EPHEMERAL value' task env_vars:test +some EPHEMERAL value +``` + +
+ +Task accepts setting environment variables **inside** the command itself like `make` due to some shells not supporting +the usual syntax. + +
+ +```sh +# These are equivalent +CONTENT='Hello, World!' FILE=file.txt MESSAGE="All done!" task write-file print +task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!" +``` + +
+ +Include **environment** variables from `.env`-like files at global or task level with `dotenv: []`.
+Non-existing files are **ignored** in a similar manner to `make`'s `-include` directive (with the prefixed dash). + +
+ +```yml +dotenv: + - .env + - .env.local +tasks: + env_vars:test: + dotenv: + - .env.task + - .env.task.local +``` + +
+ +Environment variables set in `env: {}` **take precedence** over the ones loaded from `dotenv` **at the same level**. + +```mermaid +graph LR + gd["`dotenv: []`"] --- ge["`env: {}`"] + ge["`env: {}`"] --- td["`task.dotenv: []`"] + td["`task.dotenv: []`"] --- te["`task.env: {}`"] + te["`task.env: {}`"] --- se["`shell.export`"] + se["`shell.export`"] --- ce["`command.env`"] +``` + +
+ +Variables (`vars: {}`) are **only** available to Task while executing templates, but **will default to environment +variables** with the same name. + +Task execution looks for variables in the following order (first-come-first-served): + +- Variables declared in the task's definition. +- Variables provided when calling a task from another. +- Variables defined in included Taskfiles. +- Variables provided when including Taskfiles. +- Global variables. +- Environment variables. + +```mermaid +graph LR + ev["`environment variables`"] --- gv["`vars: {}`"] + gv["`vars: {}`"] --- iv["`includes[].vars: {}`"] + iv["`includes[].vars: {}`"] --- it["`includes[]`"] + it["`includes[]`"] --- tc["`task.cmd.'task'`"] + tc["`task.cmd.'task'`"] --- te["`task.env`"] +``` + +## Call other tasks + +Use `task:` followed by the call**ed** task name as the command in the call**ing** task. + +```yml +tasks: + task:being:called: { … } + task:calling: + cmd: task: task:being:called +``` + +### Call root tasks from non-flattened included files + +Refer an empty namespace by prepending the name of the task with `:`. + +```yml +# $ROOT/Taskfile.yml +includes: + subproject: + taskfile: subproject + dir: subproject +tasks: + task:of:interest: { … } +``` + +```yml +# $ROOT/subproject/Taskfile.yml +tasks: + some:task: + cmd: + task: :task:of:interest +``` + +## Troubleshooting + +### Dry run does not print the commands that would be executed + +
+ Root cause + +Command simulations do **not** print commands to output when setting `silent: true` at any level. + +
+ +
+ Solution + +Force the print using `-v, --verbose` when `silent` is set to `true`, or set it to `false` at task level. +
## Further readings @@ -112,3 +285,4 @@ task --completion 'bash' > '/etc/bash_completion.d/task' [demystification of taskfile variables]: https://medium.com/@TianchenW/demystification-of-taskfile-variables-29b751950393 [stop using makefile (use taskfile instead)]: https://dev.to/calvinmclean/stop-using-makefile-use-taskfile-instead-4hm9 +[text/template]: https://pkg.go.dev/text/template diff --git a/templates/Taskfile.yml b/templates/Taskfile.yml index fe31ab8..2b1c000 100644 --- a/templates/Taskfile.yml +++ b/templates/Taskfile.yml @@ -26,6 +26,13 @@ tasks: - task: python:update-venv - npm update --save + env:debug: + desc: print the current shell environment + summary: Print the current shell environment + cmds: + - printenv | sort + - set | sort + python:venv:create: vars: PYTHON_VERSION: '{{ .PYTHON_VERSION | default 3.12}}'