2025-06-15 18:17:45 +08:00

554 lines
23 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: Auto Release to PyPI
on:
workflow_dispatch:
inputs:
version_type:
description: 'Version bump type (ignored if custom_version is provided)'
required: false
default: 'patch'
type: choice
options:
- patch # 2.0.0 -> 2.0.1 (bug fixes, security patches, documentation updates)
- minor # 2.0.0 -> 2.1.0 (new features, enhancements, backward-compatible changes)
- major # 2.0.0 -> 3.0.0 (breaking changes, architecture refactoring, API changes)
custom_version:
description: 'Custom version number (e.g., 2.5.0) - overrides version_type if provided'
required: false
type: string
include_desktop:
description: '是否包含桌面應用二進制文件'
required: true
default: true
type: boolean
desktop_build_run_id:
description: '桌面應用構建的 Run ID可選留空使用最新的成功構建'
required: false
type: string
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python
run: uv python install
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
uv sync --dev
- name: Configure Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Commit dependency changes if any
run: |
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit -m "📦 Update dependencies" || true
fi
- name: Get current version
id: current_version
run: |
CURRENT_VERSION=$(grep '^version =' pyproject.toml | cut -d'"' -f2)
echo "current=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
- name: Determine new version
id: bump_version
run: |
CUSTOM_VERSION="${{ github.event.inputs.custom_version }}"
if [ -n "$CUSTOM_VERSION" ]; then
echo "🎯 Using custom version: $CUSTOM_VERSION"
# Validate version format (basic semver check)
if [[ ! "$CUSTOM_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Error: Custom version must be in format X.Y.Z (e.g., 2.5.0)"
exit 1
fi
# Update version in pyproject.toml
sed -i "s/^version = \".*\"/version = \"$CUSTOM_VERSION\"/" pyproject.toml
# Update version in .bumpversion.cfg
sed -i "s/^current_version = .*/current_version = $CUSTOM_VERSION/" .bumpversion.cfg
NEW_VERSION="$CUSTOM_VERSION"
echo "✅ Set custom version: $NEW_VERSION"
else
echo "🔄 Using automatic version bump: ${{ github.event.inputs.version_type }}"
uv run bump2version --allow-dirty ${{ github.event.inputs.version_type }}
NEW_VERSION=$(grep '^version =' pyproject.toml | cut -d'"' -f2)
echo "✅ Bumped version to: $NEW_VERSION"
fi
echo "new=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Update __init__.py version
run: |
NEW_VERSION="${{ steps.bump_version.outputs.new }}"
sed -i "s/__version__ = \".*\"/__version__ = \"$NEW_VERSION\"/" src/mcp_feedback_enhanced/__init__.py
- name: Extract Release Highlights
id: extract_highlights
run: |
NEW_VERSION="v${{ steps.bump_version.outputs.new }}"
# Extract highlights from English CHANGELOG
if [ -f "RELEASE_NOTES/CHANGELOG.en.md" ]; then
echo "🔍 Extracting highlights for $NEW_VERSION from CHANGELOG..."
# Step 1: Find the version section and extract everything until next version
sed -n "/## \[${NEW_VERSION}\]/,/## \[/p" RELEASE_NOTES/CHANGELOG.en.md | head -n -1 > version_section.txt
# Step 2: Try to extract highlights section
if grep -q "### 🌟 Highlights" version_section.txt; then
echo "📝 Found Highlights section"
sed -n '/### 🌟 Highlights/,/### /p' version_section.txt | head -n -1 | tail -n +2 | grep -E "^[^#]" | head -5 > highlights.txt
elif grep -q "### ✨ New Features" version_section.txt; then
echo "📝 Using New Features section as highlights"
sed -n '/### ✨ New Features/,/### /p' version_section.txt | head -n -1 | tail -n +2 | grep -E "^- " | head -4 > highlights.txt
else
echo "⚠️ No highlights or new features section found"
echo "" > highlights.txt
fi
# Clean up temporary file
rm -f version_section.txt
# Check if we got any content
if [ -s highlights.txt ]; then
echo "✅ Successfully extracted highlights for $NEW_VERSION"
echo "📄 Content preview:"
head -2 highlights.txt
else
echo "⚠️ No highlights extracted, using default content"
echo "- 🚀 New features and improvements" > highlights.txt
echo "- 🐛 Bug fixes and optimizations" >> highlights.txt
fi
else
echo "⚠️ CHANGELOG.en.md not found, using default highlights"
echo "- 🚀 New features and improvements" > highlights.txt
echo "- 🐛 Bug fixes and optimizations" >> highlights.txt
fi
- name: Generate Release Body
id: release_body
run: |
NEW_VERSION="v${{ steps.bump_version.outputs.new }}"
# Get release title from English CHANGELOG
if [ -f "RELEASE_NOTES/CHANGELOG.en.md" ]; then
RELEASE_TITLE=$(grep "## \[${NEW_VERSION}\]" RELEASE_NOTES/CHANGELOG.en.md | head -1 | sed 's/## \[.*\] - //')
fi
if [ -z "$RELEASE_TITLE" ]; then
RELEASE_TITLE="Latest Release"
fi
# Create release body header
echo "# Release ${NEW_VERSION} - ${RELEASE_TITLE}" > release_body.md
echo "" >> release_body.md
echo "## 🌟 Key Highlights" >> release_body.md
# Add highlights
if [ -s highlights.txt ]; then
cat highlights.txt >> release_body.md
else
echo "- 🚀 New features and improvements" >> release_body.md
echo "- 🐛 Bug fixes and optimizations" >> release_body.md
fi
# Add multi-language links section
echo "" >> release_body.md
echo "## 🌐 Detailed Release Notes" >> release_body.md
echo "" >> release_body.md
echo "### 🇺🇸 English" >> release_body.md
echo "📖 **[View Complete English Release Notes](https://github.com/Minidoracat/mcp-feedback-enhanced/blob/main/RELEASE_NOTES/CHANGELOG.en.md)**" >> release_body.md
echo "" >> release_body.md
echo "### 🇹🇼 繁體中文" >> release_body.md
echo "📖 **[查看完整繁體中文發布說明](https://github.com/Minidoracat/mcp-feedback-enhanced/blob/main/RELEASE_NOTES/CHANGELOG.zh-TW.md)**" >> release_body.md
echo "" >> release_body.md
echo "### 🇨🇳 简体中文" >> release_body.md
echo "📖 **[查看完整简体中文发布说明](https://github.com/Minidoracat/mcp-feedback-enhanced/blob/main/RELEASE_NOTES/CHANGELOG.zh-CN.md)**" >> release_body.md
echo "" >> release_body.md
echo "---" >> release_body.md
echo "" >> release_body.md
echo "## 📦 Quick Installation / 快速安裝" >> release_body.md
echo "" >> release_body.md
echo '```bash' >> release_body.md
echo "# Latest version / 最新版本" >> release_body.md
echo "uvx mcp-feedback-enhanced@latest" >> release_body.md
echo "" >> release_body.md
echo "# This specific version / 此特定版本" >> release_body.md
echo "uvx mcp-feedback-enhanced@${NEW_VERSION}" >> release_body.md
echo '```' >> release_body.md
echo "" >> release_body.md
echo "## 🔗 Links" >> release_body.md
echo "- **Documentation**: [README.md](https://github.com/Minidoracat/mcp-feedback-enhanced/blob/main/README.md)" >> release_body.md
echo "- **Full Changelog**: [CHANGELOG](https://github.com/Minidoracat/mcp-feedback-enhanced/blob/main/RELEASE_NOTES/)" >> release_body.md
echo "- **Issues**: [GitHub Issues](https://github.com/Minidoracat/mcp-feedback-enhanced/issues)" >> release_body.md
echo "" >> release_body.md
echo "---" >> release_body.md
echo "**Release automatically generated from CHANGELOG system** 🤖" >> release_body.md
echo "Release body generated successfully"
- name: Verify CHANGELOG Files
run: |
NEW_VERSION="v${{ steps.bump_version.outputs.new }}"
# Check if CHANGELOG files exist and contain the new version
echo "🔍 Verifying CHANGELOG files contain version ${NEW_VERSION}..."
MISSING_FILES=""
if [ -f "RELEASE_NOTES/CHANGELOG.en.md" ]; then
if ! grep -q "\[${NEW_VERSION}\]" "RELEASE_NOTES/CHANGELOG.en.md"; then
echo "⚠️ Warning: ${NEW_VERSION} not found in CHANGELOG.en.md"
MISSING_FILES="${MISSING_FILES} en"
else
echo "✅ Found ${NEW_VERSION} in CHANGELOG.en.md"
fi
else
echo "❌ CHANGELOG.en.md not found"
MISSING_FILES="${MISSING_FILES} en"
fi
if [ -f "RELEASE_NOTES/CHANGELOG.zh-TW.md" ]; then
if ! grep -q "\[${NEW_VERSION}\]" "RELEASE_NOTES/CHANGELOG.zh-TW.md"; then
echo "⚠️ Warning: ${NEW_VERSION} not found in CHANGELOG.zh-TW.md"
MISSING_FILES="${MISSING_FILES} zh-TW"
else
echo "✅ Found ${NEW_VERSION} in CHANGELOG.zh-TW.md"
fi
else
echo "❌ CHANGELOG.zh-TW.md not found"
MISSING_FILES="${MISSING_FILES} zh-TW"
fi
if [ -f "RELEASE_NOTES/CHANGELOG.zh-CN.md" ]; then
if ! grep -q "\[${NEW_VERSION}\]" "RELEASE_NOTES/CHANGELOG.zh-CN.md"; then
echo "⚠️ Warning: ${NEW_VERSION} not found in CHANGELOG.zh-CN.md"
MISSING_FILES="${MISSING_FILES} zh-CN"
else
echo "✅ Found ${NEW_VERSION} in CHANGELOG.zh-CN.md"
fi
else
echo "❌ CHANGELOG.zh-CN.md not found"
MISSING_FILES="${MISSING_FILES} zh-CN"
fi
if [ -n "$MISSING_FILES" ]; then
echo ""
echo "📝 Note: Please ensure CHANGELOG files are updated with version ${NEW_VERSION}"
echo "Missing or incomplete files:${MISSING_FILES}"
echo "The release will continue, but manual CHANGELOG updates may be needed."
else
echo "✅ All CHANGELOG files verified successfully"
fi
- name: Commit version bump
run: |
CUSTOM_VERSION="${{ github.event.inputs.custom_version }}"
VERSION_METHOD=""
if [ -n "$CUSTOM_VERSION" ]; then
VERSION_METHOD="Custom version specified: $CUSTOM_VERSION"
else
VERSION_METHOD="Auto-bumped (${{ github.event.inputs.version_type }})"
fi
git add .
git commit -m "🔖 Release v${{ steps.bump_version.outputs.new }}
- Updated version to ${{ steps.bump_version.outputs.new }}
- $VERSION_METHOD
- Auto-generated release from workflow"
git tag "v${{ steps.bump_version.outputs.new }}"
- name: Check desktop build availability
if: ${{ github.event.inputs.include_desktop == 'true' }}
id: check_desktop
run: |
echo "🔍 檢查桌面應用構建可用性..."
# 如果指定了 run_id使用指定的構建
if [ -n "${{ github.event.inputs.desktop_build_run_id }}" ]; then
echo "🎯 使用指定的構建 Run ID: ${{ github.event.inputs.desktop_build_run_id }}"
echo "run_id=${{ github.event.inputs.desktop_build_run_id }}" >> $GITHUB_OUTPUT
else
echo "🔍 查找最新的成功桌面構建..."
# 使用 GitHub API 查找最新的成功構建
LATEST_RUN=$(curl -s \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-desktop.yml/runs?status=success&per_page=1" \
| jq -r '.workflow_runs[0].id // empty')
if [ -n "$LATEST_RUN" ] && [ "$LATEST_RUN" != "null" ]; then
echo "✅ 找到最新成功構建: $LATEST_RUN"
echo "run_id=$LATEST_RUN" >> $GITHUB_OUTPUT
else
echo "❌ 沒有找到成功的桌面構建"
echo "💡 請先運行 'Build Desktop Applications' 工作流程"
exit 1
fi
fi
- name: Download desktop binaries
if: ${{ github.event.inputs.include_desktop == 'true' }}
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: build-desktop.yml
run_id: ${{ steps.check_desktop.outputs.run_id }}
path: desktop-artifacts
if_no_artifact_found: error
- name: Prepare multi-platform desktop binaries
if: ${{ github.event.inputs.include_desktop == 'true' }}
run: |
echo "📦 準備多平台桌面應用二進制文件..."
# 檢查下載的產物
echo "🔍 檢查下載的桌面應用產物..."
if [ ! -d "desktop-artifacts" ]; then
echo "❌ 桌面產物目錄不存在"
exit 1
fi
echo "📁 產物目錄內容:"
find desktop-artifacts -type f -name "*" | head -20
# 創建桌面應用目錄
mkdir -p src/mcp_feedback_enhanced/desktop_release
# 定義平台映射
declare -A PLATFORM_MAP=(
["desktop-windows"]="mcp-feedback-enhanced-desktop.exe"
["desktop-macos-intel"]="mcp-feedback-enhanced-desktop-macos-intel"
["desktop-macos-arm64"]="mcp-feedback-enhanced-desktop-macos-arm64"
["desktop-linux"]="mcp-feedback-enhanced-desktop-linux"
)
# 複製並重命名二進制文件
COPIED_COUNT=0
TOTAL_PLATFORMS=4
for platform_dir in desktop-windows desktop-macos-intel desktop-macos-arm64 desktop-linux; do
echo "🔍 處理平台: $platform_dir"
# 查找該平台的二進制文件
BINARY_FILE=""
if [ -d "desktop-artifacts/$platform_dir" ]; then
# 查找二進制文件(可能是 .exe 或無擴展名)
BINARY_FILE=$(find "desktop-artifacts/$platform_dir" -name "mcp-feedback-enhanced-desktop*" -type f | head -1)
fi
if [ -n "$BINARY_FILE" ] && [ -f "$BINARY_FILE" ]; then
TARGET_NAME="${PLATFORM_MAP[$platform_dir]}"
cp "$BINARY_FILE" "src/mcp_feedback_enhanced/desktop_release/$TARGET_NAME"
# 設置執行權限(非 Windows
if [[ "$TARGET_NAME" != *.exe ]]; then
chmod +x "src/mcp_feedback_enhanced/desktop_release/$TARGET_NAME"
fi
echo "✅ $platform_dir: $BINARY_FILE -> $TARGET_NAME"
COPIED_COUNT=$((COPIED_COUNT + 1))
else
echo "⚠️ $platform_dir: 未找到二進制文件"
fi
done
# 創建 __init__.py
echo '"""桌面應用程式二進制檔案"""' > src/mcp_feedback_enhanced/desktop_release/__init__.py
# 驗證結果
echo ""
echo "📊 複製結果統計:"
echo " 成功複製: $COPIED_COUNT/$TOTAL_PLATFORMS 個平台"
if [ $COPIED_COUNT -eq 0 ]; then
echo "❌ 沒有成功複製任何平台的二進制文件"
exit 1
elif [ $COPIED_COUNT -lt $TOTAL_PLATFORMS ]; then
echo "⚠️ 部分平台缺失,但繼續發佈"
else
echo "✅ 所有平台都已成功複製"
fi
# 顯示最終文件列表
echo ""
echo "📦 最終的桌面應用二進制文件:"
ls -la src/mcp_feedback_enhanced/desktop_release/
- name: Validate desktop binaries
if: ${{ github.event.inputs.include_desktop == 'true' }}
run: |
echo "🔍 驗證桌面應用二進制文件..."
if [ ! -d "src/mcp_feedback_enhanced/desktop_release" ]; then
echo "❌ 桌面應用目錄不存在"
exit 1
fi
# 檢查各平台文件
PLATFORMS=(
"mcp-feedback-enhanced-desktop.exe:Windows"
"mcp-feedback-enhanced-desktop-macos-intel:macOS Intel"
"mcp-feedback-enhanced-desktop-macos-arm64:macOS ARM64"
"mcp-feedback-enhanced-desktop-linux:Linux"
)
VALID_COUNT=0
for platform_info in "${PLATFORMS[@]}"; do
IFS=':' read -r filename description <<< "$platform_info"
filepath="src/mcp_feedback_enhanced/desktop_release/$filename"
if [ -f "$filepath" ]; then
filesize=$(stat -f%z "$filepath" 2>/dev/null || stat -c%s "$filepath" 2>/dev/null || echo "0")
if [ "$filesize" -gt 1000000 ]; then # 至少 1MB
echo "✅ $description: $filename (${filesize} bytes)"
VALID_COUNT=$((VALID_COUNT + 1))
else
echo "⚠️ $description: $filename 文件太小 (${filesize} bytes)"
fi
else
echo "❌ $description: $filename 不存在"
fi
done
echo ""
echo "📊 驗證結果: $VALID_COUNT/4 個平台有效"
if [ $VALID_COUNT -eq 0 ]; then
echo "❌ 沒有有效的桌面應用二進制文件"
echo "💡 建議:"
echo " 1. 檢查 'Build Desktop Applications' 工作流程是否成功"
echo " 2. 確認指定的 Run ID 是否正確"
echo " 3. 或者設置 include_desktop 為 false"
exit 1
fi
- name: Skip desktop applications
if: ${{ github.event.inputs.include_desktop != 'true' }}
run: |
echo "⏭️ 跳過桌面應用,僅發佈 Web 版本"
echo "💡 用戶將只能使用 Web 模式,無法使用桌面模式"
- name: Build package
run: uv build
- name: Check package
run: uv run twine check dist/*
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
- name: Push changes and tags
run: |
git push origin main
git push origin "v${{ steps.bump_version.outputs.new }}"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: "v${{ steps.bump_version.outputs.new }}"
name: "Release v${{ steps.bump_version.outputs.new }}"
body_path: release_body.md
draft: false
prerelease: false
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Summary
run: |
echo "🎉 Release v${{ steps.bump_version.outputs.new }} completed successfully!"
echo ""
echo "📦 Published to PyPI: https://pypi.org/project/mcp-feedback-enhanced/"
echo "🚀 GitHub Release: https://github.com/Minidoracat/mcp-feedback-enhanced/releases/tag/v${{ steps.bump_version.outputs.new }}"
echo "📝 Release notes generated from CHANGELOG files"
echo ""
# 顯示桌面應用狀態
if [ "${{ github.event.inputs.include_desktop }}" = "true" ]; then
echo "🖥️ 桌面應用狀態:"
if [ -d "src/mcp_feedback_enhanced/desktop_release" ] && [ -n "$(ls -A src/mcp_feedback_enhanced/desktop_release 2>/dev/null)" ]; then
echo " ✅ 桌面應用已包含在發佈中"
echo " 📱 支援的平台:"
# 檢查各平台並顯示文件大小
if [ -f "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop.exe" ]; then
size=$(stat -f%z "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop.exe" 2>/dev/null || stat -c%s "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop.exe" 2>/dev/null || echo "unknown")
echo " - ✅ Windows x64 (${size} bytes)"
else
echo " - ❌ Windows x64 (缺失)"
fi
if [ -f "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-intel" ]; then
size=$(stat -f%z "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-intel" 2>/dev/null || stat -c%s "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-intel" 2>/dev/null || echo "unknown")
echo " - ✅ macOS Intel (${size} bytes)"
else
echo " - ❌ macOS Intel (缺失)"
fi
if [ -f "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-arm64" ]; then
size=$(stat -f%z "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-arm64" 2>/dev/null || stat -c%s "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-macos-arm64" 2>/dev/null || echo "unknown")
echo " - ✅ macOS Apple Silicon (${size} bytes)"
else
echo " - ❌ macOS Apple Silicon (缺失)"
fi
if [ -f "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-linux" ]; then
size=$(stat -f%z "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-linux" 2>/dev/null || stat -c%s "src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-linux" 2>/dev/null || echo "unknown")
echo " - ✅ Linux x64 (${size} bytes)"
else
echo " - ❌ Linux x64 (缺失)"
fi
echo " 🔗 構建來源: Run ID ${{ steps.check_desktop.outputs.run_id }}"
else
echo " ⚠️ 桌面應用未包含(可能構建失敗)"
fi
else
echo "🖥️ 桌面應用狀態:⏭️ 已跳過(僅 Web 版本)"
fi
echo ""
echo "✅ Next steps:"
echo " - Check the release on GitHub"
echo " - Verify the package on PyPI"
echo " - Test installation with: uvx mcp-feedback-enhanced@v${{ steps.bump_version.outputs.new }}"
if [ "${{ github.event.inputs.include_desktop }}" = "true" ]; then
echo " - Test desktop mode with: uvx mcp-feedback-enhanced@v${{ steps.bump_version.outputs.new }} test --desktop"
fi
echo ""
echo "📋 Note: Make sure CHANGELOG files are updated for future releases"