@@ -4,15 +4,20 @@ name: Release
44# 同时把 APK 作为 GitHub Release 附件挂出(IPA 不公开)。
55#
66# 触发:
7- # - push tag 形如 v1.0.8+1
7+ # - push tag 形如 v1.0.11(推荐,新格式)或 v1.0. 8+1(兼容旧格式)
88# - 或在 Actions 页面手动 dispatch 选 tag
9+ #
10+ # 版本号约定:
11+ # - tag 用纯 SemVer(v1.0.11),不带 +N
12+ # - versionCode 由 CI 自动用 git rev-list --count <tag> 生成,全局单调递增
13+ # - 详见 CLAUDE.md "Android versionCode 单调递增" 章节
914on :
1015 push :
1116 tags : ['v*']
1217 workflow_dispatch :
1318 inputs :
1419 tag :
15- description : ' Tag to release (e.g. v1.0.8+1 )'
20+ description : ' Tag to release (e.g. v1.0.11 )'
1621 required : true
1722
1823env :
@@ -61,23 +66,56 @@ jobs:
6166 env :
6267 TAG_REF : ${{ github.event.inputs.tag || github.ref_name }}
6368 run : |
64- NAME="${TAG_REF#v}"
65- NAME="${NAME%+*}"
66- NUMBER="${TAG_REF##*+}"
67- if [[ "$NAME" == "$TAG_REF" || "$NUMBER" == "$TAG_REF" || -z "$NAME" || -z "$NUMBER" ]]; then
68- echo "ERROR: tag '$TAG_REF' is not in vX.Y.Z+N format" >&2
69+ # 兼容新格式 vX.Y.Z 和旧格式 vX.Y.Z+N
70+ if [[ "$TAG_REF" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
71+ NAME="${BASH_REMATCH[1]}"
72+ # versionCode = 该 tag 指向 commit 的 git rev-list count
73+ NUMBER="$(git rev-list --count "$TAG_REF")"
74+ elif [[ "$TAG_REF" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)\+([0-9]+)$ ]]; then
75+ NAME="${BASH_REMATCH[1]}"
76+ NUMBER="${BASH_REMATCH[2]}"
77+ else
78+ echo "ERROR: tag '$TAG_REF' is not in vX.Y.Z or vX.Y.Z+N format" >&2
79+ exit 1
80+ fi
81+ if [[ -z "$NUMBER" || "$NUMBER" -le 0 ]]; then
82+ echo "ERROR: invalid build number ($NUMBER) for tag $TAG_REF" >&2
6983 exit 1
7084 fi
85+
86+ # 校验 versionCode 严格大于所有历史 tag 的 versionCode
87+ # 防止人为意外打了倒退的 +N 旧格式 tag
88+ git fetch --tags --force
89+ MAX_CODE=0
90+ for t in $(git tag -l 'v*'); do
91+ if [[ "$t" == "$TAG_REF" ]]; then continue; fi
92+ if [[ "$t" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)\+([0-9]+)$ ]]; then
93+ CODE="${BASH_REMATCH[2]}"
94+ elif [[ "$t" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
95+ CODE="$(git rev-list --count "$t" 2>/dev/null || echo 0)"
96+ else
97+ continue
98+ fi
99+ if [[ "$CODE" -gt "$MAX_CODE" ]]; then MAX_CODE="$CODE"; fi
100+ done
101+ if [[ "$NUMBER" -le "$MAX_CODE" ]]; then
102+ echo "ERROR: versionCode $NUMBER must be strictly greater than max existing $MAX_CODE" >&2
103+ echo "如需重新构建已发布的 tag,请在最新 commit 上加空 commit 后再打新 tag" >&2
104+ exit 1
105+ fi
106+
107+ # 校验 pubspec.yaml 版本号一致
71108 PUBSPEC_VERSION="$(grep '^version:' pubspec.yaml | awk '{print $2}' | cut -d'+' -f1)"
72109 if [[ "$NAME" != "$PUBSPEC_VERSION" ]]; then
73110 echo "ERROR: tag version ($NAME) does not match pubspec.yaml ($PUBSPEC_VERSION)" >&2
74111 echo "请先升级 pubspec.yaml 的 version 字段,再打 tag。" >&2
75112 exit 1
76113 fi
114+
77115 echo "name=$NAME" >> "$GITHUB_OUTPUT"
78116 echo "number=$NUMBER" >> "$GITHUB_OUTPUT"
79117 echo "version=${NAME}+${NUMBER}" >> "$GITHUB_OUTPUT"
80- echo "Parsed: name=$NAME number=$NUMBER (pubspec OK)"
118+ echo "Parsed: name=$NAME number=$NUMBER (pubspec OK, max existing code=$MAX_CODE )"
81119
82120 # ---------- Android ----------
83121
0 commit comments