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