./task

Run any project.

.forgejo/workflows/build.yml Vercel


The task file is a simple bash script and standardized interface for any software project.

It is to be understood as a software development pattern to standardize the installation, configuration and execution of different software frameworks.

  • Package Management: Install and configure software and tools with ease.
  • Docker Build: Build and publish Docker imgages for your project.
  • KeePass / Pass: Store and load secrets from KeePass and pass.
  • .env / dotenv: Manage multiple dotenv files for your projects.
  • CI Pipelines: Simplify CI pipelines by making the executed task reproducable.
  • Helper scripts: There are many examples and commands that make scripting easier.

# Specification

The specification is a short guide to set up a task file for a Python project.

Create a file task in your project.

touch task

Ensure it is executable.

chmod +x task

First add the bash shebang.

#!/usr/bin/env bash

Then append the abort on error setting.

set -e

Load environment variables from the .env file.

if [[ -a ".env" ]]; then
    source .env
fi

Add a help function.

help-table() {
    local -a rows
    local max_cmd=7 max_opt=6 max_desc=11

    rows+=("Command|Option|Description")
    rows+=("help|[grep]|Show help for commands.")
    rows+=("install||Setup the local environment.")
    rows+=("lint||Run pre-commit and update index.html.")
    rows+=("version||Show version of required tools.")

    for row in "${rows[@]}"; do
        IFS='|' read -r cmd opt desc <<< "$row"
        (( ${#cmd} > max_cmd )) && max_cmd=${#cmd}
        (( ${#opt} > max_opt )) && max_opt=${#opt}
        (( ${#desc} > max_desc )) && max_desc=${#desc}
    done

    printf '| %-*s | %-*s | %-*s |\n' \
        "$max_cmd" "Command" \
        "$max_opt" "Option" \
        "$max_desc" "Description"

    printf '|-%*s-|-%*s-|-%*s-|\n' \
        "$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
        "$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
        "$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"

    for row in "${rows[@]:1}"; do
        IFS='|' read -r cmd opt desc <<< "$row"
        printf '| %-*s | %-*s | %-*s |\n' \
            "$max_cmd" "$cmd" \
            "$max_opt" "$opt" \
            "$max_desc" "$desc"
    done
}

help() {
    echo
    if [[ -n "$1" ]]; then
        help-table | grep -i "$1" | column -t -s'|'
    else
        echo 'task <command> [options]'
        echo
        echo 'commands:'
        echo
        help-table
    fi
    echo
}

Setup the command functions.

install() {
    echo 'Setup venv and install python dependencies'
    uv venv env
    source env/bin/activate
    uv pip install pre-commit
}

lint() {
    source env/bin/activate

    echo 'Run pre-commit'
    pre-commit run --all-file
}

version() {
    uv --version
}

Finish the task file with command switch cases.

if [[ "$1" == *","* ]]; then
    # Split comma-separated commands
    IFS=',' read -ra COMMANDS <<< "$1"
    for cmd in "${COMMANDS[@]}"; do
        # Trim whitespace
        cmd=$(echo "$cmd" | xargs)
        if declare -f "$cmd" > /dev/null; then
            "$cmd"
        else
            echo "Unknown command: $cmd"
            help
            exit 1
        fi
    done
elif declare -f "$1" > /dev/null; then
    "$1" "${@:2}"
else
    case "$1" in
        all)
            install
            lint
            ;;
        *)
            echo "Unknown command: $1"
            help
            exit 1
            ;;
    esac
fi

These are the main parts of every task file script.

Now see usage on how to use the task file.

# Naming

The naming of functions is important. There are basically two styles:

  1. Action + Object
  2. Object + Action

The task file functions use the first style. The name of the function starts with an action followed by an object. The object name can be singular or plural.

Examples for actions: activate, install, dev, develop, init, build, start, update, remove, delete, enable, disable, template, convert, create, edit, change, get, set, patch, fetch, generate, push, pull, import, export, list, publish, release, test, setup, prepare, restart, stop, store, restore, translate, upgrade, zip, visualize, sync, switch, run, reset, load, dump, checkout, commit, drop, deploy, handle, trigger, render, lint, uninstall, split, parse, fix, refactor, transform, cat, ls, rm, serve, help, show, filter, login, logout, encrypt, decrypt, upload, download, analyse, transpile, compile, minify, copy

Examples for objects: env, venv, submodule, container, database, snippet, model, module, repo, mail, doc, dependency, view, user, vault, file, host, node, log, password, hash, script, requirement, part, component, system, workspace, image, process, state, platform, dir, folder, readme, overview, lang, level, request, response, result, worker, server, proxy, workflow, volume, network, package, field, value, secret, chart, node, edge, function, method, firewall, html, css, image, svg, style, query, native, group, notebook

Objects can be tools: odoo, vupress, nodejs, zsh, bash, fish, podman, kind, minikube, helm, nvim, docker, podman, rust, python, tmux, vim, helix, system, git, pass, llm, sql, dotenv, javascript, vue, vite, astro, typescript, turbo, pnpm, eslint, jenkins, k8s, nextcloud, postgres, metabase, ansible, prometheus, grafana, hugo, deno, bun, babel, panda, gulp, grunt, electron, react, express, mongodb, angular, ionic, meteor, webpack, bower, jupyter

# Style

The bash scripts follow the Bash Style Guide | ysap.sh. Have a look at the AGENTS.md for details on the applied styling.