#!/bin/bash # Generate changelog from git history for Woodpecker CI releases # Groups commits by conventional commit types (feat, fix, chore, refactor) # # Usage: ./generate-changelog.sh [output-file] # tag: Git tag to generate changelog for (e.g., v1.0.0) # output-file: Optional output file path (default: CHANGELOG.md) set -e # Check if tag argument is provided if [ -z "$1" ]; then echo "Error: Tag argument required" echo "Usage: $0 [output-file]" exit 1 fi TAG="$1" OUTPUT_FILE="${2:-CHANGELOG.md}" echo "Generating changelog for ${TAG}..." # Get previous tag (if exists) PREV_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "") if [ -z "$PREV_TAG" ]; then echo "No previous tag found. This is the first release." # Get the first commit in the repository FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD) COMMIT_RANGE="${FIRST_COMMIT}..${TAG}" echo "Generating changelog from first commit to ${TAG}" else COMMIT_RANGE="${PREV_TAG}..${TAG}" echo "Generating changelog from ${PREV_TAG} to ${TAG}" fi # Initialize changelog file echo "# Release ${TAG}" > "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" if [ -z "$PREV_TAG" ]; then echo "First release of Worldhopper! 🎉" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" fi # Get all commits in range COMMITS=$(git log "${COMMIT_RANGE}" --pretty=format:"%H|%s" 2>/dev/null || echo "") if [ -z "$COMMITS" ]; then echo "No commits found in range" >> "$OUTPUT_FILE" else # Arrays to hold categorized commits FEATURES="" FIXES="" CHORES="" REFACTORS="" OTHERS="" # Parse commits and categorize while IFS='|' read -r hash message; do # Skip empty lines [ -z "$hash" ] && continue case "$message" in feat:*|feat\(*) FEATURES="${FEATURES}- ${message#feat:} (${hash:0:7})\n" ;; fix:*|fix\(*) FIXES="${FIXES}- ${message#fix:} (${hash:0:7})\n" ;; chore:*|chore\(*) CHORES="${CHORES}- ${message#chore:} (${hash:0:7})\n" ;; refactor:*|refactor\(*) REFACTORS="${REFACTORS}- ${message#refactor:} (${hash:0:7})\n" ;; *) OTHERS="${OTHERS}- ${message} (${hash:0:7})\n" ;; esac done <<< "$COMMITS" # Write categorized sections if [ -n "$FEATURES" ]; then echo "## ✨ Features" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" echo -e "$FEATURES" >> "$OUTPUT_FILE" fi if [ -n "$FIXES" ]; then echo "## 🐛 Bug Fixes" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" echo -e "$FIXES" >> "$OUTPUT_FILE" fi if [ -n "$REFACTORS" ]; then echo "## ♻️ Refactoring" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" echo -e "$REFACTORS" >> "$OUTPUT_FILE" fi if [ -n "$CHORES" ]; then echo "## 🔧 Chores" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" echo -e "$CHORES" >> "$OUTPUT_FILE" fi if [ -n "$OTHERS" ]; then echo "## 📝 Other Changes" >> "$OUTPUT_FILE" echo "" >> "$OUTPUT_FILE" echo -e "$OTHERS" >> "$OUTPUT_FILE" fi fi echo "" >> "$OUTPUT_FILE" echo "---" >> "$OUTPUT_FILE" # Add full changelog link if we have git forge info if [ -n "$CI_FORGE_URL" ] && [ -n "$CI_REPO" ]; then COMPARE_BASE="${PREV_TAG:-$(git rev-list --max-parents=0 HEAD | head -1)}" echo "**Full Changelog**: ${CI_FORGE_URL}/${CI_REPO}/compare/${COMPARE_BASE}...${TAG}" >> "$OUTPUT_FILE" elif [ -n "$PREV_TAG" ]; then echo "**Commits**: \`git log ${PREV_TAG}..${TAG}\`" >> "$OUTPUT_FILE" else echo "**First Release**" >> "$OUTPUT_FILE" fi echo "" echo "Changelog generated successfully: ${OUTPUT_FILE}" echo "" cat "$OUTPUT_FILE"