From 43ea721ba06e1b6f3e8354cf113682fc4655a039 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:19:42 +0200 Subject: [PATCH 01/14] Use more compatible shebang --- Taskfile.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.template b/Taskfile.template index e3e7967..a2fb613 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -1,5 +1,5 @@ -#!/bin/bash PATH=./node_modules/.bin:$PATH +#!/usr/bin/env bash function install { echo "install task not implemented" From b288a370aa34e99a72f5302d61dde53986913a84 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:20:53 +0200 Subject: [PATCH 02/14] Remove node_modules path loading --- Taskfile.template | 1 - 1 file changed, 1 deletion(-) diff --git a/Taskfile.template b/Taskfile.template index a2fb613..9c4d59a 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -1,4 +1,3 @@ -PATH=./node_modules/.bin:$PATH #!/usr/bin/env bash function install { From 3f3fc85519cdffba23548670f432fb206c472a26 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:21:20 +0200 Subject: [PATCH 03/14] Use Bash strict mode --- Taskfile.template | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index 9c4d59a..eeffbdd 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -1,8 +1,8 @@ #!/usr/bin/env bash -function install { - echo "install task not implemented" -} +# Unofficial Bash Strict Mode; http://redsymbol.net/articles/unofficial-bash-strict-mode/ +set -euo pipefail +IFS=$'\n\t' function build { echo "build task not implemented" From 3a2da989c2371779495abc801761d992615db42f Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:23:13 +0200 Subject: [PATCH 04/14] Replace placeholder functions with utility functions and a single example --- Taskfile.template | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index eeffbdd..a5559e5 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -4,23 +4,43 @@ set -euo pipefail IFS=$'\n\t' -function build { - echo "build task not implemented" -} -function start { - echo "start task not implemented" +function hello() { + # Comments are not shown in the help message + : "Say hello" # But this pseudo-comment _is_ shown as the help text for the function + : " Usage: hello [name]" + WHO="${1:-World}" + echo "Hello ${WHO}!" } -function default { - start +## +# The functions below are utility functions that can be used in your Taskfile +# Write your functions above these lines. +## + +function _parallel() { + # Run commands in parallel + # If any of the commands fail, the whole function exits + # with a non-zero exit code. + # Usage: _parallel "cmd1" "cmd2" "cmd3" + + PIDS=() + for arg in "$@"; do + $arg & + PIDS+=($!) + done + for pid in ${PIDS[*]}; do + wait $pid + done } function help { - echo "$0 " - echo "Tasks:" - compgen -A function | cat -n + # This function prints the help message, automatically + # generated from the functions in this file + : "This help message" + compgen -A function | grep -vE "^_" | while read -r name ; do + paste <(printf '\033[36m%-15s\033[0m' "$name") <(type "$name" | sed -nEe 's/^[[:space:]]*: ?"(.*)";/\1/p') + done } -TIMEFORMAT="Task completed in %3lR" -time ${@:-default} +"${@:-help}" # Run the command, or print help by default From 684eae41b282f582131e418dd2a5ad984fc53177 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:34:58 +0200 Subject: [PATCH 05/14] fixup! Use more compatible shebang --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 970d09d..85e79e0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repository contains the default Taskfile template for getting started in your own projects. A Taskfile is a bash (or zsh etc.) script that follows a specific format. It's called `Taskfile`, sits in the root of your project (alongside your package.json) and contains the tasks to build your project. ```sh -#!/bin/bash +#!/usr/bin/env bash PATH=./node_modules/.bin:$PATH function install { From 7ae0223e8bc18a6a0c49e8b5b595aa61cd6e0f8b Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:35:19 +0200 Subject: [PATCH 06/14] Fix shellcheck suggestions --- Taskfile.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index a5559e5..a856469 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -29,8 +29,8 @@ function _parallel() { $arg & PIDS+=($!) done - for pid in ${PIDS[*]}; do - wait $pid + for pid in "${PIDS[@]}"; do + wait "$pid" done } From 1059a92f74ec519076fca66e8e88b006c84aedf5 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:37:46 +0200 Subject: [PATCH 07/14] fixup! Replace placeholder functions with utility functions and a single example --- Taskfile.template | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index a856469..1dcb5cc 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -8,9 +8,7 @@ IFS=$'\n\t' function hello() { # Comments are not shown in the help message : "Say hello" # But this pseudo-comment _is_ shown as the help text for the function - : " Usage: hello [name]" - WHO="${1:-World}" - echo "Hello ${WHO}!" + echo "Hello ${1:-World}!" } ## From 3d7dc9241a0cadd846e88a34a30155372df3173c Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:58:16 +0200 Subject: [PATCH 08/14] Update README --- README.md | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 85e79e0..3560090 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ function default { } function help { - echo "$0 " - echo "Tasks:" - compgen -A function | cat -n + : "This help message" + compgen -A function | grep -vE "^_" | while read -r name ; do + paste <(printf '\033[36m%-15s\033[0m' "$name") <(type "$name" | sed -nEe 's/^[[:space:]]*: ?"(.*)";/\1/p') + done } -TIMEFORMAT="Task completed in %3lR" -time ${@:-default} +${@:-default} ``` And to run a task: @@ -46,13 +46,12 @@ And to run a task: Asset Size Chunks Chunk Names index.js 1.96 MB 0 [emitted] index + 353 hidden modules - Task completed in 0m5.008s ## Install To "install", add the following to your `.bashrc` or `.zshrc` (or `.whateverrc`): # Quick start with the default Taskfile template - alias run-init="curl -so Taskfile https://raw.githubusercontent.com/adriancooney/Taskfile/master/Taskfile.template && chmod +x Taskfile" + alias run-init="curl -so Taskfile https://raw.githubusercontent.com/leukeleu/Taskfile/main/Taskfile.template && chmod +x Taskfile" # Run your tasks like: run alias run=./Taskfile @@ -66,12 +65,8 @@ Open your directory and run `run-init` to add the default Taskfile template to y Open the `Taskfile` and add your tasks. To run tasks, use `run`: $ run help - ./Taskfile - Tasks: - 1 build - 2 build-all - 3 help - Task completed in 0m0.005s + hello Say hello + help This help message ## Techniques ### Arguments @@ -174,6 +169,17 @@ And execute the `build-all` task: built web built mobile +**There is a caveat** with this approach. If any background task fails, the build-all task will still exit with a 0 exit code. To fix this, the template includes a helper function called `_parallel` that will run tasks in parallel and exit with the exit code of the first task to fail. You can use it like so: + +```sh +function build-all { + _parallel "build web" "build mobile" +} +``` + +```sh + + ### Default task To make a task the default task called when no arguments are passed, we can use bash’s default variable substitution `${VARNAME:-}` to return `default` if `$@` is empty. @@ -198,7 +204,7 @@ Now when we run `./Taskfile`, the `default` function is called. ### Runtime Statistics To add some nice runtime statistics like Gulp so you can keep an eye on build times, we use the built in `time` and pass if a formatter. -```js +```sh #!/bin/bash PATH=./node_modules/.bin:$PATH @@ -222,17 +228,14 @@ And if we execute the `build` task: Task completed in 0m1.008s ### Help -The final addition I recommend adding to your base Taskfile is the task which emulates, in a much more basic fashion, (with no arguments). It prints out usage and the available tasks in the Taskfile to show us what tasks we have available to ourself. +The final addition I recommend adding to your base Taskfile is the `help` task which emulates, in a much more basic fashion, (with no arguments). It prints out usage and the available tasks in the Taskfile to show us what tasks we have available to ourselves. -The `compgen -A function` is a [bash builtin](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html) that will list the functions in our Taskfile (i.e. tasks). This is what it looks like when we run the task: +The `compgen -A function` is a [bash builtin](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html) that will list the functions in our Taskfile (i.e. tasks). This is what it looks like when we run the task: $ ./Taskfile help - ./Taskfile - Tasks: - 1 build - 2 default - 3 help - Task completed in 0m0.005s + hello Say hello + help This help message + ### `task:` namespace If you find you need to breakout some code into reusable functions that aren't tasks by themselves and don't want them cluttering your `help` output, you can introduce a namespace to your task functions. Bash is pretty lenient with it's function names so you could, for example, prefix a task function with `task:`. Just remember to use that namespace when you're calling other tasks and in your `task:$@` entrypoint! From 10452651f5cd9f0e3e770c155b0a1b14646141c8 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 18 Oct 2023 23:59:46 +0200 Subject: [PATCH 09/14] Restore space as a field separator, fixing quoted commands as arguments Allows `_parallel "build one" "build two"`. --- Taskfile.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.template b/Taskfile.template index 1dcb5cc..714eee0 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -2,7 +2,7 @@ # Unofficial Bash Strict Mode; http://redsymbol.net/articles/unofficial-bash-strict-mode/ set -euo pipefail -IFS=$'\n\t' +IFS=$' \n\t' function hello() { From f70bb67703c0dfaa2140b62fd88ce2d8885f6756 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 15 Nov 2023 13:09:35 +0100 Subject: [PATCH 10/14] Update Taskfile.template Choose parentheses-less function signature style --- Taskfile.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index 714eee0..1ecad01 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -5,7 +5,7 @@ set -euo pipefail IFS=$' \n\t' -function hello() { +function hello { # Comments are not shown in the help message : "Say hello" # But this pseudo-comment _is_ shown as the help text for the function echo "Hello ${1:-World}!" @@ -16,7 +16,7 @@ function hello() { # Write your functions above these lines. ## -function _parallel() { +function _parallel { # Run commands in parallel # If any of the commands fail, the whole function exits # with a non-zero exit code. From e42e28978e779875a9e72334a1865f1e475ff178 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Tue, 24 Oct 2023 14:43:28 +0200 Subject: [PATCH 11/14] Lintfix with shfmt --- Taskfile.template | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Taskfile.template b/Taskfile.template index 1ecad01..4f99d12 100755 --- a/Taskfile.template +++ b/Taskfile.template @@ -24,11 +24,11 @@ function _parallel { PIDS=() for arg in "$@"; do - $arg & - PIDS+=($!) + $arg & + PIDS+=($!) done for pid in "${PIDS[@]}"; do - wait "$pid" + wait "$pid" done } @@ -36,9 +36,9 @@ function help { # This function prints the help message, automatically # generated from the functions in this file : "This help message" - compgen -A function | grep -vE "^_" | while read -r name ; do - paste <(printf '\033[36m%-15s\033[0m' "$name") <(type "$name" | sed -nEe 's/^[[:space:]]*: ?"(.*)";/\1/p') - done + compgen -A function | grep -vE "^_" | while read -r name; do + paste <(printf '\033[36m%-15s\033[0m' "$name") <(type "$name" | sed -nEe 's/^[[:space:]]*: ?"(.*)";/\1/p') + done } -"${@:-help}" # Run the command, or print help by default +"${@:-help}" # Run the command, or print help by default From 8e1ac1d0eaa6f191046c071a56b82bf6fc4420ea Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 15 Nov 2023 13:15:06 +0100 Subject: [PATCH 12/14] Run ShellCheck in CI --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b645754 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,6 @@ +on: + push: + +jobs: + - name: ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 From 655b2d977a60cc3bc6da0915e078974616310542 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 15 Nov 2023 13:25:07 +0100 Subject: [PATCH 13/14] Fix workflow syntax --- .github/workflows/test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b645754..23b6897 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,5 +2,8 @@ on: push: jobs: - - name: ShellCheck - uses: ludeeus/action-shellcheck@2.0.0 + test: + runs-on: ubuntu-latest + steps: + - name: ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 From 86da363856573cdfc410b212dd59e81094411ee1 Mon Sep 17 00:00:00 2001 From: Wouter de Vries Date: Wed, 15 Nov 2023 13:30:05 +0100 Subject: [PATCH 14/14] Fix docs --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 3560090..869fc00 100644 --- a/README.md +++ b/README.md @@ -177,9 +177,6 @@ function build-all { } ``` -```sh - - ### Default task To make a task the default task called when no arguments are passed, we can use bash’s default variable substitution `${VARNAME:-}` to return `default` if `$@` is empty.