蜂鸟Pro v2.0.1 - 基础框架版本 (待完善)
## 当前状态 - 插件界面已完成重命名 (cursorpro → hummingbird) - 双账号池 UI 已实现 (Auto/Pro 卡片) - 后端已切换到 MySQL 数据库 - 添加了 Cursor 官方用量 API 文档 ## 已知问题 (待修复) 1. 激活时检查账号导致无账号时激活失败 2. 未启用无感换号时不应获取账号 3. 账号用量模块不显示 (seamless 未启用时应隐藏) 4. 积分显示为 0 (后端未正确返回) 5. Auto/Pro 双密钥逻辑混乱,状态不同步 6. 账号添加后无自动分析功能 ## 下一版本计划 - 重构数据模型,优化账号状态管理 - 实现 Cursor API 自动分析账号 - 修复激活流程,不依赖账号 - 启用无感时才分配账号 - 完善账号用量实时显示 ## 文件说明 - docs/系统设计文档.md - 完整架构设计 - cursor 官方用量接口.md - Cursor API 文档 - 参考计费/ - Vibeviewer 开源项目参考 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
136
参考计费/Scripts/RELEASE_GUIDE.md
Normal file
136
参考计费/Scripts/RELEASE_GUIDE.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Release 流程指南
|
||||
|
||||
本文档描述了 Vibeviewer 项目的完整 Release 流程,包括构建、签名和上传。
|
||||
|
||||
## 前置要求
|
||||
|
||||
1. **GitHub CLI**
|
||||
```bash
|
||||
brew install gh
|
||||
gh auth login
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 方法 1: 使用自动化脚本(推荐)
|
||||
|
||||
```bash
|
||||
# 自动检测版本并执行完整流程
|
||||
./Scripts/release.sh
|
||||
|
||||
# 指定版本号
|
||||
./Scripts/release.sh 1.1.9
|
||||
|
||||
# 跳过构建(使用已有 DMG)
|
||||
./Scripts/release.sh --skip-build 1.1.9
|
||||
|
||||
# 跳过上传(仅本地操作)
|
||||
./Scripts/release.sh --skip-upload 1.1.9
|
||||
```
|
||||
|
||||
### 方法 2: 使用 Makefile
|
||||
|
||||
```bash
|
||||
# 构建 DMG
|
||||
make release
|
||||
|
||||
# 然后手动执行后续步骤
|
||||
```
|
||||
|
||||
### 方法 3: 手动步骤
|
||||
|
||||
1. **更新版本号**
|
||||
- 编辑 `Project.swift`,更新 `appVersion` 常量
|
||||
|
||||
2. **构建和创建 DMG**
|
||||
```bash
|
||||
make release
|
||||
# 或
|
||||
Scripts/create_dmg.sh --version 1.1.9
|
||||
```
|
||||
|
||||
3. **创建 Git Tag**
|
||||
```bash
|
||||
git tag -a v1.1.9 -m "Release version 1.1.9"
|
||||
git push origin v1.1.9
|
||||
```
|
||||
|
||||
4. **创建 GitHub Release**
|
||||
```bash
|
||||
gh release create v1.1.9 \
|
||||
--title "Version 1.1.9" \
|
||||
--notes "Release notes here" \
|
||||
Vibeviewer-1.1.9.dmg
|
||||
```
|
||||
|
||||
## 详细流程说明
|
||||
|
||||
### 1. 版本号管理
|
||||
|
||||
版本号在 `Project.swift` 中统一管理:
|
||||
- `appVersion`: 统一版本号配置(如 "1.1.9")
|
||||
- `MARKETING_VERSION`: 显示版本号(从 appVersion 读取)
|
||||
- `CURRENT_PROJECT_VERSION`: 构建版本号(从 appVersion 读取)
|
||||
- `CFBundleShortVersionString`: Info.plist 中的版本号(从 appVersion 读取)
|
||||
- `CFBundleVersion`: Info.plist 中的构建号(从 appVersion 读取)
|
||||
|
||||
### 2. 构建流程
|
||||
|
||||
`Scripts/create_dmg.sh` 脚本会:
|
||||
1. 清理之前的构建产物
|
||||
2. 构建 Release 版本应用
|
||||
3. 验证应用版本信息和代码签名
|
||||
4. 创建 DMG 安装包
|
||||
|
||||
### 3. GitHub Release
|
||||
|
||||
使用 GitHub CLI 创建 Release:
|
||||
- 自动生成变更日志(基于 Git commits)
|
||||
- 上传 DMG 文件
|
||||
- 创建 Release 页面
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: GitHub Release 创建失败
|
||||
|
||||
**可能原因**:
|
||||
- GitHub CLI 未认证
|
||||
- Tag 已存在
|
||||
- 网络问题
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 重新认证
|
||||
gh auth login
|
||||
|
||||
# 删除现有 Tag/Release
|
||||
git tag -d v1.1.9
|
||||
git push origin :refs/tags/v1.1.9
|
||||
gh release delete v1.1.9
|
||||
```
|
||||
|
||||
### 问题 2: 构建失败
|
||||
|
||||
**解决方案**:
|
||||
1. 检查 Xcode 是否正确安装
|
||||
2. 运行 `make clear` 清理构建缓存
|
||||
3. 检查 `Project.swift` 中的版本号配置
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **版本号**: 遵循语义化版本(Semantic Versioning)
|
||||
2. **变更日志**: 在 Release Notes 中清晰描述更新内容
|
||||
3. **测试**: 发布前在本地测试 DMG 安装
|
||||
4. **文档**: 重大更新时更新 README 和文档
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `Scripts/release.sh` - 完整的自动化 Release 脚本
|
||||
- `Scripts/create_dmg.sh` - DMG 创建脚本
|
||||
- `Project.swift` - 版本号配置
|
||||
- `Makefile` - 构建命令
|
||||
|
||||
## 参考链接
|
||||
|
||||
- [GitHub CLI 文档](https://cli.github.com/manual/)
|
||||
- [语义化版本](https://semver.org/)
|
||||
42
参考计费/Scripts/clear.sh
Normal file
42
参考计费/Scripts/clear.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/zsh
|
||||
set -euo pipefail
|
||||
|
||||
echo "[clean] Cleaning Xcode DerivedData for current project only..."
|
||||
|
||||
# Project name prefix inferred from repo root folder
|
||||
SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd)
|
||||
REPO_ROOT=$(cd -- "${SCRIPT_DIR}/.." && pwd)
|
||||
PROJECT_PREFIX=$(basename "$REPO_ROOT")
|
||||
|
||||
# Xcode DerivedData (current user)
|
||||
DERIVED_DATA_DIR=~/Library/Developer/Xcode/DerivedData
|
||||
|
||||
if [ -d "$DERIVED_DATA_DIR" ]; then
|
||||
# In zsh, enable null_glob so non-matching globs expand to empty
|
||||
setopt null_glob 2>/dev/null || true
|
||||
matches=("$DERIVED_DATA_DIR"/${PROJECT_PREFIX}-*)
|
||||
if [ ${#matches[@]} -gt 0 ]; then
|
||||
echo "[clean] Removing:"
|
||||
for p in "${matches[@]}"; do
|
||||
echo " - $p"
|
||||
done
|
||||
rm -rf "${matches[@]}"
|
||||
else
|
||||
echo "[clean] No DerivedData entries found for prefix: ${PROJECT_PREFIX}-*"
|
||||
fi
|
||||
else
|
||||
echo "[clean] Not found: $DERIVED_DATA_DIR"
|
||||
fi
|
||||
|
||||
# Clean Tuist caches for current project only
|
||||
# We pass --path to ensure tuist cleans caches scoped to this project
|
||||
if command -v tuist >/dev/null 2>&1; then
|
||||
echo "[clean] Cleaning Tuist caches for this project..."
|
||||
tuist clean --path "$REPO_ROOT" || true
|
||||
else
|
||||
echo "[clean] tuist not found, skipping tuist cache clean"
|
||||
fi
|
||||
|
||||
echo "[clean] Done."
|
||||
|
||||
|
||||
190
参考计费/Scripts/create_dmg.sh
Normal file
190
参考计费/Scripts/create_dmg.sh
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
APP_NAME="Vibeviewer"
|
||||
CONFIGURATION="Release"
|
||||
SCHEME="Vibeviewer"
|
||||
WORKSPACE="Vibeviewer.xcworkspace"
|
||||
BUILD_DIR="build"
|
||||
TEMP_DIR="temp_dmg"
|
||||
BACKGROUND_IMAGE_NAME="dmg_background.png"
|
||||
|
||||
# Script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# Parse command line arguments
|
||||
VERSION=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--version|-v)
|
||||
VERSION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
echo "用法: $0 [选项]"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " --version, -v <版本> 指定版本号(默认从应用 Info.plist 读取)"
|
||||
echo " --help, -h 显示此帮助信息"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 # 仅创建 DMG"
|
||||
echo " $0 -v 1.1.9 # 指定版本创建 DMG"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "未知选项: $1"
|
||||
echo "使用 --help 查看帮助信息"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🚀 Starting DMG creation process for ${APP_NAME}...${NC}"
|
||||
|
||||
# Clean up previous builds
|
||||
echo -e "${YELLOW}📦 Cleaning up previous builds...${NC}"
|
||||
rm -rf "${BUILD_DIR}"
|
||||
rm -rf "${TEMP_DIR}"
|
||||
# Note: DMG_NAME will be set after version detection, so we clean up old DMGs separately
|
||||
rm -f "${APP_NAME}"-*.dmg
|
||||
|
||||
# Build the app
|
||||
echo -e "${BLUE}🔨 Building ${APP_NAME} in ${CONFIGURATION} configuration...${NC}"
|
||||
xcodebuild -workspace "${WORKSPACE}" \
|
||||
-scheme "${SCHEME}" \
|
||||
-configuration "${CONFIGURATION}" \
|
||||
-derivedDataPath "${BUILD_DIR}" \
|
||||
-destination "platform=macOS" \
|
||||
-skipMacroValidation \
|
||||
clean build
|
||||
|
||||
# Find the built app
|
||||
APP_PATH=$(find "${BUILD_DIR}" -name "${APP_NAME}.app" -type d | head -1)
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo -e "${RED}❌ Error: Could not find ${APP_NAME}.app in build output${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ Found app at: ${APP_PATH}${NC}"
|
||||
|
||||
# 验证 app 的版本信息和代码签名
|
||||
echo -e "${BLUE}🔍 验证 app 信息...${NC}"
|
||||
INFO_PLIST="${APP_PATH}/Contents/Info.plist"
|
||||
if [ -f "$INFO_PLIST" ]; then
|
||||
APP_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null || echo "")
|
||||
APP_BUILD=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST" 2>/dev/null || echo "")
|
||||
echo -e " 版本: ${APP_VERSION}"
|
||||
echo -e " Build: ${APP_BUILD}"
|
||||
|
||||
# 检查代码签名
|
||||
if codesign -dv "${APP_PATH}" 2>&1 | grep -q "code object is not signed"; then
|
||||
echo -e "${YELLOW}⚠️ 警告: App 未签名或签名无效${NC}"
|
||||
else
|
||||
SIGNING_IDENTITY=$(codesign -dv "${APP_PATH}" 2>&1 | grep "Authority=" | head -1 | sed 's/.*Authority=\(.*\)/\1/' || echo "未知")
|
||||
echo -e " 签名: ${SIGNING_IDENTITY}"
|
||||
|
||||
# 检查签名是否有效
|
||||
if ! codesign --verify --verbose "${APP_PATH}" 2>&1 | grep -q "valid on disk"; then
|
||||
echo -e "${YELLOW}⚠️ 警告: 代码签名验证失败${NC}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 警告: 找不到 Info.plist${NC}"
|
||||
fi
|
||||
|
||||
# Get version from Project.swift first (single source of truth), then from built app
|
||||
if [ -z "$VERSION" ]; then
|
||||
# 优先从 Project.swift 读取版本号(统一版本号配置)
|
||||
if [ -f "${PROJECT_ROOT}/Project.swift" ]; then
|
||||
VERSION=$(grep -E '^let appVersion\s*=' "${PROJECT_ROOT}/Project.swift" | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/' | head -1)
|
||||
fi
|
||||
|
||||
# Fallback: 从构建后的应用读取版本号
|
||||
if [ -z "$VERSION" ]; then
|
||||
INFO_PLIST="${APP_PATH}/Contents/Info.plist"
|
||||
if [ -f "$INFO_PLIST" ]; then
|
||||
VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null || echo "")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Final fallback
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo -e "${YELLOW}⚠️ 无法自动获取版本号,使用默认值 1.1.8${NC}"
|
||||
echo -e "${YELLOW} 提示: 使用 --version 参数指定版本号${NC}"
|
||||
VERSION="1.1.8"
|
||||
fi
|
||||
fi
|
||||
|
||||
DMG_NAME="${APP_NAME}-${VERSION}.dmg"
|
||||
echo -e "${BLUE}📦 版本: ${VERSION}${NC}"
|
||||
echo -e "${BLUE}📦 DMG 文件名: ${DMG_NAME}${NC}"
|
||||
|
||||
# Create temporary directory for DMG contents
|
||||
echo -e "${YELLOW}📁 Creating DMG contents...${NC}"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
cp -R "${APP_PATH}" "${TEMP_DIR}/"
|
||||
|
||||
# Create Applications symlink
|
||||
ln -s /Applications "${TEMP_DIR}/Applications"
|
||||
|
||||
# Create a simple background image if it doesn't exist
|
||||
if [ ! -f "${BACKGROUND_IMAGE_NAME}" ]; then
|
||||
echo -e "${YELLOW}🎨 Creating background image...${NC}"
|
||||
# Create a simple background using ImageMagick if available, otherwise skip
|
||||
if command -v convert >/dev/null 2>&1; then
|
||||
convert -size 600x400 xc:white \
|
||||
-fill '#f0f0f0' -draw 'rectangle 0,0 600,400' \
|
||||
-fill black -pointsize 20 -gravity center \
|
||||
-annotate +0-100 "Drag ${APP_NAME} to Applications" \
|
||||
"${BACKGROUND_IMAGE_NAME}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Copy background image if it exists
|
||||
if [ -f "${BACKGROUND_IMAGE_NAME}" ]; then
|
||||
cp "${BACKGROUND_IMAGE_NAME}" "${TEMP_DIR}/.background.png"
|
||||
fi
|
||||
|
||||
# Create DMG
|
||||
echo -e "${BLUE}💽 Creating DMG file...${NC}"
|
||||
hdiutil create -volname "${APP_NAME}" \
|
||||
-srcfolder "${TEMP_DIR}" \
|
||||
-ov \
|
||||
-format UDZO \
|
||||
-imagekey zlib-level=9 \
|
||||
"${DMG_NAME}"
|
||||
|
||||
# Clean up temporary files
|
||||
echo -e "${YELLOW}🧹 Cleaning up temporary files...${NC}"
|
||||
rm -rf "${TEMP_DIR}"
|
||||
rm -rf "${BUILD_DIR}"
|
||||
|
||||
# Get DMG size
|
||||
DMG_SIZE=$(du -h "${DMG_NAME}" | cut -f1)
|
||||
|
||||
echo -e "${GREEN}🎉 DMG creation completed successfully!${NC}"
|
||||
echo -e "${GREEN}📦 Output: ${DMG_NAME} (${DMG_SIZE})${NC}"
|
||||
echo -e "${GREEN}📍 Location: $(pwd)/${DMG_NAME}${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}📋 下一步:${NC}"
|
||||
echo -e "1. 在 GitHub 上创建 Release (tag: v${VERSION})"
|
||||
echo -e "2. 上传 DMG 文件: ${DMG_NAME}"
|
||||
echo -e "3. 填写 Release Notes"
|
||||
|
||||
# Optional: Open the directory containing the DMG
|
||||
if command -v open >/dev/null 2>&1; then
|
||||
echo ""
|
||||
echo -e "${BLUE}📂 Opening directory...${NC}"
|
||||
open .
|
||||
fi
|
||||
21
参考计费/Scripts/generate.sh
Normal file
21
参考计费/Scripts/generate.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/zsh
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd)
|
||||
REPO_ROOT=$(cd -- "${SCRIPT_DIR}/.." && pwd)
|
||||
|
||||
cd "${REPO_ROOT}"
|
||||
|
||||
echo "[tuist] Generating project..."
|
||||
tuist install || {
|
||||
echo "[tuist] install failed" >&2
|
||||
exit 1
|
||||
}
|
||||
tuist generate || {
|
||||
echo "[tuist] generate failed" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "[tuist] Done. Open with: open Vibeviewer.xcworkspace"
|
||||
|
||||
|
||||
226
参考计费/Scripts/release.sh
Normal file
226
参考计费/Scripts/release.sh
Normal file
@@ -0,0 +1,226 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 完整的 Release 流程脚本
|
||||
# 用法: ./Scripts/release.sh [VERSION] [--skip-build] [--skip-upload] [--skip-commit]
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
APP_NAME="Vibeviewer"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 解析参数
|
||||
SKIP_BUILD=false
|
||||
SKIP_UPLOAD=false
|
||||
VERSION=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--skip-build)
|
||||
SKIP_BUILD=true
|
||||
shift
|
||||
;;
|
||||
--skip-upload)
|
||||
SKIP_UPLOAD=true
|
||||
shift
|
||||
;;
|
||||
--version|-v)
|
||||
VERSION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
echo "用法: $0 [选项] [VERSION]"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " --version, -v <版本> 指定版本号(默认从 Project.swift 读取)"
|
||||
echo " --skip-build 跳过构建步骤"
|
||||
echo " --skip-upload 跳过上传到 GitHub Release"
|
||||
echo " --help, -h 显示此帮助信息"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 # 自动检测版本并完整流程"
|
||||
echo " $0 1.1.7 # 指定版本号"
|
||||
echo " $0 --skip-build 1.1.7 # 跳过构建(使用已有 DMG)"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
if [ -z "$VERSION" ] && [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
VERSION="$1"
|
||||
else
|
||||
echo -e "${RED}❌ 未知选项: $1${NC}"
|
||||
echo "使用 --help 查看帮助信息"
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo -e "${BLUE}🚀 开始 Release 流程...${NC}"
|
||||
echo ""
|
||||
|
||||
# 1. 获取版本号(从 Project.swift 的统一版本号配置读取)
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo -e "${BLUE}📋 检测版本号...${NC}"
|
||||
# 优先从 appVersion 常量读取(统一版本号配置)
|
||||
VERSION=$(grep -E '^let appVersion\s*=' "$PROJECT_ROOT/Project.swift" | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/' | head -1)
|
||||
|
||||
# Fallback: 从 MARKETING_VERSION 读取
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION=$(grep -E 'MARKETING_VERSION' "$PROJECT_ROOT/Project.swift" | head -1 | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/')
|
||||
fi
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo -e "${RED}❌ 无法自动检测版本号${NC}"
|
||||
echo -e "${YELLOW} 请使用 --version 参数指定版本号${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ 版本号: ${VERSION}${NC}"
|
||||
echo ""
|
||||
|
||||
# 2. 检查 GitHub CLI
|
||||
if ! command -v gh >/dev/null 2>&1; then
|
||||
echo -e "${RED}❌ 错误: 需要 GitHub CLI (gh)${NC}"
|
||||
echo -e "${YELLOW} 安装: brew install gh${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. 构建和创建 DMG
|
||||
DMG_NAME="${APP_NAME}-${VERSION}.dmg"
|
||||
if [ "$SKIP_BUILD" = false ]; then
|
||||
echo -e "${BLUE}🔨 构建 Release 版本并创建 DMG...${NC}"
|
||||
"$SCRIPT_DIR/create_dmg.sh" --version "$VERSION" || {
|
||||
echo -e "${RED}❌ 构建失败${NC}"
|
||||
exit 1
|
||||
}
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}⏭️ 跳过构建步骤${NC}"
|
||||
if [ ! -f "$DMG_NAME" ]; then
|
||||
echo -e "${RED}❌ 错误: DMG 文件不存在: $DMG_NAME${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 5. 检查 Git 状态
|
||||
echo -e "${BLUE}📋 检查 Git 状态...${NC}"
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo -e "${YELLOW}⚠️ 有未提交的更改${NC}"
|
||||
git status --short
|
||||
echo ""
|
||||
read -p "是否继续?(y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 6. 创建 Git Tag
|
||||
echo -e "${BLUE}🏷️ 创建 Git Tag...${NC}"
|
||||
if git rev-parse "v${VERSION}" >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}⚠️ Tag v${VERSION} 已存在${NC}"
|
||||
read -p "是否删除并重新创建?(y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
git tag -d "v${VERSION}" 2>/dev/null || true
|
||||
git push origin ":refs/tags/v${VERSION}" 2>/dev/null || true
|
||||
else
|
||||
echo -e "${YELLOW}⏭️ 跳过 Tag 创建${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! git rev-parse "v${VERSION}" >/dev/null 2>&1; then
|
||||
git tag -a "v${VERSION}" -m "Release version ${VERSION}"
|
||||
echo -e "${GREEN}✅ Tag v${VERSION} 已创建${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⏭️ 使用现有 Tag${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 7. 创建 GitHub Release
|
||||
if [ "$SKIP_UPLOAD" = false ]; then
|
||||
echo -e "${BLUE}📤 创建 GitHub Release...${NC}"
|
||||
|
||||
# 检查 Release 是否已存在
|
||||
if gh release view "v${VERSION}" >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}⚠️ Release v${VERSION} 已存在${NC}"
|
||||
read -p "是否删除并重新创建?(y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
gh release delete "v${VERSION}" --yes 2>/dev/null || true
|
||||
else
|
||||
echo -e "${YELLOW}⏭️ 跳过 Release 创建,直接上传 DMG${NC}"
|
||||
gh release upload "v${VERSION}" "$DMG_NAME" --clobber || {
|
||||
echo -e "${RED}❌ 上传失败${NC}"
|
||||
exit 1
|
||||
}
|
||||
echo -e "${GREEN}✅ DMG 已上传${NC}"
|
||||
echo ""
|
||||
SKIP_RELEASE_CREATE=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$SKIP_RELEASE_CREATE" != true ]; then
|
||||
# 获取变更日志
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
|
||||
if [ -n "$PREV_TAG" ]; then
|
||||
CHANGELOG=$(git log "${PREV_TAG}..HEAD" --pretty=format:"- %s" | head -20)
|
||||
else
|
||||
CHANGELOG=$(git log --oneline -10 --pretty=format:"- %s")
|
||||
fi
|
||||
|
||||
RELEASE_NOTES=$(cat <<EOF
|
||||
## 更新内容
|
||||
|
||||
${CHANGELOG}
|
||||
|
||||
## 技术改进
|
||||
|
||||
- 版本更新至 ${VERSION}
|
||||
- 优化自动更新机制
|
||||
EOF
|
||||
)
|
||||
|
||||
# 创建 Release
|
||||
gh release create "v${VERSION}" \
|
||||
--title "Version ${VERSION}" \
|
||||
--notes "$RELEASE_NOTES" \
|
||||
"$DMG_NAME" || {
|
||||
echo -e "${RED}❌ Release 创建失败${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "${GREEN}✅ GitHub Release 已创建${NC}"
|
||||
echo -e "${BLUE} URL: https://github.com/MarveleE/Vibeviewer/releases/tag/v${VERSION}${NC}"
|
||||
fi
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}⏭️ 跳过上传步骤${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 8. 推送 Tag
|
||||
echo -e "${BLUE}📤 推送 Git Tag...${NC}"
|
||||
git push origin "v${VERSION}" || {
|
||||
echo -e "${YELLOW}⚠️ Tag 推送失败或已存在${NC}"
|
||||
}
|
||||
echo ""
|
||||
|
||||
# 完成
|
||||
echo -e "${GREEN}🎉 Release 流程完成!${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}📋 总结:${NC}"
|
||||
echo -e " 版本: ${VERSION}"
|
||||
echo -e " DMG: ${DMG_NAME}"
|
||||
echo -e " Release: https://github.com/MarveleE/Vibeviewer/releases/tag/v${VERSION}"
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user