mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 21:07:02 +01:00
Some checks are pending
release-apk / release (APK) (push) Waiting to run
The AUR package sources the clean vX.Y.Z tag the release workflow cuts, but that tag only moves when pubspec.yaml's version changes by hand -- so it sat on v1.0.0 while HEAD moved 8 commits ahead, and the package advertised a stale tree. Bumping the patch per commit keeps that tag tracking HEAD. Patch, not minor: minor/major are the "how much broke" signal, and auto-incrementing them on every commit throws that away (and reaches absurd numbers within a year). Two guards keep the number honest, both covered by a scratch-repo run: re-running the hook over the same staged change is idempotent, because the bump is computed from the last COMMITTED version rather than the working tree; and a rebase/merge/cherry-pick in progress is skipped, so replayed commits don't each inflate it. .git/hooks is untracked, so scripts/install_hooks.sh makes the hook reproducible on a fresh clone -- this repo has no pre-commit framework. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aoa1nKWRrAbowz7Hfd3tgL
123 lines
3.8 KiB
Bash
Executable File
123 lines
3.8 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# ============================================================================
|
|
# Bump the patch version in pubspec.yaml on every commit.
|
|
#
|
|
# `version: X.Y.Z+B` -> `version: X.Y.(Z+1)+B`. The +build suffix is left
|
|
# alone: CI replaces it with the commit count, so it is not ours to manage.
|
|
#
|
|
# Wired as a pre-commit hook so each commit ships its own bump. That keeps the
|
|
# release-apk workflow's clean `vX.Y.Z` tag moving with HEAD instead of
|
|
# sitting on whatever version was last hand-edited, which is what left the AUR
|
|
# package advertising a tag 8 commits behind.
|
|
#
|
|
# Deliberately NOT bumping minor: minor/major are the "how much broke" signal.
|
|
# Auto-incrementing them on every commit throws that signal away and reaches
|
|
# absurd numbers within a year.
|
|
# ============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
readonly SCRIPT_NAME
|
|
PUBSPEC=""
|
|
|
|
usage() {
|
|
echo "Usage: $SCRIPT_NAME [--pubspec PATH]"
|
|
echo "Options:"
|
|
echo " --pubspec PATH pubspec.yaml to bump (default: repo root's)"
|
|
echo " -h, --help Show this help"
|
|
exit 0
|
|
}
|
|
|
|
# Bumping while a rebase/merge/amend is replaying commits would inflate the
|
|
# version once per replayed commit, so skip those states entirely.
|
|
in_replay_state() {
|
|
local git_dir
|
|
git_dir="$(git rev-parse --git-dir)"
|
|
[[ -d "$git_dir/rebase-merge" || -d "$git_dir/rebase-apply" \
|
|
|| -f "$git_dir/MERGE_HEAD" || -f "$git_dir/CHERRY_PICK_HEAD" ]]
|
|
}
|
|
|
|
# Only bump when something other than pubspec.yaml is staged. A commit that
|
|
# only touches the version (or only docs the hook itself rewrote) must not
|
|
# trigger another bump, or `git commit --amend` would climb a version per
|
|
# amend.
|
|
has_non_pubspec_changes() {
|
|
local staged
|
|
staged="$(git diff --cached --name-only)"
|
|
[[ -n "$(grep -v -e '^$' -e 'pubspec\.yaml$' <<<"$staged")" ]]
|
|
}
|
|
|
|
main() {
|
|
if [[ -z "$PUBSPEC" ]]; then
|
|
PUBSPEC="$(git rev-parse --show-toplevel)/pubspec.yaml"
|
|
fi
|
|
|
|
if [[ ! -f "$PUBSPEC" ]]; then
|
|
echo "Error: no pubspec.yaml at $PUBSPEC" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if in_replay_state; then
|
|
echo "bump-version: rebase/merge in progress; leaving version alone"
|
|
exit 0
|
|
fi
|
|
|
|
if ! has_non_pubspec_changes; then
|
|
echo "bump-version: nothing staged but the version itself; not bumping"
|
|
exit 0
|
|
fi
|
|
|
|
local raw semver build major minor patch next committed rel_path
|
|
raw="$(sed -nE 's/^version:[[:space:]]*(.*)$/\1/p' "$PUBSPEC" | head -1)"
|
|
if [[ -z "$raw" ]]; then
|
|
echo "Error: no 'version:' line in $PUBSPEC" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Bump relative to the LAST COMMITTED version, not the working-tree one.
|
|
# Otherwise re-running the hook over the same staged change (a hook that
|
|
# failed, got fixed, and was retried) climbs a patch per attempt instead
|
|
# of per commit.
|
|
rel_path="${PUBSPEC#"$(git rev-parse --show-toplevel)/"}"
|
|
committed="$(git show "HEAD:$rel_path" 2>/dev/null \
|
|
| sed -nE 's/^version:[[:space:]]*(.*)$/\1/p' | head -1 || true)"
|
|
[[ -n "$committed" ]] && raw="$committed"
|
|
|
|
semver="${raw%%+*}"
|
|
build=""
|
|
[[ "$raw" == *+* ]] && build="+${raw#*+}"
|
|
|
|
if [[ ! "$semver" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
|
echo "Error: version '$raw' is not X.Y.Z[+B]" >&2
|
|
exit 1
|
|
fi
|
|
major="${BASH_REMATCH[1]}"
|
|
minor="${BASH_REMATCH[2]}"
|
|
patch="${BASH_REMATCH[3]}"
|
|
|
|
next="$major.$minor.$((patch + 1))"
|
|
sed -i -E "s/^version:[[:space:]]*.*$/version: $next$build/" "$PUBSPEC"
|
|
git add "$PUBSPEC"
|
|
echo "bump-version: $semver -> $next"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--pubspec)
|
|
PUBSPEC="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
main "$@"
|