|
| 1 | +#!/bin/bash |
| 2 | +set -e |
| 3 | + |
| 4 | +# Script to generate CHANGELOG.md based on git commit history |
| 5 | +# Usage: ./generate-changelog.sh <path> <new_version> <old_version> |
| 6 | +# |
| 7 | +# Arguments: |
| 8 | +# path: Path to the directory (e.g., "." for root plugin) |
| 9 | +# new_version: The new version being released (e.g., "1.2.3") |
| 10 | +# old_version: The previous version (e.g., "1.2.2") - optional, will auto-detect from plugin.json |
| 11 | + |
| 12 | +PATH_DIR="$1" |
| 13 | +NEW_VERSION="$2" |
| 14 | +OLD_VERSION="$3" |
| 15 | + |
| 16 | +if [ -z "$PATH_DIR" ] || [ -z "$NEW_VERSION" ]; then |
| 17 | + echo "Usage: $0 <path> <new_version> [old_version]" |
| 18 | + echo "Example: $0 . 1.2.3" |
| 19 | + exit 1 |
| 20 | +fi |
| 21 | + |
| 22 | +CHANGELOG_FILE="$PATH_DIR/CHANGELOG.md" |
| 23 | +TEMP_FILE=$(mktemp) |
| 24 | + |
| 25 | +# Determine the previous version if not provided |
| 26 | +if [ -z "$OLD_VERSION" ]; then |
| 27 | + if [ -f "$PATH_DIR/.claude-plugin/plugin.json" ]; then |
| 28 | + OLD_VERSION=$(jq -r '.version' "$PATH_DIR/.claude-plugin/plugin.json" 2>/dev/null || echo "") |
| 29 | + fi |
| 30 | +fi |
| 31 | + |
| 32 | +# Determine git range for commits |
| 33 | +# Get the last 50 commits and filter later |
| 34 | +GIT_RANGE="HEAD~50..HEAD" |
| 35 | + |
| 36 | +# Get commits for this path, excluding version bump commits and website changes |
| 37 | +COMMITS=$(git log $GIT_RANGE --pretty=format:"%h|%s|%an|%ad" --date=short -- "$PATH_DIR" ':!website' 2>/dev/null | grep -v "\[skip ci\]" | grep -v "chore(release):" | grep -v "chore(plugin): bump" || true) |
| 38 | + |
| 39 | +# If we still don't have commits, try without range limit |
| 40 | +if [ -z "$COMMITS" ]; then |
| 41 | + COMMITS=$(git log --all --pretty=format:"%h|%s|%an|%ad" --date=short -- "$PATH_DIR" ':!website' 2>/dev/null | grep -v "\[skip ci\]" | grep -v "chore(release):" | grep -v "chore(plugin): bump" | head -20 || true) |
| 42 | +fi |
| 43 | + |
| 44 | +if [ -z "$COMMITS" ]; then |
| 45 | + echo "No commits found for $PATH_DIR in range $GIT_RANGE" |
| 46 | + exit 0 |
| 47 | +fi |
| 48 | + |
| 49 | +# Parse commits into categories |
| 50 | +FEATURES="" |
| 51 | +FIXES="" |
| 52 | +REFACTORS="" |
| 53 | +CHORES="" |
| 54 | +BREAKING="" |
| 55 | +OTHER="" |
| 56 | + |
| 57 | +while IFS='|' read -r hash subject _author _date; do |
| 58 | + # Skip empty lines |
| 59 | + [ -z "$hash" ] && continue |
| 60 | + |
| 61 | + # Remove scope from subject for cleaner display |
| 62 | + CLEAN_SUBJECT=$(echo "$subject" | sed -E 's/^[a-z]+(\([^)]+\))?!?: //') |
| 63 | + |
| 64 | + # Format entry |
| 65 | + ENTRY="- $CLEAN_SUBJECT ([$hash](../../commit/$hash))" |
| 66 | + |
| 67 | + # Categorize commit (use newline only between entries, not before first) |
| 68 | + if echo "$subject" | grep -qE '^[a-z]+(\([^)]+\))?!:' || echo "$subject" | grep -q 'BREAKING CHANGE'; then |
| 69 | + [ -n "$BREAKING" ] && BREAKING="$BREAKING\n$ENTRY" || BREAKING="$ENTRY" |
| 70 | + elif echo "$subject" | grep -qE '^feat(\([^)]+\))?:'; then |
| 71 | + [ -n "$FEATURES" ] && FEATURES="$FEATURES\n$ENTRY" || FEATURES="$ENTRY" |
| 72 | + elif echo "$subject" | grep -qE '^fix(\([^)]+\))?:'; then |
| 73 | + [ -n "$FIXES" ] && FIXES="$FIXES\n$ENTRY" || FIXES="$ENTRY" |
| 74 | + elif echo "$subject" | grep -qE '^refactor(\([^)]+\))?:'; then |
| 75 | + [ -n "$REFACTORS" ] && REFACTORS="$REFACTORS\n$ENTRY" || REFACTORS="$ENTRY" |
| 76 | + elif echo "$subject" | grep -qE '^chore(\([^)]+\))?:'; then |
| 77 | + [ -n "$CHORES" ] && CHORES="$CHORES\n$ENTRY" || CHORES="$ENTRY" |
| 78 | + else |
| 79 | + [ -n "$OTHER" ] && OTHER="$OTHER\n$ENTRY" || OTHER="$ENTRY" |
| 80 | + fi |
| 81 | +done <<<"$COMMITS" |
| 82 | + |
| 83 | +# Generate changelog header |
| 84 | +{ |
| 85 | + echo "# Changelog" |
| 86 | + echo "" |
| 87 | + echo "All notable changes to this project will be documented in this file." |
| 88 | + echo "" |
| 89 | + echo "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)," |
| 90 | + echo "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)." |
| 91 | + echo "" |
| 92 | + echo "## [$NEW_VERSION] - $(date +%Y-%m-%d)" |
| 93 | + echo "" |
| 94 | +} >"$TEMP_FILE" |
| 95 | + |
| 96 | +# Add breaking changes section if any |
| 97 | +if [ -n "$BREAKING" ]; then |
| 98 | + { |
| 99 | + echo "### BREAKING CHANGES" |
| 100 | + echo "" |
| 101 | + echo -e "$BREAKING" |
| 102 | + echo "" |
| 103 | + } >>"$TEMP_FILE" |
| 104 | +fi |
| 105 | + |
| 106 | +# Add features section if any |
| 107 | +if [ -n "$FEATURES" ]; then |
| 108 | + { |
| 109 | + echo "### Added" |
| 110 | + echo "" |
| 111 | + echo -e "$FEATURES" |
| 112 | + echo "" |
| 113 | + } >>"$TEMP_FILE" |
| 114 | +fi |
| 115 | + |
| 116 | +# Add fixes section if any |
| 117 | +if [ -n "$FIXES" ]; then |
| 118 | + { |
| 119 | + echo "### Fixed" |
| 120 | + echo "" |
| 121 | + echo -e "$FIXES" |
| 122 | + echo "" |
| 123 | + } >>"$TEMP_FILE" |
| 124 | +fi |
| 125 | + |
| 126 | +# Add refactors section if any |
| 127 | +if [ -n "$REFACTORS" ]; then |
| 128 | + { |
| 129 | + echo "### Changed" |
| 130 | + echo "" |
| 131 | + echo -e "$REFACTORS" |
| 132 | + echo "" |
| 133 | + } >>"$TEMP_FILE" |
| 134 | +fi |
| 135 | + |
| 136 | +# Add other changes if any |
| 137 | +if [ -n "$OTHER" ]; then |
| 138 | + { |
| 139 | + echo "### Other" |
| 140 | + echo "" |
| 141 | + echo -e "$OTHER" |
| 142 | + echo "" |
| 143 | + } >>"$TEMP_FILE" |
| 144 | +fi |
| 145 | + |
| 146 | +# If existing changelog exists, append old entries (excluding the header) |
| 147 | +if [ -f "$CHANGELOG_FILE" ]; then |
| 148 | + # Skip the first 6 lines (header) and append the rest |
| 149 | + tail -n +7 "$CHANGELOG_FILE" >>"$TEMP_FILE" 2>/dev/null || true |
| 150 | +fi |
| 151 | + |
| 152 | +# Remove consecutive blank lines and ensure single trailing newline |
| 153 | +perl -i -0777 -pe 's/\n\n\n+/\n\n/g' "$TEMP_FILE" |
| 154 | +printf '%s\n' "$(cat "$TEMP_FILE")" >"$TEMP_FILE" |
| 155 | + |
| 156 | +# Move temp file to final location |
| 157 | +mv "$TEMP_FILE" "$CHANGELOG_FILE" |
| 158 | + |
| 159 | +echo "Changelog generated at $CHANGELOG_FILE" |
0 commit comments