Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions .github/scripts/generate-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/bin/bash
set -euo pipefail

# Usage: generate-changelog.sh <output_file> [tag_or_range]
# If tag_or_range is empty, generates from latest tag to HEAD

OUTPUT_FILE="$1"
TAG_OR_RANGE="${2:-}"

mkdir -p "$(dirname "$OUTPUT_FILE")"

if [[ -z "$TAG_OR_RANGE" ]]; then
LATEST_TAG=$(git describe --tags --abbrev=0 --match "v*.*.*" 2>/dev/null || echo "")
if [[ -z "$LATEST_TAG" ]]; then
LOG_RANGE=""
CONTEXT_MSG="All unreleased changes:"
VERSION_TITLE="Development Version"
else
LOG_RANGE="$LATEST_TAG..HEAD"
CONTEXT_MSG="Changes since $LATEST_TAG:"
VERSION_TITLE="Development Version"
fi
else
VERSION="$TAG_OR_RANGE"
PREVIOUS_TAG=$(git describe --tags --abbrev=0 --match "v*.*.*" "$TAG_OR_RANGE^" 2>/dev/null || echo "")
if [[ -z "$PREVIOUS_TAG" ]]; then
LOG_RANGE="$TAG_OR_RANGE"
CONTEXT_MSG="All changes in this release:"
else
LOG_RANGE="$PREVIOUS_TAG..$TAG_OR_RANGE"
CONTEXT_MSG="Changes since $PREVIOUS_TAG:"
fi
VERSION_TITLE="Version ${VERSION#v}"
fi

mapfile -t COMMITS < <(git log --pretty=format:'%H' $LOG_RANGE)
FEATURES=""
FIXES=""
MISC=""

for commit_hash in "${COMMITS[@]}"; do
commit_msg=$(git log -1 --pretty=format:'%s' "$commit_hash")
commit_body=$(git log -1 --pretty=format:'%b' "$commit_hash")

changelog_type=""

if echo "$commit_msg" | grep -iqE 'changelog[(: ]'; then
if echo "$commit_msg" | grep -iqE 'changelog\((feature|feat)\)'; then
changelog_type="feature"
elif echo "$commit_msg" | grep -iqE 'changelog\((fix)\)'; then
changelog_type="fix"
elif echo "$commit_msg" | grep -iqE 'changelog\((misc)\)'; then
changelog_type="misc"
fi
fi

if [ -z "$changelog_type" ]; then
if echo "$commit_body" | grep -iqE 'changelog[(: ]'; then
if echo "$commit_body" | grep -iqE 'changelog\((feature|feat)\)'; then
changelog_type="feature"
elif echo "$commit_body" | grep -iqE 'changelog\((fix)\)'; then
changelog_type="fix"
elif echo "$commit_body" | grep -iqE 'changelog\((misc)\)'; then
changelog_type="misc"
fi
fi
fi

if [ -z "$changelog_type" ]; then
if echo "$commit_msg" | grep -iqE '^(feat|feature)(\(.*\))?:'; then
changelog_type="feature"
commit_msg=$(echo "$commit_msg" | sed -E 's/^(feat|feature)(\(.*\))?:[[:space:]]*//')
elif echo "$commit_msg" | grep -iqE '^fix(\(.*\))?:'; then
changelog_type="fix"
commit_msg=$(echo "$commit_msg" | sed -E 's/^fix(\(.*\))?:[[:space:]]*//')
elif echo "$commit_msg" | grep -iqE '^(chore|docs|style|refactor|perf|test)(\(.*\))?:'; then
changelog_type="misc"
commit_msg=$(echo "$commit_msg" | sed -E 's/^(chore|docs|style|refactor|perf|test)(\(.*\))?:[[:space:]]*//')
fi
fi

if [ -n "$changelog_type" ]; then
body_content=$(echo "$commit_body" | awk 'BEGIN{IGNORECASE=1} !/changelog[(: ]/ && NF')
entry="- $commit_msg"
if [ -n "$body_content" ]; then
entry=$(printf "%s\n%s" "$entry" "$(echo "$body_content" | sed 's/^/ /')")
fi
if [ "$changelog_type" = "feature" ]; then
FEATURES=$(printf "%s\n%s" "$FEATURES" "$entry")
elif [ "$changelog_type" = "fix" ]; then
FIXES=$(printf "%s\n%s" "$FIXES" "$entry")
else
MISC=$(printf "%s\n%s" "$MISC" "$entry")
fi
fi
done

{
echo "# Changelog for $VERSION_TITLE"
echo ""
if [[ -z "$TAG_OR_RANGE" ]]; then
echo "This page shows unreleased changes in the development version."
else
echo "Release Date: $(date +'%Y-%m-%d')"
fi
echo ""
echo "$CONTEXT_MSG"
echo ""

if [[ -n "$FEATURES" ]]; then
echo "## ✨ New Features"
echo ""
echo "$FEATURES"
echo ""
fi

if [[ -n "$FIXES" ]]; then
echo "## 🐛 Fixes"
echo ""
echo "$FIXES"
echo ""
fi

if [[ -n "$MISC" ]]; then
echo "## 🔧 Miscellaneous"
echo ""
echo "$MISC"
echo ""
fi

if [[ -z "$FEATURES" && -z "$FIXES" && -z "$MISC" ]]; then
if [[ -z "$TAG_OR_RANGE" ]]; then
echo "No changes yet."
else
echo "No changes."
fi
fi
} > "$OUTPUT_FILE"

echo "Changelog generated: $OUTPUT_FILE"
43 changes: 43 additions & 0 deletions .github/workflows/generate-changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Generate Changelog

on:
workflow_call:
inputs:
mode:
required: true
type: string
description: 'Mode of operation: "release" or "snapshot"'
tag_name:
required: false
type: string
description: "Current tag name (required for release mode)"
outputs:
changelog:
description: "Generated changelog"
value: ${{ jobs.generate.outputs.changelog }}

jobs:
generate:
runs-on: ubuntu-latest
outputs:
changelog: ${{ steps.generate_changelog.outputs.changelog }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Generate Changelog
id: generate_changelog
shell: bash
run: |
chmod +x .github/scripts/generate-changelog.sh
OUTFILE=changelog_output.md
if [[ "${{ inputs.mode }}" == "release" ]]; then
.github/scripts/generate-changelog.sh "$OUTFILE" "${{ inputs.tag_name }}"
else
.github/scripts/generate-changelog.sh "$OUTFILE"
fi
echo "changelog<<CHANGELOG_EOF" >> $GITHUB_OUTPUT
cat "$OUTFILE" >> $GITHUB_OUTPUT
echo "CHANGELOG_EOF" >> $GITHUB_OUTPUT
111 changes: 0 additions & 111 deletions .github/workflows/publish-nuget.yml

This file was deleted.

Loading