Files
coolify/scripts/change.sh
T

168 lines
4.5 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
CHANGE_DIRECTORY=.changes
TYPES=(added changed deprecated removed fixed security maintenance)
SECTIONS=('Breaking Changes' Security Added Changed Deprecated Removed Fixed Maintenance)
BOLD=$'\033[1m' GREEN=$'\033[32m' RED=$'\033[31m' DIM=$'\033[2m' RESET=$'\033[0m'
[ -t 1 ] || BOLD='' GREEN='' RED='' DIM='' RESET=''
heading() { printf '\n %s%s%s\n' "$BOLD" "$*" "$RESET"; }
ok() { printf ' %s✔%s %s\n' "$GREEN" "$RESET" "$*"; }
die() {
printf ' %s✖%s %s\n' "$RED" "$RESET" "$*" >&2
exit 1
}
confirm() {
local answer
printf '\n %s [y/N] ' "$*"
read -r answer
[[ "$answer" =~ ^[Yy]$ ]]
}
cd "$(dirname "$0")/.."
trap 'tput cnorm 2> /dev/null || true' EXIT
main() {
read_arguments "$@"
if [ -n "$notes" ]; then
print_notes
return
fi
[ -n "$kind" ] && [ -n "$summary" ] || ask_questions
write_change
}
read_arguments() {
kind='' summary='' commit='' breaking='' notes='' details=()
while [ $# -gt 0 ]; do
case "$1" in
--notes) notes=true ;;
--breaking) breaking=true ;;
--type | --summary | --detail | --commit)
[ $# -ge 2 ] || die "$1 has no value, expected one"
case "$1" in
--type) kind="$2" ;;
--summary) summary="$2" ;;
--detail) details+=("$2") ;;
--commit) commit="$2" ;;
esac
shift
;;
*) die "'$1' is not an option, expected --type, --summary, --detail, --breaking, --commit or --notes" ;;
esac
shift
done
}
ask_questions() {
local selected detail
[ -t 0 ] || die "--type and --summary are required without a terminal"
if [ -z "$kind" ]; then
heading "Select the type"
selected="$(menu 0 "${TYPES[@]}")"
kind="${TYPES[$selected]}"
fi
if [ -z "$summary" ]; then
heading "Summary, one sentence with the heading"
printf ' '
read -r summary
fi
heading "Details, an empty line ends them"
while printf ' - ' && read -r detail && [ -n "$detail" ]; do
details+=("$detail")
done
if confirm "Breaking change?"; then
breaking=true
fi
printf '\n'
}
write_change() {
local path detail
printf '%s\n' "${TYPES[@]}" | grep -qx -- "$kind" || die "the type is '$kind', expected ${TYPES[*]}"
[ -n "$summary" ] || die "the summary is empty, expected one sentence"
if [ -n "$commit" ]; then
git rev-parse --verify --quiet "$commit^{commit}" > /dev/null || die "$commit is not a commit of this repository"
commit="$(git rev-parse --short "$commit")"
fi
mkdir -p "$CHANGE_DIRECTORY"
path="$CHANGE_DIRECTORY/$(file_name).md"
{
printf -- '---\ntype: %s\n' "$kind"
[ -z "$breaking" ] || printf 'breaking: true\n'
[ -z "$commit" ] || printf 'commit: %s\n' "$commit"
printf -- '---\n%s\n' "$summary"
[ "${#details[@]}" = 0 ] || printf '\n'
for detail in ${details[@]+"${details[@]}"}; do
printf -- '- %s\n' "$detail"
done
} > "$path"
ok "$path describes the $BOLD$kind$RESET change"
}
print_notes() {
local section entries
compgen -G "$CHANGE_DIRECTORY/*.md" > /dev/null || die "$CHANGE_DIRECTORY has no change files"
for section in "${SECTIONS[@]}"; do
entries="$(awk -v section="$section" '
FNR == 1 { fences = 0; type = ""; breaking = 0 }
fences < 2 {
if ($0 == "---") fences++
else if ($1 == "type:") type = $2
else if ($0 == "breaking: true") breaking = 1
next
}
NF && tolower(section) == (breaking ? "breaking changes" : type) {
prefix = /^- / ? " " : "- "
print prefix $0
}
' "$CHANGE_DIRECTORY"/*.md)"
[ -z "$entries" ] || printf '### %s\n\n%s\n\n' "$section" "$entries"
done
}
file_name() {
local stem name number=2
stem="$(printf '%s' "$summary" | LC_ALL=C tr -cs '[:alnum:]' '\n' | LC_ALL=C tr '[:upper:]' '[:lower:]' | awk 'NF && ++count <= 6' | paste -sd - -)"
name="$stem"
while [ -e "$CHANGE_DIRECTORY/$name.md" ]; do
name="$stem-$number"
number=$((number + 1))
done
echo "$name"
}
menu() {
local selected="$1" options key i
shift
options=("$@")
tput civis >&2 2> /dev/null || true
while true; do
for i in "${!options[@]}"; do
if [ "$i" = "$selected" ]; then
printf ' %s❯ %s%s\n' "$GREEN" "${options[$i]}" "$RESET" >&2
else
printf ' %s %s%s\n' "$DIM" "${options[$i]}" "$RESET" >&2
fi
done
IFS= read -rsn1 key
if [ "$key" = $'\x1b' ]; then
IFS= read -rsn2 key
if [ "$key" = '[A' ] && [ "$selected" -gt 0 ]; then
selected=$((selected - 1))
elif [ "$key" = '[B' ] && [ "$selected" -lt $((${#options[@]} - 1)) ]; then
selected=$((selected + 1))
fi
elif [ -z "$key" ]; then
break
fi
printf '\033[%dA\033[J' "${#options[@]}" >&2
done
tput cnorm >&2 2> /dev/null || true
echo "$selected"
}
main "$@"