Files
git.taskfile.build/patterns.md
T
Janik von Rotz 28817b1eb6 feat(script): add kubeconfig utilities and enhance branch-specific env handling
- Added new scripts for loading and saving kubeconfig from Keepass and Pass
- Introduced log-error and log-success utilities for consistent logging
- Enhanced init-venv to create branch-specific virtual environments
- Added pattern for loading branch-specific .env files based on current git branch
- Improved error messages with proper quoting and formatting
- Updated patterns.md to document branch-specific environment handling
2026-01-23 12:56:44 +01:00

315 lines
7.6 KiB
Markdown

---
layout: layouts/base.njk
---
# Patterns
The task file from the specification is very basic. Commands can also have parameters and call each other.
The following is a collection of more complex task file patterns.
## Set default parameter
Fallback to a default value for a parameter.
```bash
build() {
local platform="amd64"
if [[ -n "$1" ]]; then
platform="$1"
fi
```
## Ensure parameter is not empty
Check the first param and exit if it is empty.
```bash
deploy() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
```
## Prompt for input
Use `read` to ask for inputs.
```bash
if [[ -z "$2" ]]; then
read -p 'Enter the task description: ' task_description
else
task_description="$2"
fi
```
## Static env vars
These vars are exported from the script and used in external tools.
```bash
CONFIGURATION_FILE=${CONFIGURATION_FILE:=file.conf}
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
```
## Updateable vars
This variables can be configured from the environment, but is used only internally.
```
container_engine=${CONTAINER_ENGINE:=docker}
compose_command=${COMPOSE_COMMAND:=docker compose}
```
## Conditional vars
Depending on the value of another var, this vars value changes.
```bash
if [[ "$container_engine" == "podman" ]]; then
compose_command="podman-compose"
fi
```
## Template with env vars
Create a parameterized file from a template. Requires `envsubst`.
```bash
template-with-env() {
echo "Template $CONFIGURATION_FILE"
export CONFIGURATION_1
export CONFIGURATION_2=${CONFIGURATION_2:=value}
envsubst < 'file.conf.template' > "$CONFIGURATION_FILE"
}
```
## Create Python virtual env for git branch
Initialize Python virtual env with uv.
```bash
init-venv() {
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
if [[ ! -d ".venv$GIT_BRANCH" ]]; then
echo "Init .venv$GIT_BRANCH with $(uv --version)."
uv venv ".venv$GIT_BRANCH"
fi
}
```
## Call a Python script
Run a Python script.
```bash
generate-password-hash() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
export PASSWORD_PLAIN="$1"
bin/password-hash
}
```
The Python script: `bin/password-hash`
```python
#!/usr/bin/env python3
import os
from passlib.context import CryptContext
crypt_context = CryptContext(schemes=['pbkdf2_sha512', 'plaintext'], deprecated=['plaintext'])
password = os.environ.get('PASSWORD_PLAIN')
print(crypt_context.hash(password))
```
## Command with named parameters
Assuming you have a `docker-compose.yml` and would like to start selected or all containers.
```bash
start() {
if [[ "$1" =~ 'db' ]]; then
docker compose up -d db
fi
if [[ "$1" =~ 'admin' ]]; then
docker compose up -d admin
echo 'Open http://localhost:8000 url in your browser.'
fi
if [[ "$1" =~ 'odoo' ]]; then
docker compose up -d odoo
echo 'Open http://localhost:8069 url in your browser.'
fi
if [[ "$1" =~ 'mail' ]]; then
docker compose up -d mail
echo 'Open http://localhost:8025 url in your browser.'
fi
}
```
Start all containers with `task start` and selected with `task start db,admin`.
## Run commands in container
Use `docker exec -i` to run commands in a container.
```bash
drop-db() {
local database="$1"
if [[ -z "$database" ]]; then
database="example"
fi
docker exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$database';"
docker exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "DROP DATABASE \"$database\";"
}
```
## Loop over files and folders
Use `for` to loop over file, folders or arrays.
```bash
render() {
echo "Update index.html for all folders"
for folder in ./*; do
if [[ -f "$folder/README.md" ]]; then
cd "$folder" || exit
md2html README.md _site/index.html
cd .. || exit
fi
done
}
```
## Parse and convert a file
With this function you can split a file into multiple parts whenever a specific keyword is matching. In this example the keyword is `!vault`.
```bash
convert-vault-file() {
local file_path="$1"
local temp_file=$(mktemp)
local temp_part_file=$(mktemp)
local write_finished=false
local current_key=""
while IFS= read -r line; do
# Check for keyword
if [[ "$line" =~ "!vault" ]]; then
# Process previous vault entry if it exists
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
# Decrypt part file and write to assemble file
ansible-vault decrypt "$temp_part_file"
local value=$(cat "$temp_part_file")
echo "$current_key: $value" >> "$temp_file"
fi
# Set up for new vault entry
current_key=$(echo "$line" | cut -d':' -f1)
# Clear the file
: > "$temp_part_file"
# Flag as ready to write
write_finished=true
else
if [[ "$write_finished" = true ]]; then
# Pipe into part file
echo "$line" >> "$temp_part_file"
fi
done
done < "$file_path"
# Process the final vault entry
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
ansible-vault decrypt "$temp_part_file"
local value=$(cat "$temp_part_file")
echo "$current_key: $value" >> "$temp_file"
fi
# Output assembled file
cat "$temp_file"
# Cleanup temp files
rm -f "$temp_file"
rm -f "$temp_part_file"
}
```
## Process data
This pattern tries to match the worklow of a jupyter notebook. Create a folder with the data processing scripts:
```
scripts
├── 01_import-mail-data
├── 02_transform-mail-data
└── 03_export-mail-data
```
The following function lists the scripts and asks for the number of scripts to run. Every script until the entered number is concatenated and executed.
```bash
process-data() {
while true; do
local scripts=($(ls scripts))
echo -e "Available scripts:\n"
for index in "${!scripts[@]}"; do
echo "$((index+1)): ${scripts[$index]}"
done
echo ""
read -p "Enter the number of scripts to run (or 'q' to quit): " user_input
if [[ "$user_input" = "q" ]]; then
break
fi
local temp_file=$(mktemp)
for index in "${!scripts[@]}"; do
if (( $user_input >= $((index+1)) )); then
cat "scripts/${scripts[$index]}" >> "$temp_file"
echo >> "$temp_file"
fi
done
clear
echo -e "\nPython Output:\n\n---"
python "$temp_file"
local exit_code=$?
echo -e "---\n"
echo -e "Exit code: $exit_code\n"
rm "$temp_file"
done
}
```
## Check commands
Add the following statements to check if the required commands is available:
```bash
if ! (command -v grep &> /dev/null && grep --version | grep -q GNU) && [[ "$OS_RELEASE" =~ ^(Darwin)$ ]]; then
echo 'Error: On Darwin systems, GNU grep must be installed.'
exit 1
fi
if ! command -v envsubst &> /dev/null; then
echo "Error: 'envsubst' is not available. Install 'gettext' package."
exit 1
fi
```
## Load dotenv by git branch
If you want to have a `.env.<branch>` file for each git branch use this pattern:
```bash
if [[ -d ".git" ]]; then
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
if [[ -a ".env.$GIT_BRANCH" ]]; then
export $(cat ".env.$GIT_BRANCH" | sed 's/^#.*//g' | xargs)
fi
fi
```