Skip to content

Instantly share code, notes, and snippets.

@goliatone
Last active April 18, 2025 03:06
Show Gist options
  • Save goliatone/d136377d7768acf6960f7cceefb8a24e to your computer and use it in GitHub Desktop.
Save goliatone/d136377d7768acf6960f7cceefb8a24e to your computer and use it in GitHub Desktop.
Taskfile template
#!/bin/bash
# Check for -debug flag
if [[ $* == *-debug* ]]; then
set -x
fi
export LGR_NO_TIMESTAMP=true
VERSION_FILE="./.version"
# If we have a .taskenv file load it as source
# the file should be e.g.
# #!/bin/bash
# export DATABASE_URL="..."
if [ -f .taskenv ]; then
# shellcheck disable=SC1091
source .taskenv
fi
# This makes all bin packages installed via npm available here
# e.g. bogota, nyc, autocannon, etc.
PATH=$(pwd)/node_modules/.bin:$PATH
# This will make all scripts available in the ./src/bin directory
PATH=$(pwd)/src/bin:$PATH
#################################################
# Development dependencies
#################################################
function _install:lgr {
mkdir -p bin
if hash lgr 2>/dev/null; then
lgr OK "lgr already installed..."
else
if [[ $(command -v brew) == "" ]]; then
echo "Installing lgr"
brew tap goliatone/homebrew-tap
brew install lgr
lgr OK "lgr installed..."
else
LGR_VERSION="0.1.1"
LGR_FILENAME="lgr_${LGR_VERSION}_linux_x86_64.tar.gz"
curl -sL "https://github.com/goliatone/lgr/releases/download/v${LGR_VERSION}/${LGR_FILENAME}" | tar xz
chmod +x lgr
lgr OK "lgr installed"
fi
fi
}
function _install:changelog {
if git-cliff lgr 2>/dev/null; then
lgr OK "git-cliff already installed..."
else
echo "Installing lgr"
brew install brew install orhun/git-cliff/git-cliff
lgr OK "git-cliff installed..."
fi
}
function _install:brew {
if [[ $(command -v brew) == "" ]]; then
lgr I "Installing Hombrew"
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
else
lgr I "Updating Homebrew"
brew update
fi
}
function _install:envset {
if hash envset 2>/dev/null; then
lgr OK "envset installed..."
else
lgr I "Installing envset..."
brew install envset
lgr OK "envset installed..."
fi
}
function lgr {
if command -v lgr >/dev/null 2>&1; then
command lgr "$@"
else
echo "$@" # fallback to plain echo
fi
}
##########################################
# Application management
##########################################
function dev:install {
cd "$(pwd)/src" || exit "$?"
_install:lgr
_install:brew
_install:envset
_install:changelog
lgr ok "dependencies intalled..."
}
function dev:env:load {
eval "$(envset development --isolated=true)"
}
##
## ########################################
## Version Management
## ########################################
##
## -----
##
## version:upsert
##
## Save version to meta file.
## First time will create file if not present
##
## Arguments:
## @arg 1 {string} [tag=0.0.1]
function version:upsert {
local tag=${1}
if [ -z "$tag" ]; then
version:get
else
version:set "$tag"
version:get
fi
}
##
## -----
##
## version:get
##
## Get version from meta file.
function version:get {
test -f "${VERSION_FILE}" || touch "${VERSION_FILE}"
local tag
tag=$(cat "${VERSION_FILE}")
if [ -z "$tag" ]; then
tag="0.0.1"
version:set "$tag"
fi
echo -n "$tag"
}
##
## -----
##
## version:set
##
## Set and save version to meta file.
## First time will create file if not present.
##
## Arguments:
## @arg 1 {string} [tag=0.0.1]
function version:set {
local tag
tag=${1}
if [ -z "$tag" ]; then
exit 1
fi
version:check
echo -e "$tag" > "${VERSION_FILE}"
}
##
## -----
##
## version:bump
## Bump sem ver by specifying a level.
## Valid levels are:
## - patch (default)
## - minor
## - major
##
## If you want to update the .version file
## pass the `--write` flag.
## @see https://github.com/fsaintjacques/semver-tool/blob/master/src/semver
##
## @arg 1 {string} [level=patch]
## Outputs:
## Semver string "$major.$minor.$patch"
##
## @flag --write Will write to .version file
##
function version:bump {
version:check
# Default values
level='patch'
write_to_file=0
# Parse options
while [[ "$#" -gt 0 ]]; do
case $1 in
--write)
write_to_file=1
shift
;;
patch|minor|major)
level=$1
shift
;;
*)
echo "Invalid option: $1"
return 2
;;
esac
done
# Read contents of version and store in
IFS='.' read -ra identifiers < "$VERSION_FILE"
[[ "${#identifiers[@]}" -ne 3 ]] && echo "Invalid semver string" && return 1
patch=${identifiers[2]}
minor=${identifiers[1]}
major=${identifiers[0]}
case $level in
patch)
patch=$((patch+1))
;;
minor)
minor=$((minor+1))
patch=0
;;
major)
major=$((major+1))
minor=0
patch=0
;;
*)
echo "Invalid level passed"
return 2
esac
new_version="$major.$minor.$patch"
if [[ $write_to_file -eq 1 ]]; then
echo "$new_version" > "${VERSION_FILE}"
else
echo "$new_version"
fi
}
function version:check {
if [ ! -f "$VERSION_FILE" ]; then
echo "0.0.0" > "$VERSION_FILE"
fi
}
##
## -----
##
## release
##
## Bump our current version, create a git tag
## and push to trigger our release flow.
##
## Arguments:
## @arg 1 {string} [level=patch]
## Accepted major, minor, patch
function release {
local tag
local level
local message
# Fetch all changes from origin
git fetch --all
if [ -f ".version" ]; then
# Make sure we have the latest version file
git checkout origin/main -- ".version"
else
lgr I "File .version does not exist. Skipping."
fi
# Pull tags to make sure we have
git pull --tags -f
level=${1:-"patch"}
# Bump our version
tag=$(version:bump "${level}")
# Set message: default to New major|minor|patch release: vx.x.x
message=${2:-"New ${level} release: v${tag}"}
lgr I "$message"
# Update version file
version:set "${tag}"
# Add updated version file to git
git add "${VERSION_FILE}"
git commit -m "Bump version: v${tag}"
# Create a new tag
git tag -a "v${tag}" -m "${message}"
# Push tags and trigger release 🚀 🥳
git push --tags
git push
# Generate changelog
git cliff --output CHANGELOG.md
git add CHANGELOG.md
git commit -m "docs: update changelog for v${tag}"
git push
lgr OK "We released v${tag} 🚀 🥳"
}
##########################################
# Help and auxiliary functions
##########################################
## Show function code
function help:show {
declare -f "$1"
}
function help {
echo ""
echo "$0 <task> [...arguments]"
echo ""
echo "Project: ${PROJECT}"
echo ""
echo "Tasks:"
compgen -A function | grep -v '^_' | cat -n
echo ""
prog="$0"
me=$(basename "$prog")
grep -e '^##[[:space:]]' -e '^##$' "$prog" | sed -e 's/^##//' -e "s/_PROG_/$me/" 2>&1 | less
}
TIMEFORMAT="Task completed in %3lR"
time "${@:-help}"
@goliatone
Copy link
Author

