chore: update workflow #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' # Trigger when pushing tags starting with 'v' | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Fetch all history to generate changelog | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.8.1 | |
| - name: Get version from tag | |
| id: tag_version | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: Get previous tag | |
| id: previous_tag | |
| run: | | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [ -z "$PREVIOUS_TAG" ]; then | |
| PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD) | |
| fi | |
| echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT | |
| echo "Previous tag: $PREVIOUS_TAG" | |
| - name: Generate changelog | |
| id: changelog | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PREVIOUS_TAG="${{ steps.previous_tag.outputs.previous_tag }}" | |
| CURRENT_TAG="${{ github.ref }}" | |
| # Define emoji mapping for commit types | |
| declare -A EMOJI_MAP=( | |
| ["feat"]="β¨" | |
| ["fix"]="π" | |
| ["docs"]="π" | |
| ["style"]="π" | |
| ["refactor"]="β»οΈ" | |
| ["perf"]="β‘" | |
| ["test"]="β " | |
| ["build"]="π¨" | |
| ["ci"]="π·" | |
| ["chore"]="π§" | |
| ["revert"]="βͺ" | |
| ["security"]="π" | |
| ["deps"]="π¦" | |
| ["config"]="βοΈ" | |
| ["types"]="π·οΈ" | |
| ["i18n"]="π" | |
| ["ui"]="π¨" | |
| ["ux"]="π‘" | |
| ["api"]="π" | |
| ["db"]="ποΈ" | |
| ["docker"]="π³" | |
| ["release"]="π" | |
| ) | |
| # Get all commits | |
| if [ "$PREVIOUS_TAG" = "" ] || [ "$PREVIOUS_TAG" = "$(git rev-list --max-parents=0 HEAD)" ]; then | |
| COMMITS=$(git log --pretty=format:"%H|%s|%an|%ae" --no-merges 2>/dev/null || echo "") | |
| else | |
| COMMITS=$(git log ${PREVIOUS_TAG}..HEAD --pretty=format:"%H|%s|%an|%ae" --no-merges 2>/dev/null || echo "") | |
| fi | |
| # Categorize commits (only features and fixes) | |
| FEATURES="" | |
| FIXES="" | |
| # Store all contributors | |
| declare -A CONTRIBUTORS | |
| # Store GitHub username mapping for contributors | |
| declare -A CONTRIBUTOR_GITHUB_USERS | |
| # First pass: collect all unique contributors | |
| if [ -n "$COMMITS" ]; then | |
| while IFS='|' read -r HASH MESSAGE AUTHOR EMAIL; do | |
| [ -z "$HASH" ] && continue | |
| CONTRIBUTORS["$AUTHOR|$EMAIL"]=1 | |
| done <<< "$COMMITS" | |
| fi | |
| # Batch lookup GitHub usernames for all contributors | |
| echo "Looking up GitHub usernames for contributors..." | |
| for CONTRIBUTOR in "${!CONTRIBUTORS[@]}"; do | |
| IFS='|' read -r AUTHOR EMAIL <<< "$CONTRIBUTOR" | |
| GITHUB_USER="" | |
| if [ -n "$GITHUB_TOKEN" ]; then | |
| # Try by email first | |
| API_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ | |
| "https://api.github.com/search/users?q=${EMAIL}+in:email" 2>/dev/null || echo "") | |
| if [ -n "$API_RESPONSE" ]; then | |
| GITHUB_USER=$(echo "$API_RESPONSE" | grep -o '"login":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "") | |
| fi | |
| # Try by name if email search failed | |
| if [ -z "$GITHUB_USER" ]; then | |
| API_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ | |
| "https://api.github.com/search/users?q=${AUTHOR}+in:name" 2>/dev/null || echo "") | |
| GITHUB_USER=$(echo "$API_RESPONSE" | grep -o '"login":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "") | |
| fi | |
| # Small delay to avoid rate limiting | |
| sleep 0.1 | |
| fi | |
| CONTRIBUTOR_GITHUB_USERS["$AUTHOR|$EMAIL"]="$GITHUB_USER" | |
| done | |
| # Second pass: process commits and format with contributors | |
| if [ -n "$COMMITS" ]; then | |
| while IFS='|' read -r HASH MESSAGE AUTHOR EMAIL; do | |
| # Skip empty lines | |
| [ -z "$HASH" ] && continue | |
| # Extract commit type (conventional commits format) | |
| TYPE=$(echo "$MESSAGE" | sed -E 's/^([^:\(]+)(\(.+\))?:.*/\1/' | tr '[:upper:]' '[:lower:]' | xargs) | |
| # Default to 'other' if no type prefix | |
| if [ -z "$TYPE" ] || [ "$TYPE" = "$MESSAGE" ]; then | |
| TYPE="other" | |
| fi | |
| # Get emoji | |
| EMOJI="${EMOJI_MAP[$TYPE]:-π}" | |
| # Clean commit message (remove type prefix) | |
| if echo "$MESSAGE" | grep -qE '^[^:]+(\(.+\))?:'; then | |
| CLEAN_MSG=$(echo "$MESSAGE" | sed -E 's/^[^:]+(\(.+\))?:\s*//') | |
| else | |
| CLEAN_MSG="$MESSAGE" | |
| fi | |
| # Escape special characters | |
| CLEAN_MSG=$(echo "$CLEAN_MSG" | sed 's/"/\\"/g' | sed 's/`/\\`/g') | |
| # Get GitHub username for this contributor | |
| GITHUB_USER="${CONTRIBUTOR_GITHUB_USERS["$AUTHOR|$EMAIL"]}" | |
| # Format contributor mention (use @ for GitHub username) | |
| if [ -n "$GITHUB_USER" ]; then | |
| CONTRIBUTOR_MENTION=" @${GITHUB_USER}" | |
| else | |
| CONTRIBUTOR_MENTION="" | |
| fi | |
| # Format commit line with contributor | |
| COMMIT_LINE="$EMOJI $CLEAN_MSG${CONTRIBUTOR_MENTION}" | |
| # Categorize (only features and fixes) | |
| case "$TYPE" in | |
| feat|feature) | |
| FEATURES="${FEATURES}- ${COMMIT_LINE}\n" | |
| ;; | |
| fix|bugfix) | |
| FIXES="${FIXES}- ${COMMIT_LINE}\n" | |
| ;; | |
| *) | |
| # Skip other types | |
| ;; | |
| esac | |
| done <<< "$COMMITS" | |
| fi | |
| # Build changelog | |
| CHANGELOG="# Release Notes - v${{ steps.tag_version.outputs.version }}\n\n" | |
| # Check if there are any changes | |
| HAS_CHANGES=false | |
| if [ -n "$FEATURES" ]; then | |
| CHANGELOG="${CHANGELOG}## β¨ New Features\n${FEATURES}\n" | |
| HAS_CHANGES=true | |
| fi | |
| if [ -n "$FIXES" ]; then | |
| CHANGELOG="${CHANGELOG}## π Bug Fixes\n${FIXES}\n" | |
| HAS_CHANGES=true | |
| fi | |
| # Add message if no changes | |
| if [ "$HAS_CHANGES" = false ]; then | |
| CHANGELOG="${CHANGELOG}No code changes in this release.\n\n" | |
| fi | |
| # Output to file (use printf to properly handle newlines) | |
| printf "%b" "$CHANGELOG" > CHANGELOG.md | |
| # Save to output (for subsequent steps) | |
| { | |
| echo 'changelog<<EOF' | |
| printf "%b" "$CHANGELOG" | |
| echo EOF | |
| } >> $GITHUB_OUTPUT | |
| echo "Changelog generated successfully" | |
| cat CHANGELOG.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ github.ref_name }} | |
| name: Release v${{ steps.tag_version.outputs.version }} | |
| body_path: CHANGELOG.md | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: false | |