mirror of
https://github.com/coleam00/bolt.new-any-llm
synced 2024-12-26 22:02:09 +00:00
ci: improved change-log generation script and cleaner release ci action (#896)
Some checks failed
Update Stable Branch / prepare-release (push) Has been cancelled
Some checks failed
Update Stable Branch / prepare-release (push) Has been cancelled
* build: improved-changelog * added a better change log script * improved changelog script * improved change log script
This commit is contained in:
parent
7eee0386ff
commit
4844db82fa
261
.github/scripts/generate-changelog.sh
vendored
Executable file
261
.github/scripts/generate-changelog.sh
vendored
Executable file
@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Ensure we're running in bash
|
||||
if [ -z "$BASH_VERSION" ]; then
|
||||
echo "This script requires bash. Please run with: bash $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure we're using bash 4.0 or later for associative arrays
|
||||
if ((BASH_VERSINFO[0] < 4)); then
|
||||
echo "This script requires bash version 4 or later" >&2
|
||||
echo "Current bash version: $BASH_VERSION" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set default values for required environment variables if not in GitHub Actions
|
||||
if [ -z "$GITHUB_ACTIONS" ]; then
|
||||
: "${GITHUB_SERVER_URL:=https://github.com}"
|
||||
: "${GITHUB_REPOSITORY:=stackblitz-labs/bolt.diy}"
|
||||
: "${GITHUB_OUTPUT:=/tmp/github_output}"
|
||||
touch "$GITHUB_OUTPUT"
|
||||
|
||||
# Running locally
|
||||
echo "Running locally - checking for upstream remote..."
|
||||
MAIN_REMOTE="origin"
|
||||
if git remote -v | grep -q "upstream"; then
|
||||
MAIN_REMOTE="upstream"
|
||||
fi
|
||||
MAIN_BRANCH="main" # or "master" depending on your repository
|
||||
|
||||
# Ensure we have latest tags
|
||||
git fetch ${MAIN_REMOTE} --tags
|
||||
|
||||
# Use the remote reference for git log
|
||||
GITLOG_REF="${MAIN_REMOTE}/${MAIN_BRANCH}"
|
||||
else
|
||||
# Running in GitHub Actions
|
||||
GITLOG_REF="HEAD"
|
||||
fi
|
||||
|
||||
# Get the latest tag
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
# Start changelog file
|
||||
echo "# 🚀 Release v${NEW_VERSION}" > changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "## What's Changed 🌟" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
echo "### 🎉 First Release" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "Exciting times! This marks our first release. Thanks to everyone who contributed! 🙌" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
COMPARE_BASE="$(git rev-list --max-parents=0 HEAD)"
|
||||
else
|
||||
echo "### 🔄 Changes since $LATEST_TAG" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
COMPARE_BASE="$LATEST_TAG"
|
||||
fi
|
||||
|
||||
# Function to extract conventional commit type and associated emoji
|
||||
get_commit_type() {
|
||||
local msg="$1"
|
||||
if [[ $msg =~ ^feat(\(.+\))?:|^feature(\(.+\))?: ]]; then echo "✨ Features"
|
||||
elif [[ $msg =~ ^fix(\(.+\))?: ]]; then echo "🐛 Bug Fixes"
|
||||
elif [[ $msg =~ ^docs(\(.+\))?: ]]; then echo "📚 Documentation"
|
||||
elif [[ $msg =~ ^style(\(.+\))?: ]]; then echo "💎 Styles"
|
||||
elif [[ $msg =~ ^refactor(\(.+\))?: ]]; then echo "♻️ Code Refactoring"
|
||||
elif [[ $msg =~ ^perf(\(.+\))?: ]]; then echo "⚡ Performance Improvements"
|
||||
elif [[ $msg =~ ^test(\(.+\))?: ]]; then echo "🧪 Tests"
|
||||
elif [[ $msg =~ ^build(\(.+\))?: ]]; then echo "🛠️ Build System"
|
||||
elif [[ $msg =~ ^ci(\(.+\))?: ]]; then echo "⚙️ CI"
|
||||
elif [[ $msg =~ ^chore(\(.+\))?: ]]; then echo "" # Skip chore commits
|
||||
else echo "🔍 Other Changes" # Default category with emoji
|
||||
fi
|
||||
}
|
||||
|
||||
# Initialize associative arrays
|
||||
declare -A CATEGORIES
|
||||
declare -A COMMITS_BY_CATEGORY
|
||||
declare -A ALL_AUTHORS
|
||||
declare -A NEW_CONTRIBUTORS
|
||||
|
||||
# Get all historical authors before the compare base
|
||||
while IFS= read -r author; do
|
||||
ALL_AUTHORS["$author"]=1
|
||||
done < <(git log "${COMPARE_BASE}" --pretty=format:"%ae" | sort -u)
|
||||
|
||||
# Process all commits since last tag
|
||||
while IFS= read -r commit_line; do
|
||||
if [[ ! $commit_line =~ ^[a-f0-9]+\| ]]; then
|
||||
echo "WARNING: Skipping invalid commit line format: $commit_line" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
HASH=$(echo "$commit_line" | cut -d'|' -f1)
|
||||
COMMIT_MSG=$(echo "$commit_line" | cut -d'|' -f2)
|
||||
BODY=$(echo "$commit_line" | cut -d'|' -f3)
|
||||
# Skip if hash doesn't match the expected format
|
||||
if [[ ! $HASH =~ ^[a-f0-9]{40}$ ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
HASH=$(echo "$commit_line" | cut -d'|' -f1)
|
||||
COMMIT_MSG=$(echo "$commit_line" | cut -d'|' -f2)
|
||||
BODY=$(echo "$commit_line" | cut -d'|' -f3)
|
||||
|
||||
|
||||
# Validate hash format
|
||||
if [[ ! $HASH =~ ^[a-f0-9]{40}$ ]]; then
|
||||
echo "WARNING: Invalid commit hash format: $HASH" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if it's a merge commit
|
||||
if [[ $COMMIT_MSG =~ Merge\ pull\ request\ #([0-9]+) ]]; then
|
||||
# echo "Processing as merge commit" >&2
|
||||
PR_NUM="${BASH_REMATCH[1]}"
|
||||
|
||||
# Extract the PR title from the merge commit body
|
||||
PR_TITLE=$(echo "$BODY" | grep -v "^Merge pull request" | head -n 1)
|
||||
|
||||
# Only process if it follows conventional commit format
|
||||
CATEGORY=$(get_commit_type "$PR_TITLE")
|
||||
|
||||
if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
|
||||
# Get PR author's GitHub username
|
||||
GITHUB_USERNAME=$(gh pr view "$PR_NUM" --json author --jq '.author.login')
|
||||
|
||||
if [ -n "$GITHUB_USERNAME" ]; then
|
||||
# Check if this is a first-time contributor
|
||||
AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
|
||||
if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
|
||||
NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
|
||||
ALL_AUTHORS["$AUTHOR_EMAIL"]=1
|
||||
fi
|
||||
|
||||
CATEGORIES["$CATEGORY"]=1
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* ${PR_TITLE#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM)) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
|
||||
else
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* ${PR_TITLE#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
|
||||
fi
|
||||
fi
|
||||
# Check if it's a squash merge by looking for (#NUMBER) pattern
|
||||
elif [[ $COMMIT_MSG =~ \(#([0-9]+)\) ]]; then
|
||||
# echo "Processing as squash commit" >&2
|
||||
PR_NUM="${BASH_REMATCH[1]}"
|
||||
|
||||
# Only process if it follows conventional commit format
|
||||
CATEGORY=$(get_commit_type "$COMMIT_MSG")
|
||||
|
||||
if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
|
||||
# Get PR author's GitHub username
|
||||
GITHUB_USERNAME=$(gh pr view "$PR_NUM" --json author --jq '.author.login')
|
||||
|
||||
if [ -n "$GITHUB_USERNAME" ]; then
|
||||
# Check if this is a first-time contributor
|
||||
AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
|
||||
if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
|
||||
NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
|
||||
ALL_AUTHORS["$AUTHOR_EMAIL"]=1
|
||||
fi
|
||||
|
||||
CATEGORIES["$CATEGORY"]=1
|
||||
COMMIT_TITLE=${COMMIT_MSG%% (#*} # Remove the PR number suffix
|
||||
COMMIT_TITLE=${COMMIT_TITLE#*: } # Remove the type prefix
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM)) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
|
||||
else
|
||||
COMMIT_TITLE=${COMMIT_MSG%% (#*} # Remove the PR number suffix
|
||||
COMMIT_TITLE=${COMMIT_TITLE#*: } # Remove the type prefix
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
# echo "Processing as regular commit" >&2
|
||||
# Process conventional commits without PR numbers
|
||||
CATEGORY=$(get_commit_type "$COMMIT_MSG")
|
||||
|
||||
if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
|
||||
# Get commit author info
|
||||
AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
|
||||
|
||||
# Try to get GitHub username using gh api
|
||||
if [ -n "$GITHUB_ACTIONS" ] || command -v gh >/dev/null 2>&1; then
|
||||
GITHUB_USERNAME=$(gh api "/repos/${GITHUB_REPOSITORY}/commits/${HASH}" --jq '.author.login' 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -n "$GITHUB_USERNAME" ]; then
|
||||
# If we got GitHub username, use it
|
||||
if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
|
||||
NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
|
||||
ALL_AUTHORS["$AUTHOR_EMAIL"]=1
|
||||
fi
|
||||
|
||||
CATEGORIES["$CATEGORY"]=1
|
||||
COMMIT_TITLE=${COMMIT_MSG#*: } # Remove the type prefix
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE (${HASH:0:7}) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
|
||||
else
|
||||
# Fallback to git author name if no GitHub username found
|
||||
AUTHOR_NAME=$(git show -s --format='%an' "$HASH")
|
||||
|
||||
if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
|
||||
NEW_CONTRIBUTORS["$AUTHOR_NAME"]=1
|
||||
ALL_AUTHORS["$AUTHOR_EMAIL"]=1
|
||||
fi
|
||||
|
||||
CATEGORIES["$CATEGORY"]=1
|
||||
COMMIT_TITLE=${COMMIT_MSG#*: } # Remove the type prefix
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE (${HASH:0:7}) by $AUTHOR_NAME"$'\n'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
done < <(git log "${COMPARE_BASE}..${GITLOG_REF}" --pretty=format:"%H|%s|%b" --reverse --first-parent)
|
||||
|
||||
# Write categorized commits to changelog with their emojis
|
||||
for category in "✨ Features" "🐛 Bug Fixes" "📚 Documentation" "💎 Styles" "♻️ Code Refactoring" "⚡ Performance Improvements" "🧪 Tests" "🛠️ Build System" "⚙️ CI" "🔍 Other Changes"; do
|
||||
if [ -n "${COMMITS_BY_CATEGORY[$category]}" ]; then
|
||||
echo "### $category" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "${COMMITS_BY_CATEGORY[$category]}" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
fi
|
||||
done
|
||||
|
||||
# Add first-time contributors section if there are any
|
||||
if [ ${#NEW_CONTRIBUTORS[@]} -gt 0 ]; then
|
||||
echo "## ✨ First-time Contributors" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "A huge thank you to our amazing new contributors! Your first contribution marks the start of an exciting journey! 🌟" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
# Use readarray to sort the keys
|
||||
readarray -t sorted_contributors < <(printf '%s\n' "${!NEW_CONTRIBUTORS[@]}" | sort)
|
||||
for github_username in "${sorted_contributors[@]}"; do
|
||||
echo "* 🌟 [@$github_username](https://github.com/$github_username)" >> changelog.md
|
||||
done
|
||||
echo "" >> changelog.md
|
||||
fi
|
||||
|
||||
# Add compare link if not first release
|
||||
if [ -n "$LATEST_TAG" ]; then
|
||||
echo "## 📈 Stats" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "**Full Changelog**: [\`$LATEST_TAG..v${NEW_VERSION}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/$LATEST_TAG...v${NEW_VERSION})" >> changelog.md
|
||||
fi
|
||||
|
||||
# Output the changelog content
|
||||
CHANGELOG_CONTENT=$(cat changelog.md)
|
||||
{
|
||||
echo "content<<EOF"
|
||||
echo "$CHANGELOG_CONTENT"
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Also print to stdout for local testing
|
||||
echo "Generated changelog:"
|
||||
echo "==================="
|
||||
cat changelog.md
|
||||
echo "==================="
|
82
.github/workflows/update-stable.yml
vendored
82
.github/workflows/update-stable.yml
vendored
@ -80,83 +80,15 @@ jobs:
|
||||
NEW_VERSION=${{ steps.bump_version.outputs.new_version }}
|
||||
pnpm version $NEW_VERSION --no-git-tag-version --allow-same-version
|
||||
|
||||
|
||||
- name: Prepare changelog script
|
||||
run: chmod +x .github/scripts/generate-changelog.sh
|
||||
|
||||
- name: Generate Changelog
|
||||
id: changelog
|
||||
run: |
|
||||
# Get the latest tag
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
# Start changelog file
|
||||
echo "# Release v${{ steps.bump_version.outputs.new_version }}" > changelog.md
|
||||
echo "" >> changelog.md
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
echo "### 🎉 First Release" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
COMPARE_BASE="$(git rev-list --max-parents=0 HEAD)"
|
||||
else
|
||||
echo "### 🔄 Changes since $LATEST_TAG" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
COMPARE_BASE="$LATEST_TAG"
|
||||
fi
|
||||
|
||||
# Function to extract conventional commit type
|
||||
get_commit_type() {
|
||||
if [[ $1 =~ ^feat:|^feature: ]]; then echo "✨ Features";
|
||||
elif [[ $1 =~ ^fix: ]]; then echo "🐛 Bug Fixes";
|
||||
elif [[ $1 =~ ^docs: ]]; then echo "📚 Documentation";
|
||||
elif [[ $1 =~ ^style: ]]; then echo "💎 Styles";
|
||||
elif [[ $1 =~ ^refactor: ]]; then echo "♻️ Code Refactoring";
|
||||
elif [[ $1 =~ ^perf: ]]; then echo "⚡️ Performance Improvements";
|
||||
elif [[ $1 =~ ^test: ]]; then echo "✅ Tests";
|
||||
elif [[ $1 =~ ^build: ]]; then echo "🛠️ Build System";
|
||||
elif [[ $1 =~ ^ci: ]]; then echo "⚙️ CI";
|
||||
elif [[ $1 =~ ^chore: ]]; then echo "🔧 Chores";
|
||||
else echo "🔍 Other Changes";
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate categorized changelog
|
||||
declare -A CATEGORIES
|
||||
declare -A COMMITS_BY_CATEGORY
|
||||
|
||||
# Get commits since last tag or all commits if no tag exists
|
||||
while IFS= read -r commit_line; do
|
||||
HASH=$(echo "$commit_line" | cut -d'|' -f1)
|
||||
MSG=$(echo "$commit_line" | cut -d'|' -f2)
|
||||
PR_NUM=$(echo "$commit_line" | cut -d'|' -f3)
|
||||
|
||||
CATEGORY=$(get_commit_type "$MSG")
|
||||
CATEGORIES["$CATEGORY"]=1
|
||||
|
||||
# Format commit message with PR link if available
|
||||
if [ -n "$PR_NUM" ]; then
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
|
||||
else
|
||||
COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: }"$'\n'
|
||||
fi
|
||||
done < <(git log "${COMPARE_BASE}..HEAD" --pretty=format:"%H|%s|%(trailers:key=PR-Number,valueonly)" --reverse)
|
||||
|
||||
# Write categorized commits to changelog
|
||||
for category in "✨ Features" "🐛 Bug Fixes" "📚 Documentation" "💎 Styles" "♻️ Code Refactoring" "⚡️ Performance Improvements" "✅ Tests" "🛠️ Build System" "⚙️ CI" "🔧 Chores" "🔍 Other Changes"; do
|
||||
if [ -n "${COMMITS_BY_CATEGORY[$category]}" ]; then
|
||||
echo "#### $category" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
echo "${COMMITS_BY_CATEGORY[$category]}" >> changelog.md
|
||||
echo "" >> changelog.md
|
||||
fi
|
||||
done
|
||||
|
||||
# Add compare link if not first release
|
||||
if [ -n "$LATEST_TAG" ]; then
|
||||
echo "**Full Changelog**: [\`$LATEST_TAG..v${{ steps.bump_version.outputs.new_version }}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/$LATEST_TAG...v${{ steps.bump_version.outputs.new_version }})" >> changelog.md
|
||||
fi
|
||||
|
||||
# Save changelog content for the release
|
||||
CHANGELOG_CONTENT=$(cat changelog.md)
|
||||
echo "content<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.bump_version.outputs.new_version }}
|
||||
run: .github/scripts/generate-changelog.sh
|
||||
|
||||
- name: Get the latest commit hash and version tag
|
||||
run: |
|
||||
|
Loading…
Reference in New Issue
Block a user