Files
wehub-resource-sync 8c89588461
CI / Coverage (push) Waiting to run
CI / Format (push) Waiting to run
CI / Clippy (push) Waiting to run
CI / Test (push) Waiting to run
CI / Nix Build (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:16:47 +08:00

168 lines
5.1 KiB
Bash
Executable File

#!/bin/bash
# Generate CHANGELOG.md from git commit history
# Follows Conventional Commits format
set -e
CHANGELOG_FILE="CHANGELOG.md"
TEMP_FILE="${CHANGELOG_FILE}.tmp"
# Function to generate changelog section for a range of commits
function generate_section_for_commits() {
local from_ref="$1"
local to_ref="$2"
# Build git log range
if [ -z "$to_ref" ]; then
local range="$from_ref"
else
local range="${to_ref}..${from_ref}"
fi
# Get commits and categorize them
local features=""
local fixes=""
local breaking=""
local others=""
# Process commits
while IFS= read -r commit; do
if [ -z "$commit" ]; then
continue
fi
local message=$(echo "$commit" | cut -d' ' -f2-)
local commit_hash=$(echo "$commit" | cut -d' ' -f1)
# Get repository URL from git remote
local repo_url=$(git remote get-url origin | sed 's/\.git$//' | sed 's/git@github\.com:/https:\/\/github\.com\//')
# Categorize commit based on conventional commit format
case "$message" in
feat*|feature*)
features="${features}- ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
fix*)
fixes="${fixes}- ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
*"BREAKING CHANGE"*|*"!"*)
breaking="${breaking}- ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
chore*|docs*|style*|refactor*|test*|build*|ci*)
others="${others}- ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
"Merge pull request"*)
# Extract PR info
local pr_info=$(echo "$message" | sed 's/Merge pull request #\([0-9]*\) from .*/PR #\1/')
others="${others}- ${pr_info}: ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
*)
others="${others}- ${message} ([${commit_hash:0:7}](${repo_url}/commit/${commit_hash}))\n"
;;
esac
done < <(git log --oneline --no-merges "$range" 2>/dev/null || true)
# Output categorized changes
local has_content=false
if [ -n "$breaking" ]; then
echo "### 💥 BREAKING CHANGES"
echo ""
echo -e "$breaking"
has_content=true
fi
if [ -n "$features" ]; then
echo "### ✨ Features"
echo ""
echo -e "$features"
has_content=true
fi
if [ -n "$fixes" ]; then
echo "### 🐛 Bug Fixes"
echo ""
echo -e "$fixes"
has_content=true
fi
if [ -n "$others" ]; then
echo "### 📝 Other Changes"
echo ""
echo -e "$others"
has_content=true
fi
if [ "$has_content" = false ]; then
echo "- No notable changes"
echo ""
fi
echo ""
}
# Get the current version from Cargo.toml
CURRENT_VERSION=$(grep "^version" Cargo.toml | sed 's/version = "\(.*\)"/\1/')
# Create header
cat > "$TEMP_FILE" << EOF
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
EOF
# Get all tags sorted by version (newest first)
TAGS=$(git tag -l --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+' | head -20)
# If no tags exist, show unreleased changes
if [ -z "$TAGS" ]; then
echo "## [Unreleased]" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
generate_section_for_commits "HEAD" "" >> "$TEMP_FILE"
else
# Get latest tag
LATEST_TAG=$(echo "$TAGS" | head -1)
# Check if there are unreleased changes
UNRELEASED_COMMITS=$(git log --oneline "${LATEST_TAG}..HEAD" --pretty=format:"%s" | wc -l)
if [ "$UNRELEASED_COMMITS" -gt 0 ]; then
echo "## [Unreleased]" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
generate_section_for_commits "HEAD" "$LATEST_TAG" >> "$TEMP_FILE"
fi
# Generate sections for each tag
PREV_TAG=""
TAGS_ARRAY=($TAGS)
for i in "${!TAGS_ARRAY[@]}"; do
TAG="${TAGS_ARRAY[$i]}"
TAG_DATE=$(git log -1 --format="%ai" "$TAG" | cut -d' ' -f1)
CLEAN_VERSION=$(echo "$TAG" | sed 's/^v//')
echo "## [$CLEAN_VERSION] - $TAG_DATE" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
# Get the next (older) tag for the range
if [ $((i + 1)) -lt ${#TAGS_ARRAY[@]} ]; then
PREV_TAG="${TAGS_ARRAY[$((i + 1))]}"
else
PREV_TAG=""
fi
generate_section_for_commits "$TAG" "$PREV_TAG" >> "$TEMP_FILE"
done
fi
# Replace the old changelog with the new one
mv "$TEMP_FILE" "$CHANGELOG_FILE"
echo "✅ CHANGELOG.md has been generated successfully!"
echo "📄 Preview:"
echo "----------------------------------------"
head -20 "$CHANGELOG_FILE"
echo "----------------------------------------"