feat(bin): add git folder management utilities and enhance task command parsing

- Introduce new git folder management functions: `clean-git-folder`, `commit-git-folder`, `ls-git-folder`, `push-git-folder`, `reset-git-folder`, `stage-git-folder`, `status-git-folder`
- Add `.prompt/update-switch-case-for-all-task-files` script to update task files with comma-separated command support
- Enhance task command parsing to support comma-separated commands with whitespace trimming and error handling
- Document all new git folder functions in `library.md` under Git section
- Add all new git folder functions to help table in `task.template`
- Update `library.md` to include folder structure overview and fix typos
- Maintain consistent formatting and structure with existing code
This commit is contained in:
Janik von Rotz committed 2025-12-03 09:22:46 +01:00
1 parent 7269ed359d
commit c1f97636cf
10 files changed
+258 -3

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
#!/bin/bash
DRY_RUN=false
SEARCH_PATTERN=$(cat <<'EOF'
if declare -f "$1" > /dev/null; then
activate-venv
"$1" "${@:2}"
EOF
)
REPLACE_BLOCK=$(cat <<'EOF'
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}"
EOF
)
# Find all 'task' files, excluding specified subtrees
find "$HOME" -type f -name 'task' \
-not -path '*/janikv.cloud/*' \
-not -path '*/cloud.mint-system.ch/*' \
-not -path '*/tmp/*' \
| while read -r file; do
# Only process if the exact block exists
if grep -qF "$SEARCH_PATTERN" "$file"; then
echo "Processing: $file"
task_dir="$(dirname "$file")"
tmp_dir="$task_dir/tmp"
mkdir -p "$tmp_dir"
# Add tmp/ to .gitignore if not already there
gitignore="$task_dir/.gitignore"
if [[ -f "$gitignore" ]]; then
if ! grep -q "^tmp/$" "$gitignore" && ! grep -q "^tmp$" "$gitignore"; then
echo "tmp/" >> "$gitignore"
echo "✅ Added 'tmp/' to $gitignore"
fi
else
echo "tmp/" > "$gitignore"
echo "✅ Created $gitignore with 'tmp/'"
fi
backup_path="$tmp_dir/task"
cp "$file" "$backup_path"
echo "💾 Backup saved to: $backup_path"
if [[ "$DRY_RUN" == false ]]; then
sed -i -E "
s|$(printf '%s' "$SEARCH_PATTERN" | sed 's/[]\/$*.^[]/\\&/g; s/\n/\\n/g')|$(
printf '%s' "$REPLACE_BLOCK" | sed 's/[]\/$*.^[]/\\&/g; s/\n/\\n/g'
)|g
" "$file"
echo "✅ Done: $file"
else
echo "🟡 Dry-run: No changes made to $file"
fi
else
echo "⚠️ Skipping (pattern not found): $file"
fi
done
echo "🎉 All exact 'task' files processed (excluding janikv.cloud, cloud.mint-system.ch, and tmp subtrees)."
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
clean-git-folder() {
local git_folders=$(ls-git-folder)
for git_folder in $git_folders; do
echo "Clean git folder $git_folder."
git -C "$git_folder" clean -df
done
}
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
commit-git-folder() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
if [[ -z "$2" ]]; then echo "\$2 is empty."; exit; fi
local git_folders=$(ls-git-folder "$1")
for git_folder in $git_folders; do
echo "Commit in $git_folder."
git -C "$git_folder" commit --message "$2"
done
}
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
#!/usr/bin/env bash
ls-git-folder() {
[[ -z "$1" ]] && { echo '$1 is empty.' >&2; return 1; }
[[ ! -d "$1" ]] && { echo "Error: '$1' is not a directory." >&2; return 1; }
local excludes="${GIT_FOLDER_EXCLUDE:-.cache,node_modules,venv,__pycache__,.vim,.fzf,.password-store,.oh-my-zsh}"
local find_cmd="find \"$1\" -maxdepth 3"
IFS=',' read -ra patterns <<< "$excludes"
for pattern in "${patterns[@]}"; do
pattern=$(echo "$pattern" | xargs)
[[ -n "$pattern" ]] && find_cmd="$find_cmd \( -name '$pattern' -o -path \"*/$pattern/*\" \) -prune -o"
done
find_cmd="$find_cmd -type d -name '.git' -print"
eval "$find_cmd" 2>/dev/null | while IFS= read -r git_dir; do
dirname "$git_dir"
done
}
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
push-git-folder() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
local git_folders=$(ls-git-folder "$1")
for git_folder in $git_folders; do
echo "Push in $git_folder."
git -C "$git_folder" push
done
}
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
reset-git-folder() {
local git_folders=$(ls-git-folder)
for git_folder in $git_folders; do
echo "Abort rebase and reset git folder $git_folder."
git -C "$git_folder" rebase --abort
git -C "$git_folder" reset --hard
done
}
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
stage-git-folder() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
local git_folders=$(ls-git-folder "$1")
for git_folder in $git_folders; do
echo "Stage all files in $git_folder."
git -C "$git_folder" add --all
done
}
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
status-git-folder() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
local git_folders=$(ls-git-folder "$1")
echo 'Show status in git folders.'
for git_folder in $git_folders; do
git -C "$git_folder" status
done
}
+70 -2
View File
@@ -32,9 +32,16 @@ if [[ -d "$HOME/taskfile.build/bin" ]]; then
fi
```
These commands create folder in the directory of the task file and the home directory. Here is an overview of these folders:
* `$PWD/tmp`: Temporary directory for the task commands.
* `$PWD/.prompt`: LLM prompts stored as markdown files.
* `$HOME/.config/taskfile.build`: Default path for storing dotenv files.
* `$HOME/.docker/$CONTAINER_REGISTRY`: Default path for storing container registry credentials.
## Task
Configure the task commands.
Configure the task enviroment.
```bash
OPEN_BROWSER=False # Default: True
@@ -67,6 +74,8 @@ printf "$column" 'open-url-with-delay' '[url][delay]' 'Open url after n seconds.
## Files
Managing files and directories.
### ensure-directory
```bash
@@ -87,6 +96,8 @@ printf "$column" 'create-symlink-files' '[source][target]' 'Create symlink for f
## Python
Setup Python virtual enviroment.
### activate-venv
```bash
@@ -169,6 +180,8 @@ printf "$column" 'restore-env-files' '[path]' 'Extract and copy env files from b
## LLM
Commands that integrate the `llm` cli.
### commit-with-llm
```bash
@@ -183,6 +196,8 @@ printf "$column" 'update-with-llm' '[glob][prompt]' 'Feed files matching glob to
## Logging
Colorful logging in task commands.
### log-warning
```bash
@@ -191,14 +206,61 @@ printf "$column" 'log-warning' '' 'Colored output for warnings.'
## Git
Manage git folders and submodules.
### commit-git-folder
```bash
printf "$column" 'commit-git-folder' '[message][path]' 'Commit all changes in git folders in path.'
```
### commit-git-folder
```bash
printf "$column" 'clean-git-folder' '' 'Clean git folder.'
```
### ls-git-folder
```bash
printf "$column" 'ls-git-folder' '[path]' 'Space separated list of git folders in path.'
```
### push-git-folder
```bash
printf "$column" 'push-git-folder' '' 'Push all git folders in path.'
```
### reset-git-folder
```bash
printf "$column" 'reset-git-folder' '' 'Abort, rebase and reset git folder.'
```
### stage-git-folder
```bash
printf "$column" 'stage-git-folder' '[path]' 'Stage all files in git folders in path.'
```
### status-git-folder
```bash
printf "$column" 'status-git-folder' '[path]' 'Show status of git folders in path.'
```
### update-submodule
```bash
printf "$column" 'update-submodule' '' 'Update git submodules.'
```
## Pass
Load and store secrets from pass.
Set path to pass entry.
```bash
@@ -219,7 +281,9 @@ printf "$column" 'load-dotenv-from-pass' '' 'Restore content to .env from pass e
## KeePass
Set path to KeePass database and entry.
Load and store secrets from KeePassXC.
Set path to KeePassXC database and entry.
```bash
KEEPASS_DATABASE_FILE="/path/to/database.kdbx"
@@ -253,6 +317,8 @@ printf "$column" 'load-dotenv-from-keepass' '' 'Restore content to .env from Kee
## Docker
Build and push Docker images.
Set Docker env vars.
```bash
@@ -277,6 +343,8 @@ printf "$column" 'build-image' '[output]' 'Build Docker image with buildx.'
## Ansible
Install scripts from the Ansible Build project.
### install-ansible-build-scripts
The available roles with scripts are listed here: <https://ansible.build/scripts.html>
+22 -1
View File
@@ -37,6 +37,13 @@ help-table() {
# Logging
printf "$column" 'log-warning' '' 'Colored output for warnings.'
# Git
printf "$column" 'commit-git-folder' '[message][path]' 'Commit all changes in git folders in path.'
printf "$column" 'clean-git-folder' '' 'Clean git folder.'
printf "$column" 'ls-git-folder' '[path]' 'Space separated list of git folders in path.'
printf "$column" 'push-git-folder' '' 'Push all git folders in path.'
printf "$column" 'reset-git-folder' '' 'Abort, rebase and reset git folder.'
printf "$column" 'stage-git-folder' '[path]' 'Stage all files in git folders in path.'
printf "$column" 'status-git-folder' '[path]' 'Show status of git folders in path.'
printf "$column" 'update-submodule' '' 'Update git submodules.'
# Pass
printf "$column" 'save-dotenv-to-pass' '' 'Store content of .env in pass entry.'
@@ -73,7 +80,21 @@ if [[ -d "$HOME/taskfile.build/bin" ]]; then
done
fi
if declare -f "$1" > /dev/null; then
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