1+ name : Update Stable Branch
2+
3+ on :
4+ push :
5+ branches :
6+ - main
7+
8+ permissions :
9+ contents : write
10+
11+ jobs :
12+ prepare-release :
13+ if : contains(github.event.head_commit.message, '#release')
14+ runs-on : ubuntu-latest
15+
16+ steps :
17+ - uses : actions/checkout@v4
18+ with :
19+ fetch-depth : 0
20+
21+ - name : Configure Git
22+ run : |
23+ git config --global user.name 'github-actions[bot]'
24+ git config --global user.email 'github-actions[bot]@users.noreply.github.com'
25+
26+ - name : Setup Node.js
27+ uses : actions/setup-node@v4
28+ with :
29+ node-version : ' 20'
30+
31+ - name : Install pnpm
32+ uses : pnpm/action-setup@v2
33+ with :
34+ version : latest
35+ run_install : false
36+
37+ - name : Get pnpm store directory
38+ id : pnpm-cache
39+ shell : bash
40+ run : |
41+ echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
42+
43+ - name : Setup pnpm cache
44+ uses : actions/cache@v4
45+ with :
46+ path : ${{ steps.pnpm-cache.outputs.STORE_PATH }}
47+ key : ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
48+ restore-keys : |
49+ ${{ runner.os }}-pnpm-store-
50+
51+ - name : Get Current Version
52+ id : current_version
53+ run : |
54+ CURRENT_VERSION=$(node -p "require('./package.json').version")
55+ echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
56+
57+ - name : Install semver
58+ run : pnpm add -g semver
59+
60+ - name : Determine Version Bump
61+ id : version_bump
62+ run : |
63+ COMMIT_MSG="${{ github.event.head_commit.message }}"
64+ if [[ $COMMIT_MSG =~ "#release:major" ]]; then
65+ echo "bump=major" >> $GITHUB_OUTPUT
66+ elif [[ $COMMIT_MSG =~ "#release:minor" ]]; then
67+ echo "bump=minor" >> $GITHUB_OUTPUT
68+ else
69+ echo "bump=patch" >> $GITHUB_OUTPUT
70+ fi
71+
72+ - name : Bump Version
73+ id : bump_version
74+ run : |
75+ NEW_VERSION=$(semver -i ${{ steps.version_bump.outputs.bump }} ${{ steps.current_version.outputs.version }})
76+ echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
77+
78+ - name : Update Package.json
79+ run : |
80+ NEW_VERSION=${{ steps.bump_version.outputs.new_version }}
81+ pnpm version $NEW_VERSION --no-git-tag-version --allow-same-version
82+
83+ - name : Generate Changelog
84+ id : changelog
85+ run : |
86+ # Get the latest tag
87+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
88+
89+ # Start changelog file
90+ echo "# Release v${{ steps.bump_version.outputs.new_version }}" > changelog.md
91+ echo "" >> changelog.md
92+
93+ if [ -z "$LATEST_TAG" ]; then
94+ echo "### 🎉 First Release" >> changelog.md
95+ echo "" >> changelog.md
96+ COMPARE_BASE="$(git rev-list --max-parents=0 HEAD)"
97+ else
98+ echo "### 🔄 Changes since $LATEST_TAG" >> changelog.md
99+ echo "" >> changelog.md
100+ COMPARE_BASE="$LATEST_TAG"
101+ fi
102+
103+ # Function to extract conventional commit type
104+ get_commit_type() {
105+ if [[ $1 =~ ^feat:|^feature: ]]; then echo "✨ Features";
106+ elif [[ $1 =~ ^fix: ]]; then echo "🐛 Bug Fixes";
107+ elif [[ $1 =~ ^docs: ]]; then echo "📚 Documentation";
108+ elif [[ $1 =~ ^style: ]]; then echo "💎 Styles";
109+ elif [[ $1 =~ ^refactor: ]]; then echo "♻️ Code Refactoring";
110+ elif [[ $1 =~ ^perf: ]]; then echo "⚡️ Performance Improvements";
111+ elif [[ $1 =~ ^test: ]]; then echo "✅ Tests";
112+ elif [[ $1 =~ ^build: ]]; then echo "🛠️ Build System";
113+ elif [[ $1 =~ ^ci: ]]; then echo "⚙️ CI";
114+ elif [[ $1 =~ ^chore: ]]; then echo "🔧 Chores";
115+ else echo "🔍 Other Changes";
116+ fi
117+ }
118+
119+ # Generate categorized changelog
120+ declare -A CATEGORIES
121+ declare -A COMMITS_BY_CATEGORY
122+
123+ # Get commits since last tag or all commits if no tag exists
124+ while IFS= read -r commit_line; do
125+ HASH=$(echo "$commit_line" | cut -d'|' -f1)
126+ MSG=$(echo "$commit_line" | cut -d'|' -f2)
127+ PR_NUM=$(echo "$commit_line" | cut -d'|' -f3)
128+
129+ CATEGORY=$(get_commit_type "$MSG")
130+ CATEGORIES["$CATEGORY"]=1
131+
132+ # Format commit message with PR link if available
133+ if [ -n "$PR_NUM" ]; then
134+ COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
135+ else
136+ COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: }"$'\n'
137+ fi
138+ done < <(git log "${COMPARE_BASE}..HEAD" --pretty=format:"%H|%s|%(trailers:key=PR-Number,valueonly)" --reverse)
139+
140+ # Write categorized commits to changelog
141+ for category in "✨ Features" "🐛 Bug Fixes" "📚 Documentation" "💎 Styles" "♻️ Code Refactoring" "⚡️ Performance Improvements" "✅ Tests" "🛠️ Build System" "⚙️ CI" "🔧 Chores" "🔍 Other Changes"; do
142+ if [ -n "${COMMITS_BY_CATEGORY[$category]}" ]; then
143+ echo "#### $category" >> changelog.md
144+ echo "" >> changelog.md
145+ echo "${COMMITS_BY_CATEGORY[$category]}" >> changelog.md
146+ echo "" >> changelog.md
147+ fi
148+ done
149+
150+ # Add compare link if not first release
151+ if [ -n "$LATEST_TAG" ]; then
152+ 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
153+ fi
154+
155+ # Save changelog content for the release
156+ CHANGELOG_CONTENT=$(cat changelog.md)
157+ echo "content<<EOF" >> $GITHUB_OUTPUT
158+ echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
159+ echo "EOF" >> $GITHUB_OUTPUT
160+
161+ - name : Get the latest commit hash and version tag
162+ run : |
163+ echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV
164+ echo "CURRENT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
165+
166+ - name : Commit and Tag Release
167+ run : |
168+ git pull
169+ echo "{ \"commit\": \"$COMMIT_HASH\" , \"version\": \"$CURRENT_VERSION\" }" > app/commit.json
170+ git add package.json pnpm-lock.yaml changelog.md app/commit.json
171+ git commit -m "chore: release version ${{ steps.bump_version.outputs.new_version }}"
172+ git tag "v${{ steps.bump_version.outputs.new_version }}"
173+ git push
174+ git push --tags
175+
176+ - name : Update Stable Branch
177+ run : |
178+ if ! git checkout stable 2>/dev/null; then
179+ echo "Creating new stable branch..."
180+ git checkout -b stable
181+ fi
182+ git merge main --no-ff -m "chore: release version ${{ steps.bump_version.outputs.new_version }}"
183+ git push --set-upstream origin stable --force
184+
185+ - name : Create GitHub Release
186+ env :
187+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
188+ run : |
189+ VERSION="v${{ steps.bump_version.outputs.new_version }}"
190+ gh release create "$VERSION" \
191+ --title "Release $VERSION" \
192+ --notes "${{ steps.changelog.outputs.content }}" \
193+ --target stable
0 commit comments