diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..74f323d --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,89 @@ +#!/bin/bash + +# Colors for output +CYAN='\033[0;36m' +YELLOW='\033[1;33m' +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NOCOLOR='\033[0m' + +# Get the directory where this hook is located +HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Go up from .git/hooks/ to repo root +REPO_ROOT="$(cd "$HOOK_DIR/../.." && pwd)" +CHANGELOG_SCRIPT="$REPO_ROOT/scripts/update_changelog.sh" +PREVIEW_FILE="$REPO_ROOT/.changelog_preview.tmp" +VERSION_FILE="$REPO_ROOT/.changelog_version.tmp" + +# Only run changelog update if there are actual code changes (not just changelog files) +STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) +if [ -z "$STAGED_FILES" ]; then + # No staged files, exit + exit 0 +fi + +# Check if only CHANGELOG.md and/or Makefile are being committed +OTHER_FILES=$(echo "$STAGED_FILES" | grep -v "^CHANGELOG.md$" | grep -v "^Makefile$") +if [ -z "$OTHER_FILES" ]; then + # Only changelog files are being committed, skip update + exit 0 +fi + +# Update changelog before commit +if [ -f "$CHANGELOG_SCRIPT" ]; then + echo -e "\n${CYAN}Updating changelog...${NOCOLOR}" + + # Set environment variable to indicate we're running from pre-commit + export CHANGELOG_CONTEXT=pre-commit + + bash "$CHANGELOG_SCRIPT" + changelog_status=$? + if [ $changelog_status -ne 0 ]; then + echo -e "${RED}Commit aborted: changelog update failed.${NOCOLOR}" + exit 1 + fi + + # Show preview if changelog was updated + if [ -f "$PREVIEW_FILE" ] && [ -f "$VERSION_FILE" ]; then + NEW_VERSION=$(cat "$VERSION_FILE") + PREVIEW_CONTENT=$(cat "$PREVIEW_FILE") + + echo "" + echo -e "${BLUE}========================================================================${NOCOLOR}" + echo -e "${CYAN} CHANGELOG PREVIEW${NOCOLOR}" + echo -e "${BLUE}========================================================================${NOCOLOR}" + echo "" + echo -e "${GREEN}New Version: ${YELLOW}$NEW_VERSION${NOCOLOR}" + echo "" + echo -e "${CYAN}Changelog Entry:${NOCOLOR}" + echo -e "${BLUE}────────────────────────────────────────────────────────────────────────${NOCOLOR}" + echo -e "$PREVIEW_CONTENT" + echo -e "${BLUE}────────────────────────────────────────────────────────────────────────${NOCOLOR}" + echo "" + echo -e "${YELLOW}Do you want to proceed with the commit? (yes/no):${NOCOLOR} " + # Read from /dev/tty to ensure we can read from terminal even in git hook context + read -r confirmation < /dev/tty + + if [ "$confirmation" != "yes" ]; then + echo -e "${RED}Commit aborted by user.${NOCOLOR}" + echo -e "${YELLOW}To revert changes, run:${NOCOLOR}" + echo -e " git checkout CHANGELOG.md Makefile" + # Clean up temp files + rm -f "$PREVIEW_FILE" "$VERSION_FILE" + exit 1 + fi + + echo -e "${GREEN}Proceeding with commit...${NOCOLOR}" + + # Add the updated CHANGELOG.md and Makefile to the current commit + echo -e "${CYAN}Staging CHANGELOG.md and Makefile...${NOCOLOR}" + git add CHANGELOG.md Makefile + + # Clean up temp files + rm -f "$PREVIEW_FILE" "$VERSION_FILE" + fi +else + echo -e "${YELLOW}Warning: changelog update script not found at $CHANGELOG_SCRIPT${NOCOLOR}" +fi + diff --git a/.githooks/pre-push b/.githooks/pre-push index a19b525..b340af6 100644 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -2,81 +2,11 @@ # Colors for output CYAN='\033[0;36m' -YELLOW='\033[1;33m' GREEN='\033[0;32m' RED='\033[0;31m' -BLUE='\033[0;34m' NOCOLOR='\033[0m' -# Get the directory where this hook is located -HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# Go up from .git/hooks/ to repo root -REPO_ROOT="$(cd "$HOOK_DIR/../.." && pwd)" -CHANGELOG_SCRIPT="$REPO_ROOT/scripts/update_changelog.sh" -PREVIEW_FILE="$REPO_ROOT/.changelog_preview.tmp" -VERSION_FILE="$REPO_ROOT/.changelog_version.tmp" - -# Update changelog before push -if [ -f "$CHANGELOG_SCRIPT" ]; then - echo -e "\n${CYAN}Updating changelog...${NOCOLOR}" - bash "$CHANGELOG_SCRIPT" - changelog_status=$? - if [ $changelog_status -ne 0 ]; then - echo -e "${RED}Push aborted: changelog update failed.${NOCOLOR}" - exit 1 - fi - - # Show preview if changelog was updated - if [ -f "$PREVIEW_FILE" ] && [ -f "$VERSION_FILE" ]; then - NEW_VERSION=$(cat "$VERSION_FILE") - PREVIEW_CONTENT=$(cat "$PREVIEW_FILE") - - echo "" - echo -e "${BLUE}========================================================================${NOCOLOR}" - echo -e "${CYAN} CHANGELOG PREVIEW${NOCOLOR}" - echo -e "${BLUE}========================================================================${NOCOLOR}" - echo "" - echo -e "${GREEN}New Version: ${YELLOW}$NEW_VERSION${NOCOLOR}" - echo "" - echo -e "${CYAN}Changelog Entry:${NOCOLOR}" - echo -e "${BLUE}────────────────────────────────────────────────────────────────────────${NOCOLOR}" - echo -e "$PREVIEW_CONTENT" - echo -e "${BLUE}────────────────────────────────────────────────────────────────────────${NOCOLOR}" - echo "" - echo -e "${YELLOW}Do you want to proceed with the push? (yes/no):${NOCOLOR} " - # Read from /dev/tty to ensure we can read from terminal even in git hook context - read -r confirmation < /dev/tty - - if [ "$confirmation" != "yes" ]; then - echo -e "${RED}Push aborted by user.${NOCOLOR}" - echo -e "${YELLOW}To revert changes, run:${NOCOLOR}" - echo -e " git checkout CHANGELOG.md Makefile" - # Clean up temp files - rm -f "$PREVIEW_FILE" "$VERSION_FILE" - exit 1 - fi - - echo -e "${GREEN}Proceeding with push...${NOCOLOR}" - - # Commit the updated CHANGELOG.md and Makefile - cd "$REPO_ROOT" - echo -e "${CYAN}Staging CHANGELOG.md and Makefile...${NOCOLOR}" - git add CHANGELOG.md Makefile - - echo -e "${CYAN}Committing changes...${NOCOLOR}" - NEW_VERSION=$(cat "$VERSION_FILE") - git commit -m "chore: update changelog and version to $NEW_VERSION" || { - # If commit fails (e.g., no changes to commit), continue anyway - echo -e "${YELLOW}Note: Could not commit changes (may already be committed)${NOCOLOR}" - } - - # Clean up temp files - rm -f "$PREVIEW_FILE" "$VERSION_FILE" - fi -else - echo -e "${YELLOW}Warning: changelog update script not found at $CHANGELOG_SCRIPT${NOCOLOR}" -fi - +# Run tests before push echo -e "\n${CYAN}Running tests...${NOCOLOR}" go test ./... # Runs all tests in your repo status=$? diff --git a/CHANGELOG.md b/CHANGELOG.md index b1455f0..363cd85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,21 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant ### Deprecated ### Fixed +## [0.53.17] - 2025-11-03 + +### Added +- Added a new Git `pre-commit` hook to automatically update the changelog and version before committing, ensuring version consistency. + +### Changed +- Refactored the `update_changelog.sh` script to support different execution contexts (pre-commit vs. pre-push), allowing it to analyze only staged changes during commit. +- The Git `pre-push` hook was simplified by removing the changelog update logic, which is now handled by the `pre-commit` hook. + +### Deprecated + +### Removed + +### Fixed +\n ## [0.53.16] - 2025-11-03 ### Added diff --git a/Makefile b/Makefile index 1c10d96..ee694ad 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test-e2e: .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports install-hooks -VERSION := 0.53.16 +VERSION := 0.53.17 COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' diff --git a/scripts/update_changelog.sh b/scripts/update_changelog.sh index 334b2c6..1f10e1d 100755 --- a/scripts/update_changelog.sh +++ b/scripts/update_changelog.sh @@ -93,47 +93,76 @@ fi # Gather all git diffs log "Collecting git diffs..." -# Unstaged changes -UNSTAGED_DIFF=$(git diff 2>/dev/null || echo "") -UNSTAGED_COUNT=$(echo "$UNSTAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") -[ -z "$UNSTAGED_COUNT" ] && UNSTAGED_COUNT="0" - -# Staged changes -STAGED_DIFF=$(git diff --cached 2>/dev/null || echo "") -STAGED_COUNT=$(echo "$STAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") -[ -z "$STAGED_COUNT" ] && STAGED_COUNT="0" - -# Unpushed commits -UNPUSHED_DIFF=$(git diff "$REMOTE_BRANCH"..HEAD 2>/dev/null || echo "") -UNPUSHED_COMMITS=$(git rev-list --count "$REMOTE_BRANCH"..HEAD 2>/dev/null || echo "0") -[ -z "$UNPUSHED_COMMITS" ] && UNPUSHED_COMMITS="0" - -# Check if the only unpushed commit is a changelog update commit -# If so, exclude it from the diff to avoid infinite loops -if [ "$UNPUSHED_COMMITS" -gt 0 ]; then - LATEST_COMMIT_MSG=$(git log -1 --pretty=%B HEAD 2>/dev/null || echo "") - if echo "$LATEST_COMMIT_MSG" | grep -q "chore: update changelog and version"; then - # If the latest commit is a changelog commit, check if there are other commits - if [ "$UNPUSHED_COMMITS" -eq 1 ]; then - log "Latest commit is a changelog update. No other changes detected. Skipping changelog update." - # Clean up any old preview files - rm -f "$REPO_ROOT/.changelog_preview.tmp" "$REPO_ROOT/.changelog_version.tmp" - exit 0 - else - # Multiple commits, exclude the latest changelog commit from diff - log "Multiple unpushed commits detected. Excluding latest changelog commit from analysis." - # Get all commits except the latest one - UNPUSHED_DIFF=$(git diff "$REMOTE_BRANCH"..HEAD~1 2>/dev/null || echo "") - UNPUSHED_COMMITS=$(git rev-list --count "$REMOTE_BRANCH"..HEAD~1 2>/dev/null || echo "0") - [ -z "$UNPUSHED_COMMITS" ] && UNPUSHED_COMMITS="0" +# Check if running from pre-commit context +if [ "$CHANGELOG_CONTEXT" = "pre-commit" ]; then + log "Running in pre-commit context - analyzing staged changes only" + + # Unstaged changes (usually none in pre-commit, but check anyway) + UNSTAGED_DIFF=$(git diff 2>/dev/null || echo "") + UNSTAGED_COUNT=$(echo "$UNSTAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") + [ -z "$UNSTAGED_COUNT" ] && UNSTAGED_COUNT="0" + + # Staged changes (these are what we're committing) + STAGED_DIFF=$(git diff --cached 2>/dev/null || echo "") + STAGED_COUNT=$(echo "$STAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") + [ -z "$STAGED_COUNT" ] && STAGED_COUNT="0" + + # No unpushed commits analysis in pre-commit context + UNPUSHED_DIFF="" + UNPUSHED_COMMITS="0" + + log "Found: $UNSTAGED_COUNT unstaged file(s), $STAGED_COUNT staged file(s)" +else + # Pre-push context - analyze everything + # Unstaged changes + UNSTAGED_DIFF=$(git diff 2>/dev/null || echo "") + UNSTAGED_COUNT=$(echo "$UNSTAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") + [ -z "$UNSTAGED_COUNT" ] && UNSTAGED_COUNT="0" + + # Staged changes + STAGED_DIFF=$(git diff --cached 2>/dev/null || echo "") + STAGED_COUNT=$(echo "$STAGED_DIFF" | grep -c "^diff\|^index" 2>/dev/null || echo "0") + [ -z "$STAGED_COUNT" ] && STAGED_COUNT="0" + + # Unpushed commits + UNPUSHED_DIFF=$(git diff "$REMOTE_BRANCH"..HEAD 2>/dev/null || echo "") + UNPUSHED_COMMITS=$(git rev-list --count "$REMOTE_BRANCH"..HEAD 2>/dev/null || echo "0") + [ -z "$UNPUSHED_COMMITS" ] && UNPUSHED_COMMITS="0" + + # Check if the only unpushed commit is a changelog update commit + # If so, exclude it from the diff to avoid infinite loops + if [ "$UNPUSHED_COMMITS" -gt 0 ]; then + LATEST_COMMIT_MSG=$(git log -1 --pretty=%B HEAD 2>/dev/null || echo "") + if echo "$LATEST_COMMIT_MSG" | grep -q "chore: update changelog and version"; then + # If the latest commit is a changelog commit, check if there are other commits + if [ "$UNPUSHED_COMMITS" -eq 1 ]; then + log "Latest commit is a changelog update. No other changes detected. Skipping changelog update." + # Clean up any old preview files + rm -f "$REPO_ROOT/.changelog_preview.tmp" "$REPO_ROOT/.changelog_version.tmp" + exit 0 + else + # Multiple commits, exclude the latest changelog commit from diff + log "Multiple unpushed commits detected. Excluding latest changelog commit from analysis." + # Get all commits except the latest one + UNPUSHED_DIFF=$(git diff "$REMOTE_BRANCH"..HEAD~1 2>/dev/null || echo "") + UNPUSHED_COMMITS=$(git rev-list --count "$REMOTE_BRANCH"..HEAD~1 2>/dev/null || echo "0") + [ -z "$UNPUSHED_COMMITS" ] && UNPUSHED_COMMITS="0" + fi fi fi + + log "Found: $UNSTAGED_COUNT unstaged file(s), $STAGED_COUNT staged file(s), $UNPUSHED_COMMITS unpushed commit(s)" fi -log "Found: $UNSTAGED_COUNT unstaged file(s), $STAGED_COUNT staged file(s), $UNPUSHED_COMMITS unpushed commit(s)" - # Combine all diffs -ALL_DIFFS="${UNSTAGED_DIFF} +if [ "$CHANGELOG_CONTEXT" = "pre-commit" ]; then + ALL_DIFFS="${UNSTAGED_DIFF} +--- +STAGED CHANGES: +--- +${STAGED_DIFF}" +else + ALL_DIFFS="${UNSTAGED_DIFF} --- STAGED CHANGES: --- @@ -142,13 +171,23 @@ ${STAGED_DIFF} UNPUSHED COMMITS: --- ${UNPUSHED_DIFF}" +fi # Check if there are any changes -if [ -z "$(echo "$UNSTAGED_DIFF$STAGED_DIFF$UNPUSHED_DIFF" | tr -d '[:space:]')" ]; then - log "No changes detected (unstaged, staged, or unpushed). Skipping changelog update." - # Clean up any old preview files - rm -f "$REPO_ROOT/.changelog_preview.tmp" "$REPO_ROOT/.changelog_version.tmp" - exit 0 +if [ "$CHANGELOG_CONTEXT" = "pre-commit" ]; then + # In pre-commit, only check staged changes + if [ -z "$(echo "$STAGED_DIFF" | tr -d '[:space:]')" ]; then + log "No staged changes detected. Skipping changelog update." + rm -f "$REPO_ROOT/.changelog_preview.tmp" "$REPO_ROOT/.changelog_version.tmp" + exit 0 + fi +else + # In pre-push, check all changes + if [ -z "$(echo "$UNSTAGED_DIFF$STAGED_DIFF$UNPUSHED_DIFF" | tr -d '[:space:]')" ]; then + log "No changes detected (unstaged, staged, or unpushed). Skipping changelog update." + rm -f "$REPO_ROOT/.changelog_preview.tmp" "$REPO_ROOT/.changelog_version.tmp" + exit 0 + fi fi # Get current version from Makefile