#!/bin/bash # 版本发布脚本 # 用途: 创建版本发布归档,生成release notes,创建git tag set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 打印带颜色的信息 print_info() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } # 检查是否在项目根目录 check_project_root() { if [ ! -f "FILE_ORGANIZATION.md" ]; then print_error "请在项目根目录运行此脚本" exit 1 fi } # 检查是否在git仓库中 check_git_repo() { if ! git rev-parse --git-dir > /dev/null 2>&1; then print_error "不在git仓库中" exit 1 fi } # 显示使用说明 show_usage() { echo "使用方法: $0 <版本号> [发布类型]" echo "" echo "参数:" echo " 版本号 格式: X.Y.Z (如: 1.2.0)" echo " 发布类型 Major | Minor | Patch (可选,默认根据版本号判断)" echo "" echo "示例:" echo " $0 1.2.0" echo " $0 1.2.0 Minor" echo " $0 2.0.0 Major" echo "" echo "说明:" echo " - Major: 重大版本更新,可能包含不兼容的API变更" echo " - Minor: 次要版本更新,新增功能但向后兼容" echo " - Patch: 补丁版本,仅包含bug修复" exit 1 } # 验证版本号格式 validate_version() { local version=$1 if ! [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then print_error "版本号格式错误,应为 X.Y.Z" exit 1 fi } # 判断发布类型 determine_release_type() { local version=$1 local provided_type=$2 if [ -n "$provided_type" ]; then echo "$provided_type" return fi # 自动判断 local last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") local last_version=${last_tag#v} IFS='.' read -r -a curr_parts <<< "$version" IFS='.' read -r -a last_parts <<< "$last_version" if [ "${curr_parts[0]}" -gt "${last_parts[0]}" ]; then echo "Major" elif [ "${curr_parts[1]}" -gt "${last_parts[1]}" ]; then echo "Minor" else echo "Patch" fi } # 获取当前日期 get_date() { date +%Y-%m-%d } # 创建版本归档目录 create_version_dirs() { local version=$1 local version_path="archives/versions/v${version}" print_info "创建版本归档目录: ${version_path}" mkdir -p "${version_path}/backup" print_success "目录创建完成" echo "${version_path}" } # 获取commit统计 get_commit_stats() { local last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -z "$last_tag" ]; then # 如果没有tag,统计所有commit git rev-list --count HEAD else # 统计从上个tag到现在的commit git rev-list --count ${last_tag}..HEAD fi } # 获取变更的文件数 get_changed_files() { local last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -z "$last_tag" ]; then git diff --name-only --diff-filter=ACMR | wc -l else git diff --name-only --diff-filter=ACMR ${last_tag}..HEAD | wc -l fi } # 生成release notes create_release_notes() { local version=$1 local release_type=$2 local release_date=$3 local version_path=$4 local notes_path="${version_path}/release_notes.md" local template_path=".claude/templates/release_notes_template.md" print_info "生成Release Notes: ${notes_path}" local commit_count=$(get_commit_stats) local file_count=$(get_changed_files) local last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") local last_version=${last_tag#v} # 如果模板存在,使用模板 if [ -f "${template_path}" ]; then cp "${template_path}" "${notes_path}" # 替换模板变量 sed -i "s/{{VERSION}}/${version}/g" "${notes_path}" sed -i "s/{{RELEASE_DATE}}/${release_date}/g" "${notes_path}" sed -i "s/{{RELEASE_TYPE}}/${release_type}/g" "${notes_path}" sed -i "s/{{COMMIT_COUNT}}/${commit_count}/g" "${notes_path}" sed -i "s/{{FILE_COUNT}}/${file_count}/g" "${notes_path}" sed -i "s/{{OLD_VERSION}}/${last_version}/g" "${notes_path}" sed -i "s/{{PREVIOUS_VERSION}}/${last_version}/g" "${notes_path}" else # 创建基本release notes cat > "${notes_path}" << EOF # Release Notes - v${version} **发布日期**: ${release_date} **版本号**: ${version} **发布类型**: ${release_type} --- ## 版本概述 [简要描述本版本的主要更新内容] ## 重要变更 ⚠️ [列出所有重大变更] ## 新增功能 ✨ - [功能1] - [功能2] ## Bug修复 🐛 - [Bug修复1] - [Bug修复2] ## 性能优化 🚀 - [优化项1] - [优化项2] ## 统计数据 - **总提交数**: ${commit_count} - **修改文件数**: ${file_count} - **上一版本**: ${last_version} ## 升级指南 ### 从 v${last_version} 升级 1. 备份当前版本 2. 更新代码 3. 重新编译 4. 测试验证 ## 获取此版本 \`\`\`bash git clone git checkout v${version} \`\`\` --- **归档位置**: \`archives/versions/v${version}/\` EOF fi print_success "Release Notes生成完成" echo "${notes_path}" } # 创建git tag create_git_tag() { local version=$1 local tag_name="v${version}" print_info "检查是否已存在tag: ${tag_name}" if git rev-parse "${tag_name}" >/dev/null 2>&1; then print_warning "Tag ${tag_name} 已存在" read -p "是否删除并重新创建? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then git tag -d "${tag_name}" print_info "已删除旧tag" else print_info "跳过创建tag" return fi fi print_info "创建git tag: ${tag_name}" git tag -a "${tag_name}" -m "Release version ${version}" print_success "Git tag创建完成" echo "" print_info "推送tag到远程仓库:" echo " git push origin ${tag_name}" } # 可选:备份代码 backup_code() { local version_path=$1 echo "" read -p "是否备份完整代码到归档目录? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then print_info "创建代码备份..." local backup_file="${version_path}/backup/source_code.tar.gz" tar -czf "${backup_file}" \ --exclude='.git' \ --exclude='build' \ --exclude='archives' \ --exclude='*.o' \ --exclude='*.so' \ --exclude='*.dll' \ src/ include/ examples/ CMakeLists.txt print_success "代码备份完成: ${backup_file}" else print_info "跳过代码备份" fi } # 显示下一步操作 show_next_steps() { local version=$1 local notes_path=$2 local version_path=$3 echo "" print_success "版本发布归档创建完成!" echo "" echo "📁 版本目录: ${version_path}" echo "📄 Release Notes: ${notes_path}" echo "🏷️ Git Tag: v${version}" echo "" print_info "下一步操作:" echo " 1. 编辑Release Notes: vim ${notes_path}" echo " 2. 检查并补充版本信息" echo " 3. 提交归档: git add archives/versions/ && git commit -m \"release: v${version}\"" echo " 4. 推送tag: git push origin v${version}" echo " 5. 在GitHub/GitLab创建Release" echo "" } # 主函数 main() { # 检查参数 if [ $# -lt 1 ]; then show_usage fi local version=$1 local release_type=$2 # 验证版本号 validate_version "${version}" # 检查环境 check_project_root check_git_repo # 确定发布类型 release_type=$(determine_release_type "${version}" "${release_type}") # 获取日期 local release_date=$(get_date) print_info "开始创建版本发布" print_info "版本号: ${version}" print_info "发布类型: ${release_type}" print_info "发布日期: ${release_date}" echo "" # 确认 read -p "确认创建版本 v${version}? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_info "取消操作" exit 0 fi # 创建版本目录 local version_path=$(create_version_dirs "${version}") # 生成Release Notes local notes_path=$(create_release_notes "${version}" "${release_type}" "${release_date}" "${version_path}") # 创建Git Tag create_git_tag "${version}" # 可选备份 backup_code "${version_path}" # 显示下一步操作 show_next_steps "${version}" "${notes_path}" "${version_path}" } # 运行主函数 main "$@"