| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #!/usr/bin/env bash
- # CoinVision 版本号升级脚本
- #
- # 同步更新两处版本号:
- # 1) pubspec.yaml → version: X.Y.Z+CODE
- # 2) lib/core/config/app_config.dart → static const String appVersion = 'X.Y.Z';
- #
- # 用法:
- # ./scripts/bump-version.sh patch # 4.0.3 → 4.0.4 (修订号+1)
- # ./scripts/bump-version.sh minor # 4.0.3 → 4.1.0 (次版本+1,修订号归零)
- # ./scripts/bump-version.sh major # 4.0.3 → 5.0.0 (主版本+1,次/修订归零)
- # ./scripts/bump-version.sh 4.2.1 # 手动指定版本号
- # ./scripts/bump-version.sh --show # 只显示当前版本,不修改
- # ./scripts/bump-version.sh --dry-run patch # 预览改动,不写入文件
- #
- # versionCode 规则: major × 10000 + minor × 100 + patch
- # 例: 4.0.3 → 40003 ; 4.1.0 → 40100 ; 5.0.0 → 50000
- #
- # 安全检查:
- # - 新 versionCode 必须严格大于当前 versionCode,否则拒绝更新
- # - pubspec.yaml 的 x.y.z 必须和 app_config.dart 的 appVersion 一致
- set -euo pipefail
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
- cd "$PROJECT_ROOT"
- PUBSPEC="pubspec.yaml"
- APP_CONFIG="lib/core/config/app_config.dart"
- if [ -t 1 ]; then
- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
- BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
- else
- RED=''; GREEN=''; YELLOW=''; BLUE=''; CYAN=''; BOLD=''; NC=''
- fi
- log_info() { printf "${BLUE}==>${NC} %s\n" "$*"; }
- log_ok() { printf "${GREEN}✓${NC} %s\n" "$*"; }
- log_warn() { printf "${YELLOW}!${NC} %s\n" "$*"; }
- log_err() { printf "${RED}✗${NC} %s\n" "$*" >&2; }
- usage() {
- cat <<EOF
- CoinVision 版本号升级脚本
- 用法:
- ./scripts/bump-version.sh <模式> [选项]
- 模式:
- patch 修订号 +1 (4.0.3 → 4.0.4)
- minor 次版本 +1,修订号归零 (4.0.3 → 4.1.0)
- major 主版本 +1,次/修订归零 (4.0.3 → 5.0.0)
- X.Y.Z 手动指定版本号 (如 4.2.1)
- --show 仅显示当前版本,不修改
- 选项:
- --dry-run 预览改动,不写入文件
- -h, --help 显示此帮助
- 示例:
- ./scripts/bump-version.sh --show
- ./scripts/bump-version.sh patch
- ./scripts/bump-version.sh minor --dry-run
- ./scripts/bump-version.sh 4.2.1
- versionCode = major × 10000 + minor × 100 + patch
- EOF
- }
- if [ ! -f "$PUBSPEC" ]; then
- log_err "找不到 $PUBSPEC"
- exit 1
- fi
- if [ ! -f "$APP_CONFIG" ]; then
- log_err "找不到 $APP_CONFIG"
- exit 1
- fi
- # ── 解析当前版本 ─────────────────────────────────────────────
- CURRENT_LINE=$(grep -E "^version:" "$PUBSPEC" | head -1)
- if [ -z "$CURRENT_LINE" ]; then
- log_err "$PUBSPEC 中未找到 version: 行"
- exit 1
- fi
- CURRENT_VERSION_FULL=$(echo "$CURRENT_LINE" | awk '{print $2}' | tr -d '[:space:]')
- CURRENT_SEMVER="${CURRENT_VERSION_FULL%%+*}"
- CURRENT_CODE="${CURRENT_VERSION_FULL##*+}"
- if ! echo "$CURRENT_SEMVER" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
- log_err "当前 pubspec.yaml 版本号格式非法: $CURRENT_SEMVER (应为 x.y.z)"
- exit 1
- fi
- if ! echo "$CURRENT_CODE" | grep -qE '^[0-9]+$'; then
- log_err "当前 pubspec.yaml versionCode 格式非法: $CURRENT_CODE"
- exit 1
- fi
- CURRENT_MAJOR="${CURRENT_SEMVER%%.*}"
- CURRENT_REST="${CURRENT_SEMVER#*.}"
- CURRENT_MINOR="${CURRENT_REST%%.*}"
- CURRENT_PATCH="${CURRENT_REST##*.}"
- # ── 解析 app_config.dart 中的 appVersion ────────────────────
- APP_CONFIG_VERSION=$(grep -E "static const String appVersion" "$APP_CONFIG" | sed -E "s/.*'([^']+)'.*/\1/")
- if [ -z "$APP_CONFIG_VERSION" ]; then
- log_err "$APP_CONFIG 中未找到 static const String appVersion"
- exit 1
- fi
- # ── 参数解析 ─────────────────────────────────────────────────
- MODE=""
- DRY_RUN=false
- while [ $# -gt 0 ]; do
- case "$1" in
- -h|--help) usage; exit 0 ;;
- --show)
- printf "${CYAN}${BOLD}当前版本${NC}\n"
- printf " pubspec.yaml : %s (semver=%s, code=%s)\n" "$CURRENT_VERSION_FULL" "$CURRENT_SEMVER" "$CURRENT_CODE"
- printf " app_config.dart : %s\n" "$APP_CONFIG_VERSION"
- if [ "$CURRENT_SEMVER" != "$APP_CONFIG_VERSION" ]; then
- log_warn "两处版本号不一致!"
- exit 1
- fi
- exit 0
- ;;
- --dry-run) DRY_RUN=true ;;
- patch|minor|major)
- MODE="$1"
- ;;
- [0-9]*.[0-9]*.[0-9]*)
- MODE="manual"
- MANUAL_VERSION="$1"
- ;;
- *) log_err "未知参数: $1"; echo; usage; exit 1 ;;
- esac
- shift
- done
- if [ -z "$MODE" ]; then
- log_err "未指定模式"
- echo
- usage
- exit 1
- fi
- # ── 一致性校验 ───────────────────────────────────────────────
- if [ "$CURRENT_SEMVER" != "$APP_CONFIG_VERSION" ]; then
- log_warn "pubspec.yaml ($CURRENT_SEMVER) 与 app_config.dart ($APP_CONFIG_VERSION) 不一致"
- log_warn "将以 pubspec.yaml 为基准计算新版本"
- fi
- # ── 计算新版本 ───────────────────────────────────────────────
- case "$MODE" in
- patch)
- NEW_MAJOR="$CURRENT_MAJOR"
- NEW_MINOR="$CURRENT_MINOR"
- NEW_PATCH=$((CURRENT_PATCH + 1))
- ;;
- minor)
- NEW_MAJOR="$CURRENT_MAJOR"
- NEW_MINOR=$((CURRENT_MINOR + 1))
- NEW_PATCH=0
- ;;
- major)
- NEW_MAJOR=$((CURRENT_MAJOR + 1))
- NEW_MINOR=0
- NEW_PATCH=0
- ;;
- manual)
- if ! echo "$MANUAL_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
- log_err "手动版本号格式非法: $MANUAL_VERSION (应为 x.y.z)"
- exit 1
- fi
- NEW_MAJOR="${MANUAL_VERSION%%.*}"
- _REST="${MANUAL_VERSION#*.}"
- NEW_MINOR="${_REST%%.*}"
- NEW_PATCH="${_REST##*.}"
- ;;
- esac
- # 修订号不得超过 99,否则和下一个次版本的 versionCode 冲突
- if [ "$NEW_PATCH" -gt 99 ]; then
- log_err "修订号 $NEW_PATCH 超过 99,会和下一个次版本 versionCode 冲突"
- log_err "建议升级 minor 版本: ./scripts/bump-version.sh minor"
- exit 1
- fi
- if [ "$NEW_MINOR" -gt 99 ]; then
- log_err "次版本号 $NEW_MINOR 超过 99,会和下一个主版本 versionCode 冲突"
- log_err "建议升级 major 版本: ./scripts/bump-version.sh major"
- exit 1
- fi
- NEW_SEMVER="${NEW_MAJOR}.${NEW_MINOR}.${NEW_PATCH}"
- NEW_CODE=$((NEW_MAJOR * 10000 + NEW_MINOR * 100 + NEW_PATCH))
- NEW_VERSION_FULL="${NEW_SEMVER}+${NEW_CODE}"
- # ── 安全检查: versionCode 必须严格递增 ──────────────────────
- if [ "$NEW_CODE" -le "$CURRENT_CODE" ]; then
- log_err "新 versionCode ($NEW_CODE) 不大于当前 versionCode ($CURRENT_CODE)"
- log_err "Android 拒绝安装 versionCode 更低或相同的包"
- exit 1
- fi
- # ── 展示变化 ─────────────────────────────────────────────────
- printf "\n${CYAN}${BOLD}版本号变更预览${NC}\n"
- printf " 版本号 : ${YELLOW}%s${NC} → ${GREEN}%s${NC}\n" "$CURRENT_SEMVER" "$NEW_SEMVER"
- printf " versionCode : ${YELLOW}%s${NC} → ${GREEN}%s${NC}\n" "$CURRENT_CODE" "$NEW_CODE"
- printf " 完整写入 : ${GREEN}%s${NC}\n" "$NEW_VERSION_FULL"
- printf "\n${CYAN}${BOLD}将更新文件${NC}\n"
- printf " %s (line: version: %s)\n" "$PUBSPEC" "$NEW_VERSION_FULL"
- printf " %s (line: static const String appVersion = '%s';)\n" "$APP_CONFIG" "$NEW_SEMVER"
- if [ "$DRY_RUN" = true ]; then
- echo
- log_info "dry-run 模式,未写入文件"
- exit 0
- fi
- # ── 写入文件 (macOS/BSD sed 和 GNU sed 兼容) ─────────────────
- sed_inplace() {
- local pattern="$1"
- local file="$2"
- # macOS BSD sed 要求 -i '' ; GNU sed 不能加 ''
- if sed --version >/dev/null 2>&1; then
- sed -i "$pattern" "$file"
- else
- sed -i '' "$pattern" "$file"
- fi
- }
- # pubspec.yaml: 替换第一个 ^version: 开头的行
- sed_inplace "s|^version:.*|version: ${NEW_VERSION_FULL}|" "$PUBSPEC"
- # app_config.dart: 替换 appVersion 常量
- sed_inplace "s|static const String appVersion = '[^']*';|static const String appVersion = '${NEW_SEMVER}';|" "$APP_CONFIG"
- # ── 写入验证 ─────────────────────────────────────────────────
- WRITTEN_PUBSPEC=$(grep -E "^version:" "$PUBSPEC" | awk '{print $2}' | tr -d '[:space:]')
- WRITTEN_CONFIG=$(grep -E "static const String appVersion" "$APP_CONFIG" | sed -E "s/.*'([^']+)'.*/\1/")
- if [ "$WRITTEN_PUBSPEC" != "$NEW_VERSION_FULL" ]; then
- log_err "写入 $PUBSPEC 失败,实际: $WRITTEN_PUBSPEC"
- exit 1
- fi
- if [ "$WRITTEN_CONFIG" != "$NEW_SEMVER" ]; then
- log_err "写入 $APP_CONFIG 失败,实际: $WRITTEN_CONFIG"
- exit 1
- fi
- echo
- log_ok "$PUBSPEC → version: $WRITTEN_PUBSPEC"
- log_ok "$APP_CONFIG → appVersion = '$WRITTEN_CONFIG'"
- # ── 下一步提示 ───────────────────────────────────────────────
- echo
- printf "${CYAN}${BOLD}下一步${NC}\n"
- printf " 1. 检查改动: ${BLUE}git diff $PUBSPEC $APP_CONFIG${NC}\n"
- printf " 2. 构建 Release: ${BLUE}./scripts/build.sh${NC}\n"
- printf " 3. 提交 + 打 tag:\n"
- printf " ${BLUE}git add $PUBSPEC $APP_CONFIG${NC}\n"
- printf " ${BLUE}git commit -m 'chore(release): bump version to $NEW_SEMVER'${NC}\n"
- printf " ${BLUE}git tag v$NEW_SEMVER${NC}\n"
|