From dda63a05ffd60ab5ec80e60be6915596e4667e88 Mon Sep 17 00:00:00 2001 From: rootiest Date: Wed, 17 Jun 2026 20:58:08 -0400 Subject: [PATCH] feat(agents-tools): add version-bump precommit logic --- scripts/agents-tools/test-version-bump.sh | 40 ++++++++++++ scripts/agents-tools/version-bump | 77 +++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 scripts/agents-tools/test-version-bump.sh create mode 100755 scripts/agents-tools/version-bump diff --git a/scripts/agents-tools/test-version-bump.sh b/scripts/agents-tools/test-version-bump.sh new file mode 100644 index 0000000..6a764fe --- /dev/null +++ b/scripts/agents-tools/test-version-bump.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later +# +# Self-contained tests for version-bump. Run: bash test-version-bump.sh +set -u +HERE="$(cd "$(dirname "$0")" && pwd)" +SCRIPT="$HERE/version-bump" +fail() { echo "FAIL: $1"; exit 1; } + +new_repo() { + local d; d="$(mktemp -d)" + git -C "$d" init -q + git -C "$d" config user.email t@t + git -C "$d" config user.name t + git -C "$d" config commit.gpgsign false + printf '%s\n' "$d" +} + +# ── precommit: baseline + PATCH + MINOR ────────────────────────────────────── +r="$(new_repo)"; cd "$r" +mkdir -p plans; : > plans/.gitkeep +echo 1.0.0 > .version +git add -A; "$SCRIPT" precommit; git commit -q -m init +[ "$(cat .version)" = 1.0.0 ] || fail "first commit: want 1.0.0 got $(cat .version)" + +echo hi > plans/a.md +git add -A; "$SCRIPT" precommit; git commit -q -m content +[ "$(cat .version)" = 1.0.1 ] || fail "content: want 1.0.1 got $(cat .version)" + +mkdir -p specs; : > specs/.gitkeep +git add -A; "$SCRIPT" precommit; git commit -q -m structure +[ "$(cat .version)" = 1.1.0 ] || fail "structure: want 1.1.0 got $(cat .version)" + +echo x > specs/s.md +git add -A; "$SCRIPT" precommit; git commit -q -m content2 +[ "$(cat .version)" = 1.1.1 ] || fail "content2: want 1.1.1 got $(cat .version)" + +cd /; rm -rf "$r" +echo "precommit OK" diff --git a/scripts/agents-tools/version-bump b/scripts/agents-tools/version-bump new file mode 100755 index 0000000..a8689c5 --- /dev/null +++ b/scripts/agents-tools/version-bump @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# agents-tools-version: 1 +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later +# +# version-bump [msgfile] +# +# Maintains /.version (MAJOR.MINOR.PATCH). MAJOR is manual-only. +# MINOR bumps when the tracked directory set changes between HEAD and the +# staged index; PATCH bumps on any other commit. Never blocks a commit: +# all hook paths exit 0 even on unexpected errors. + +mode="${1:-}" +root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0 +vfile="$root/.version" + +read_dirset() { + # $1: HEAD|INDEX — print sorted unique content dirs (dot-dirs excluded) + local listing + if [ "$1" = HEAD ]; then + listing="$(git ls-tree -r --name-only HEAD 2>/dev/null || true)" + else + listing="$(git ls-files 2>/dev/null || true)" + fi + printf '%s\n' "$listing" \ + | while IFS= read -r f; do [ -n "$f" ] && dirname "$f"; done \ + | { grep -v '^\.' || true; } \ + | sort -u +} + +bump_precommit() { + [ -f "$vfile" ] || printf '1.0.0\n' > "$vfile" + + # First commit: establish the baseline, no bump. + if ! git rev-parse --verify -q HEAD >/dev/null 2>&1; then + grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' "$vfile" || printf '1.0.0\n' > "$vfile" + git add -- "$vfile" 2>/dev/null || true + return 0 + fi + + local major minor patch + IFS=. read -r major minor patch < "$vfile" + case "$major$minor$patch" in + *[!0-9]*|"") major=1; minor=0; patch=0 ;; + esac + + if [ "$(read_dirset HEAD)" != "$(read_dirset INDEX)" ]; then + minor=$((minor + 1)); patch=0 + else + patch=$((patch + 1)) + fi + printf '%s.%s.%s\n' "$major" "$minor" "$patch" > "$vfile" + git add -- "$vfile" 2>/dev/null || true +} + +bump_prepmsg() { + local msgfile="${1:-}" version first rest + [ -n "$msgfile" ] && [ -f "$msgfile" ] || return 0 + [ -f "$vfile" ] || return 0 + version="$(head -n1 "$vfile")" + [ -n "$version" ] || return 0 + head -n1 "$msgfile" | grep -qF "(v$version)" && return 0 + first="$(head -n1 "$msgfile")" + rest="$(tail -n +2 "$msgfile")" + if [ -n "$rest" ]; then + { printf '%s (v%s)\n' "$first" "$version"; printf '%s\n' "$rest"; } > "$msgfile" + else + printf '%s (v%s)\n' "$first" "$version" > "$msgfile" + fi +} + +case "$mode" in + precommit) bump_precommit ;; + prepmsg) bump_prepmsg "${2:-}" ;; + *) echo "version-bump: unknown mode '$mode'" >&2; exit 2 ;; +esac +exit 0