goliatone commented Dec 30, 2017

Add this to .zshrc

# Quick start with the default Taskfile template
alias run-init="curl -so taskfile https://gist.githubusercontent.com/goliatone/d136377d7768acf6960f7cceefb8a24e/raw/taskfile.template && chmod +x taskfile"

alias run=./taskfile

@goliatone
Copy link
Author

goliatone commented Oct 28, 2021

TODO

  • Integrate a way to use/parse arguments: maybe bargs or this
  • Add template functions and sections
  • Include template version/release number.
    • Would it be possible to include the revision hash?
  • Maybe have different templates, e.g. run-init node or run-init go.

@goliatone
Copy link
Author

@goliatone
Copy link
Author

have a way to mark a task as "singleton" and implement a sort of lock file we check before running the task, to prevent to run the same task concurrently, e.g. i run server:fresh which drops the database and then runs the server, then in another window I use up arrow to bring a cmd and mistakenly autocomplete to the wrong command, which could drop the db

have a simple wrapper to run these task files. taskrun

  • which would download the task from gist
  • would run an specific command
  • could be used to parse help from a given task

@goliatone
Copy link
Author

Use this to get the latest tag for logger:

LATEST_TAG=$(curl -s https://api.github.com/repos/goliatone/lgr/releases/latest | jq -r .tag_name)
LGR_FILENAME="lgr_${LGR_VERSION}_linux_x86_64.tar.gz"
curl -sL "https://github.com/goliatone/lgr/releases/download/v${LGR_VERSION}/${LGR_FILENAME}" | tar xz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment