#!/bin/bash # increment_and_push.sh - Version increment and git automation script for n_os_tr # Usage: # ./increment_and_push.sh "meaningful git comment" # ./increment_and_push.sh --set-version vX.Y.Z "meaningful git comment" # ./increment_and_push.sh -m "meaningful git comment" # minor bump # ./increment_and_push.sh -M "meaningful git comment" # major bump set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' print_info() { echo -e "${BLUE}[INFO]${NC} $1"; } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } show_usage() { cat </dev/null 2>&1; then print_error "Not in a git repository" exit 1 fi } current_branch() { git branch --show-current } latest_version_tag() { git tag -l 'v*.*.*' | sort -V | tail -n 1 } compute_next_version() { local bump_type="$1" local latest_tag latest_tag="$(latest_version_tag)" if [[ -z "$latest_tag" ]]; then latest_tag="v0.0.0" print_warning "No existing semantic tags found. Starting from $latest_tag" >&2 fi local version="${latest_tag#v}" if [[ ! "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then print_error "Latest tag '$latest_tag' is not in vX.Y.Z format" exit 1 fi local major="${BASH_REMATCH[1]}" local minor="${BASH_REMATCH[2]}" local patch="${BASH_REMATCH[3]}" case "$bump_type" in major) major=$((major + 1)) minor=0 patch=0 ;; minor) minor=$((minor + 1)) patch=0 ;; patch) patch=$((patch + 1)) ;; *) print_error "Unknown bump type: $bump_type" exit 1 ;; esac echo "v${major}.${minor}.${patch}" } COMMIT_MESSAGE="" TARGET_VERSION="" BUMP_TYPE="patch" while [[ $# -gt 0 ]]; do case "$1" in -p|--patch) BUMP_TYPE="patch" shift ;; -m|--minor) BUMP_TYPE="minor" shift ;; -M|--major) BUMP_TYPE="major" shift ;; --set-version) if [[ $# -lt 2 ]]; then print_error "--set-version requires a value like v1.2.3" exit 1 fi TARGET_VERSION="$2" shift 2 ;; -h|--help) show_usage exit 0 ;; *) if [[ -z "$COMMIT_MESSAGE" ]]; then COMMIT_MESSAGE="$1" else COMMIT_MESSAGE+=" $1" fi shift ;; esac done if [[ -z "$COMMIT_MESSAGE" ]]; then print_error "Commit message is required" show_usage exit 1 fi check_git_repo if [[ -n "$TARGET_VERSION" ]]; then if [[ ! "$TARGET_VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then print_error "Invalid --set-version value '$TARGET_VERSION' (expected vX.Y.Z)" exit 1 fi NEW_VERSION="$TARGET_VERSION" else NEW_VERSION="$(compute_next_version "$BUMP_TYPE")" fi print_info "Target version: $NEW_VERSION" print_info "Staging changes..." git add -A if git diff --staged --quiet; then print_warning "No staged changes to commit" exit 0 fi FULL_COMMIT_MESSAGE="$NEW_VERSION - $COMMIT_MESSAGE" print_info "Committing: $FULL_COMMIT_MESSAGE" git commit -m "$FULL_COMMIT_MESSAGE" if git rev-parse "$NEW_VERSION" >/dev/null 2>&1; then print_warning "Tag $NEW_VERSION already exists locally. Re-pointing to current commit." git tag -d "$NEW_VERSION" >/dev/null 2>&1 || true fi print_info "Creating tag: $NEW_VERSION" git tag "$NEW_VERSION" BRANCH="$(current_branch)" if [[ -z "$BRANCH" ]]; then print_error "Could not determine current branch" exit 1 fi print_info "Pushing branch '$BRANCH'..." if ! git push origin "$BRANCH"; then print_warning "Initial push failed. Attempting rebase onto origin/$BRANCH and retrying..." git pull --rebase origin "$BRANCH" git push origin "$BRANCH" fi print_info "Pushing tag '$NEW_VERSION'..." if ! git push origin "$NEW_VERSION"; then print_warning "Tag push failed; attempting force update for tag '$NEW_VERSION'" git push --force origin "$NEW_VERSION" fi print_success "Done: committed and pushed $NEW_VERSION"