@@ -27,11 +27,70 @@ jobs:
2727 pull-requests : write
2828 actions : read
2929
30+ dry_run_check :
31+ name : Check if Release is Needed (Dry Run)
32+ runs-on : ubuntu-latest
33+ needs : test
34+ if : |
35+ github.event_name == 'push' &&
36+ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') &&
37+ !contains(github.event.head_commit.message, '[skip ci]') &&
38+ !contains(github.event.head_commit.message, 'chore: sync beta with main') &&
39+ !github.event.inputs.skip_approval
40+ outputs :
41+ needs_release : ${{ steps.check_release.outputs.needs_release }}
42+ next_version : ${{ steps.check_release.outputs.next_version }}
43+ release_notes : ${{ steps.check_release.outputs.release_notes }}
44+ steps :
45+ - name : Checkout code
46+ uses : actions/checkout@v4
47+ with :
48+ fetch-depth : 0
49+ token : ${{ secrets.GITHUB_TOKEN }}
50+
51+ - name : Setup Node.js
52+ uses : actions/setup-node@v4
53+ with :
54+ node-version : " 20"
55+ cache : " npm"
56+
57+ - name : Install semantic-release dependencies
58+ run : npm ci
59+
60+ - name : Check if release is needed
61+ id : check_release
62+ run : |
63+ echo "正在检查是否需要发布新版本..."
64+
65+ # 运行 semantic-release dry-run 检查是否有新版本
66+ SEMANTIC_OUTPUT=$(npx semantic-release --dry-run --no-ci 2>&1)
67+ echo "$SEMANTIC_OUTPUT"
68+
69+ # 检查是否会创建新版本
70+ if echo "$SEMANTIC_OUTPUT" | grep -q "The next release version is"; then
71+ NEXT_VERSION=$(echo "$SEMANTIC_OUTPUT" | grep -oP 'The next release version is \K[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?')
72+ echo "✅ 检测到需要发布新版本: $NEXT_VERSION"
73+ echo "needs_release=true" >> $GITHUB_OUTPUT
74+ echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT
75+
76+ # 提取发布说明
77+ RELEASE_NOTES=$(echo "$SEMANTIC_OUTPUT" | sed -n '/Release note/,/^$/p' | head -20)
78+ echo "release_notes<<EOF" >> $GITHUB_OUTPUT
79+ echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
80+ echo "EOF" >> $GITHUB_OUTPUT
81+ else
82+ echo "ℹ️ 无需发布新版本 - 没有检测到符合版本发布条件的提交"
83+ echo "needs_release=false" >> $GITHUB_OUTPUT
84+ fi
85+ env :
86+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
87+
3088 approval :
3189 name : Manual Approval Required
3290 runs-on : ubuntu-latest
33- needs : test
91+ needs : [ test, dry_run_check]
3492 if : |
93+ needs.dry_run_check.outputs.needs_release == 'true' &&
3594 github.event_name == 'push' &&
3695 (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') &&
3796 !contains(github.event.head_commit.message, '[skip ci]') &&
@@ -41,17 +100,23 @@ jobs:
41100 steps :
42101 - name : Manual approval checkpoint
43102 run : |
44- echo "等待手动确认部署..."
45- echo "分支: ${{ github.ref }}"
46- echo "提交: ${{ github.event.head_commit.message }}"
47- echo "提交者: ${{ github.event.head_commit.author.name }}"
103+ echo "🚀 准备发布新版本,等待手动确认..."
104+ echo "📋 发布信息:"
105+ echo " • 分支: ${{ github.ref }}"
106+ echo " • 版本: ${{ needs.dry_run_check.outputs.next_version }}"
107+ echo " • 提交: ${{ github.event.head_commit.message }}"
108+ echo " • 提交者: ${{ github.event.head_commit.author.name }}"
109+ echo ""
110+ echo "📝 发布说明:"
111+ echo "${{ needs.dry_run_check.outputs.release_notes }}"
48112
49113 release :
50114 name : Release
51115 runs-on : ubuntu-latest
52- needs : [test, approval]
116+ needs : [test, dry_run_check, approval]
53117 if : |
54- (github.event_name == 'push' &&
118+ (needs.dry_run_check.outputs.needs_release == 'true' &&
119+ github.event_name == 'push' &&
55120 (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') &&
56121 !contains(github.event.head_commit.message, '[skip ci]') &&
57122 !contains(github.event.head_commit.message, 'chore: sync beta with main')) ||
@@ -128,26 +193,20 @@ jobs:
128193 restore-keys : |
129194 ${{ runner.os }}-gradle-
130195
131- - name : Run semantic-release (dry-run to get version)
132- id : semantic_release_dry
196+ - name : Prepare version for build
197+ id : prepare_version
133198 run : |
134- # Run semantic-release in dry-run mode to get the next version
135- NEXT_VERSION=$(npx semantic-release --dry-run --no-ci | grep -oP 'The next release version is \K[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?' || echo "")
136- if [ -n "$NEXT_VERSION" ]; then
137- echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT
138- echo "has_release=true" >> $GITHUB_OUTPUT
139- # Update pubspec.yaml with the new version
140- sed -i "s/^version: .*/version: $NEXT_VERSION/" pubspec.yaml
141- echo "Updated pubspec.yaml version to: $NEXT_VERSION"
142- else
143- echo "has_release=false" >> $GITHUB_OUTPUT
144- echo "No release will be created"
145- fi
146- env :
147- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
199+ # Use the version determined in dry_run_check
200+ NEXT_VERSION="${{ needs.dry_run_check.outputs.next_version }}"
201+ echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT
202+ echo "has_release=true" >> $GITHUB_OUTPUT
203+
204+ # Update pubspec.yaml with the new version
205+ sed -i "s/^version: .*/version: $NEXT_VERSION/" pubspec.yaml
206+ echo "✅ Updated pubspec.yaml version to: $NEXT_VERSION"
148207
149208 - name : Setup signing
150- if : steps.semantic_release_dry .outputs.has_release == 'true'
209+ if : steps.prepare_version .outputs.has_release == 'true'
151210 run : |
152211 echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/release-key.jks
153212 echo "storeFile=release-key.jks" > key.properties
@@ -156,19 +215,19 @@ jobs:
156215 echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> key.properties
157216
158217 - name : Build signed APK
159- if : steps.semantic_release_dry .outputs.has_release == 'true'
218+ if : steps.prepare_version .outputs.has_release == 'true'
160219 run : flutter build apk --release
161220
162221 - name : Build App Bundle
163- if : steps.semantic_release_dry .outputs.has_release == 'true'
222+ if : steps.prepare_version .outputs.has_release == 'true'
164223 continue-on-error : true
165224 run : flutter build appbundle --release
166225
167226 - name : Prepare release assets
168- if : steps.semantic_release_dry .outputs.has_release == 'true'
227+ if : steps.prepare_version .outputs.has_release == 'true'
169228 run : |
170229 mkdir -p release-files
171- VERSION=${{ steps.semantic_release_dry .outputs.next_version }}
230+ VERSION=${{ steps.prepare_version .outputs.next_version }}
172231
173232 # Copy APK if exists
174233 if [ -f "build/app/outputs/flutter-apk/app-release.apk" ]; then
@@ -181,15 +240,15 @@ jobs:
181240 fi
182241
183242 - name : Clean up signing files
184- if : steps.semantic_release_dry .outputs.has_release == 'true' && env.KEYSTORE_BASE64 != ''
243+ if : steps.prepare_version .outputs.has_release == 'true' && env.KEYSTORE_BASE64 != ''
185244 run : |
186245 rm -f android/app/release-key.jks
187246 rm -f android/key.properties
188247 env :
189248 KEYSTORE_BASE64 : ${{ secrets.KEYSTORE_BASE64 }}
190249
191250 - name : Run semantic-release
192- if : steps.semantic_release_dry .outputs.has_release == 'true'
251+ if : steps.prepare_version .outputs.has_release == 'true'
193252 run : npx semantic-release
194253 env :
195254 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments