-
Notifications
You must be signed in to change notification settings - Fork 2
157 lines (142 loc) · 6.99 KB
/
Copy pathandroid-release.yml
File metadata and controls
157 lines (142 loc) · 6.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
name: Android Release
# 打 Tag(如 v1.0.0)时触发:构建三个签名 Release APK
# - universal : arm64-v8a + x86_64,含 arm + x86 两套容器镜像(通用,体积最大)
# - armsolo : 仅 arm64-v8a,仅含 arm 镜像(真机首选,体积约为 universal 的一半)
# - x86solo : 仅 x86_64,仅含 x86 镜像(x86 模拟器/Chromebook,体积约为 universal 的一半)
# 创建 GitHub Release 并把三个 APK 作为资产发布。
on:
push:
tags:
- 'v*'
# 允许在 Actions 页面手动触发,便于验证构建链路。
workflow_dispatch:
jobs:
build:
name: Build & Release
runs-on: ubuntu-latest
permissions:
contents: write # 创建 Release 与上传资产需要写权限
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# versionCode 由 build.gradle.kts 的 gitCommitCount() 取 git rev-list --count HEAD,
# 浅克隆(默认 depth=1)会得到 1,必须拉完整历史,否则 Release APK 版本号错乱。
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
with:
# 复用 Gradle 构建缓存,加速后续构建。
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
# 打印当前 Tag,Tag 驱动直接生成 versionName。
# 仅打 tag 触发时校验;workflow_dispatch(手动,无 tag)跳过。
- name: Display release tag info
if: startsWith(github.ref, 'refs/tags/v')
run: |
set -e
tag_ver="${GITHUB_REF_NAME#v}" # 1.7.0 / 1.7.0-rc1 / ...
echo "tag version (without v) = $tag_ver"
echo "✓ tag 将直接驱动应用 versionName ($tag_ver)"
# 校验 versionCode 单调递增:versionCode = git commit count,rebase/squash 改写历史
# 可能让 commit count 变小,导致新版本 versionCode < 旧版本、升级判定失效。
# 取按提交时间倒序最近的非当前 tag,算其 commit count,要求当前 HEAD 不小于上个 Release。
# 允许相等:rc 转正式版时常在同一提交上打 tag,versionCode 相等是正常的。
# 仅打 tag 触发时校验;workflow_dispatch(手动,无 tag)跳过。
- name: Verify versionCode monotonic
if: startsWith(github.ref, 'refs/tags/v')
run: |
set -e
cur_vc=$(git rev-list --count HEAD)
prev_tag=$(git tag --sort=-creatordate | grep -vE "^${GITHUB_REF_NAME}$" | head -1)
if [[ -z "$prev_tag" ]]; then
echo "无历史 tag,跳过 versionCode 单调校验(首次发版)"
echo "当前 versionCode(commit count) = $cur_vc"
exit 0
fi
prev_vc=$(git rev-list --count "$prev_tag")
echo "上个 Release($prev_tag) versionCode = $prev_vc"
echo "当前(${GITHUB_REF_NAME}) versionCode = $cur_vc"
if [[ "$cur_vc" -lt "$prev_vc" ]]; then
echo "::error::versionCode 回退: 当前 $cur_vc < 上个 Release($prev_tag) $prev_vc。通常因 rebase/squash 改写历史使 commit count 变小。请确保新版本在旧 tag 之上线性推进。"
exit 1
fi
echo "✓ versionCode 单调递增: $prev_vc -> $cur_vc"
- name: Restore release keystore
env:
# keystore 文件以 base64 存入 Secret,避免二进制文件被破坏。
# 还原到 app/aicode.jks,与 build.gradle.kts 期望的位置一致。
KEYSTORE_BASE64: ${{ secrets.AICODE_KEYSTORE_BASE64 }}
run: |
echo "$KEYSTORE_BASE64" | base64 -d > app/aicode.jks
echo "keystore restored ($(stat -c%s app/aicode.jks) bytes)"
- name: Generate keystore.properties
env:
KEYSTORE_PASSWORD: ${{ secrets.AICODE_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.AICODE_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.AICODE_KEY_PASSWORD }}
run: |
cat > app/keystore.properties <<EOF
storeFile=aicode.jks
storePassword=$KEYSTORE_PASSWORD
keyAlias=$KEY_ALIAS
keyPassword=$KEY_PASSWORD
EOF
echo "app/keystore.properties generated"
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
# 发版质量门禁:跑单元测试,失败即中止,避免发出回归包。
# 只跑 universal debug 变体:单测逻辑与 flavor 无关,跑全 flavor 6 变体是重复编译。
- name: Run unit tests
run: ./gradlew :app:testUniversalDebugUnitTest
# 一次性构建全部 flavor 的 release APK(universal/armsolo/x86solo)
# --stacktrace:构建失败时输出完整调用栈,便于在 CI 定位 OOM/内存类根因。
- name: Build all flavor Release APKs
run: ./gradlew assembleRelease --stacktrace
# 给三个 APK 重命名为「包名-架构-版本」格式,架构用真实 ABI 名便于用户识别:
# aicode-arm64-v1.0.0-rc1.apk (armsolo)
# aicode-x86_64-v1.0.0-rc1.apk (x86solo)
# aicode-universal-v1.0.0-rc1.apk (universal,含两套镜像)
- name: Rename APKs by flavor
run: |
mkdir -p dist
ver="${GITHUB_REF_NAME:-manual}" # tag 如 v1.0.0-rc1;手动触发时为 manual-N
declare -A abi=( [armsolo]=arm64 [x86solo]=x86_64 [universal]=universal )
for f in universal armsolo x86solo; do
src="app/build/outputs/apk/$f/release/app-$f-release.apk"
if [[ -f "$src" ]]; then
out="dist/aicode-${abi[$f]}-${ver}.apk"
cp "$src" "$out"
echo "packaged $out"
else
echo "::warning::missing $src"
fi
done
ls -lh dist/
- name: Determine release name
id: release
run: |
# 手动触发(无 tag)时用 run id 作为临时名,避免破坏 tag 发布。
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
else
echo "tag=manual-${GITHUB_RUN_NUMBER}" >> "$GITHUB_OUTPUT"
fi
- name: Create GitHub Release & Upload assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.release.outputs.tag }}
name: Release ${{ steps.release.outputs.tag }}
generate_release_notes: true
# 产物名约定 aicode-<abi>-<版本>.apk(见 Rename 步骤),故 glob 把 ABI 段放 aicode- 紧后、版本段用 * 兜底。
# 不要写成 aicode-*-<abi>.apk——那会把 abi 误放末段,与 aicode-<abi>-<ver> 永远匹配不上(rc3 翻车原因)。
files: |
dist/aicode-universal-*.apk
dist/aicode-arm64-*.apk
dist/aicode-x86_64-*.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}