Release v2.3.0 #63
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push Docker Image | |
| on: | |
| release: | |
| types: | |
| - published # 当通过 GitHub Releases 页面创建 release 时触发 | |
| workflow_dispatch: | |
| inputs: | |
| build_type: | |
| description: '构建类型' | |
| required: true | |
| type: choice | |
| options: | |
| - package-only # 只打包产物 | |
| - package-and-docker # 打包产物 + Docker 镜像 | |
| default: 'package-and-docker' | |
| version: | |
| description: '版本号(例如: v1.0.0)' | |
| required: false | |
| type: string | |
| tag_name: | |
| description: 'Git Tag 名称(留空则使用 version)' | |
| required: false | |
| type: string | |
| jobs: | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # 需要写权限以上传 Assets | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.release.tag_name || github.event.inputs.tag_name || github.event.inputs.version || github.ref }} | |
| - name: Determine build type | |
| id: build_config | |
| run: | | |
| # 确定构建类型 | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| # Release 事件:默认只打包产物(不构建 Docker) | |
| BUILD_TYPE="package-only" | |
| echo "📦 Release 事件:将只打包产物(不构建 Docker)" | |
| else | |
| # workflow_dispatch 事件:使用用户输入 | |
| BUILD_TYPE="${{ github.event.inputs.build_type }}" | |
| echo "🔧 手动触发:构建类型 = ${BUILD_TYPE}" | |
| fi | |
| echo "BUILD_TYPE=${BUILD_TYPE}" >> $GITHUB_OUTPUT | |
| - name: Extract version and check if pre-release | |
| id: extract_version | |
| run: | | |
| # 从不同事件源提取版本号 | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| # Release 事件:从 release tag 中提取 | |
| TAG_NAME="${{ github.event.release.tag_name }}" | |
| IS_PRERELEASE="${{ github.event.release.prerelease }}" | |
| else | |
| # workflow_dispatch 事件:从输入参数中提取 | |
| TAG_NAME="${{ github.event.inputs.tag_name }}" | |
| if [ -z "$TAG_NAME" ]; then | |
| TAG_NAME="${{ github.event.inputs.version }}" | |
| fi | |
| # 如果仍然为空,尝试从 git ref 中提取 | |
| if [ -z "$TAG_NAME" ]; then | |
| TAG_NAME=${GITHUB_REF#refs/tags/} | |
| if [ "$TAG_NAME" = "$GITHUB_REF" ]; then | |
| # 不是 tag,尝试从分支名或 commit SHA 获取 | |
| TAG_NAME=${GITHUB_REF#refs/heads/} | |
| if [ "$TAG_NAME" = "$GITHUB_REF" ]; then | |
| TAG_NAME="dev-$(date +%Y%m%d-%H%M%S)" | |
| echo "⚠️ 未指定版本号,使用临时版本: $TAG_NAME" | |
| fi | |
| fi | |
| fi | |
| IS_PRERELEASE="false" | |
| fi | |
| # 验证版本号格式:v数字.数字.数字[-后缀](例如 v1.0.0, v2.10.102, v1.0.0-beta) | |
| if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]] && [[ ! "$TAG_NAME" =~ ^dev- ]]; then | |
| echo "⚠️ 警告: 版本号格式不符合标准,但仍将继续构建" | |
| echo " 当前版本号: $TAG_NAME" | |
| echo " 标准格式应为: v数字.数字.数字 或 v数字.数字.数字-后缀 (例如: v1.0.0, v1.0.0-beta)" | |
| fi | |
| VERSION=${TAG_NAME#v} # 移除 v 前缀(如果存在) | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| echo "TAG=$TAG_NAME" >> $GITHUB_OUTPUT | |
| echo "IS_PRERELEASE=$IS_PRERELEASE" >> $GITHUB_OUTPUT | |
| if [ "$IS_PRERELEASE" = "true" ]; then | |
| echo "📋 这是 Pre-release: $TAG_NAME" | |
| else | |
| echo "📦 这是正式版本: $TAG_NAME" | |
| fi | |
| - name: Send Telegram notification (build started) | |
| if: steps.extract_version.outputs.IS_PRERELEASE == 'false' && steps.build_config.outputs.BUILD_TYPE == 'package-and-docker' | |
| env: | |
| TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} | |
| TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} | |
| run: | | |
| # 检查必要的环境变量 | |
| if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then | |
| echo "⚠️ Telegram Bot Token 或 Chat ID 未配置,跳过通知" | |
| exit 0 | |
| fi | |
| # 获取构建信息 | |
| TAG="${{ steps.extract_version.outputs.TAG }}" | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| RELEASE_URL="${{ github.event.release.html_url }}" | |
| MESSAGE="🔨 <b>Release 构建中</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> Docker 升级"$'\n'"🔗 <a href=\"${RELEASE_URL}\">查看 Release</a>" | |
| else | |
| WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| MESSAGE="🔨 <b>构建中</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> Docker 升级"$'\n'"🔗 <a href=\"${WORKFLOW_URL}\">查看 Workflow</a>" | |
| fi | |
| # 发送 Telegram 消息(使用 jq 转义 JSON) | |
| curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$(jq -n \ | |
| --arg chat_id "$TELEGRAM_CHAT_ID" \ | |
| --arg text "$MESSAGE" \ | |
| '{chat_id: $chat_id, text: $text, parse_mode: "HTML", disable_web_page_preview: false}')" > /tmp/telegram_response.json | |
| # 检查发送结果 | |
| if [ $? -eq 0 ]; then | |
| RESPONSE=$(cat /tmp/telegram_response.json) | |
| if echo "$RESPONSE" | grep -q '"ok":true'; then | |
| echo "✅ Telegram 通知发送成功" | |
| else | |
| echo "❌ Telegram 通知发送失败: $RESPONSE" | |
| # 通知失败不应该导致整个 job 失败 | |
| exit 0 | |
| fi | |
| else | |
| echo "❌ 发送 Telegram 消息时发生错误" | |
| # 通知失败不应该导致整个 job 失败 | |
| exit 0 | |
| fi | |
| # ============ 编译前后端产物 ============ | |
| - name: Setup JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| - name: Build Backend JAR | |
| run: | | |
| cd backend | |
| chmod +x gradlew | |
| ./gradlew bootJar --no-daemon | |
| echo "✅ 后端构建完成" | |
| ls -lh build/libs/*.jar | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| - name: Build Frontend | |
| env: | |
| VERSION: ${{ steps.extract_version.outputs.VERSION }} | |
| GIT_TAG: ${{ steps.extract_version.outputs.TAG }} | |
| GITHUB_REPO_URL: https://github.com/WrBug/PolyHermes | |
| run: | | |
| cd frontend | |
| npm ci | |
| npm run build | |
| echo "✅ 前端构建完成" | |
| echo "📦 版本信息: VERSION=${{ steps.extract_version.outputs.VERSION }}, GIT_TAG=${{ steps.extract_version.outputs.TAG }}" | |
| du -sh dist/ | |
| # ============ 打包更新包 ============ | |
| - name: Create Update Package | |
| run: | | |
| echo "📦 开始打包更新包..." | |
| # 创建目录结构 | |
| mkdir -p update-package/backend | |
| mkdir -p update-package/frontend | |
| # 复制后端 JAR | |
| cp backend/build/libs/*.jar update-package/backend/polyhermes.jar | |
| echo "✅ 后端 JAR 已复制" | |
| # 复制前端产物 | |
| cp -r frontend/dist/* update-package/frontend/ | |
| echo "✅ 前端文件已复制" | |
| # 创建版本信息文件 | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| RELEASE_NOTES=$(echo '${{ github.event.release.body }}' | jq -Rs .) | |
| else | |
| RELEASE_NOTES="\"手动构建 - workflow_dispatch\"" | |
| fi | |
| cat > update-package/version.json <<EOF | |
| { | |
| "version": "${{ steps.extract_version.outputs.VERSION }}", | |
| "tag": "${{ steps.extract_version.outputs.TAG }}", | |
| "buildTime": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", | |
| "releaseNotes": ${RELEASE_NOTES} | |
| } | |
| EOF | |
| echo "✅ 版本信息已创建" | |
| # 打包成 tar.gz | |
| cd update-package | |
| tar -czf ../polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz . | |
| cd .. | |
| echo "✅ 打包完成: polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz" | |
| ls -lh polyhermes-*.tar.gz | |
| - name: Calculate Checksum | |
| id: checksum | |
| run: | | |
| FILE="polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz" | |
| CHECKSUM=$(sha256sum "$FILE" | awk '{print $1}') | |
| echo "CHECKSUM=$CHECKSUM" >> $GITHUB_OUTPUT | |
| echo "✅ SHA256: $CHECKSUM" | |
| echo "$CHECKSUM $FILE" > checksums.txt | |
| - name: Upload Update Package to Release | |
| if: github.event_name == 'release' | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| upload_url: ${{ github.event.release.upload_url }} | |
| asset_path: ./polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz | |
| asset_name: polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz | |
| asset_content_type: application/gzip | |
| - name: Upload Checksums to Release | |
| if: github.event_name == 'release' | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| upload_url: ${{ github.event.release.upload_url }} | |
| asset_path: ./checksums.txt | |
| asset_name: checksums.txt | |
| asset_content_type: text/plain | |
| - name: Upload Update Package as Artifact | |
| if: github.event_name == 'workflow_dispatch' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: polyhermes-${{ steps.extract_version.outputs.TAG }}-update | |
| path: | | |
| polyhermes-${{ steps.extract_version.outputs.TAG }}-update.tar.gz | |
| checksums.txt | |
| retention-days: 30 | |
| - name: Set up Docker Buildx | |
| if: steps.build_config.outputs.BUILD_TYPE == 'package-and-docker' | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| # 启用多架构构建支持 | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Log in to Docker Hub | |
| if: steps.build_config.outputs.BUILD_TYPE == 'package-and-docker' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Prepare Docker build context | |
| if: steps.build_config.outputs.BUILD_TYPE == 'package-and-docker' | |
| run: | | |
| echo "📦 准备 Docker 构建上下文..." | |
| # 确保构建产物存在且可访问 | |
| if [ ! -d "frontend/dist" ]; then | |
| echo "❌ 错误:frontend/dist 不存在" | |
| exit 1 | |
| fi | |
| if [ ! -d "backend/build/libs" ] || [ -z "$(ls -A backend/build/libs/*.jar 2>/dev/null)" ]; then | |
| echo "❌ 错误:backend/build/libs/*.jar 不存在" | |
| exit 1 | |
| fi | |
| echo "✅ 构建产物已准备好" | |
| ls -lh frontend/dist/ | head -5 | |
| ls -lh backend/build/libs/*.jar | |
| - name: Build and push Docker image | |
| if: steps.build_config.outputs.BUILD_TYPE == 'package-and-docker' | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| push: true | |
| # 多架构构建:支持 amd64 和 arm64 | |
| platforms: linux/amd64,linux/arm64 | |
| tags: | | |
| wrbug/polyhermes:${{ steps.extract_version.outputs.TAG }} | |
| ${{ steps.extract_version.outputs.IS_PRERELEASE == 'false' && 'wrbug/polyhermes:latest' || '' }} | |
| build-args: | | |
| BUILD_IN_DOCKER=false | |
| VERSION=${{ steps.extract_version.outputs.VERSION }} | |
| GIT_TAG=${{ steps.extract_version.outputs.TAG }} | |
| GITHUB_REPO_URL=https://github.com/WrBug/PolyHermes | |
| cache-from: type=registry,ref=wrbug/polyhermes:latest | |
| cache-to: type=inline | |
| - name: Skip Docker build notice | |
| if: steps.build_config.outputs.BUILD_TYPE == 'package-only' | |
| run: | | |
| echo "⏭️ 跳过 Docker 镜像构建(构建类型:package-only)" | |
| echo "✅ 仅打包产物已完成" | |
| - name: Send Telegram notification | |
| if: steps.extract_version.outputs.IS_PRERELEASE == 'false' | |
| env: | |
| TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} | |
| TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} | |
| run: | | |
| # 检查必要的环境变量 | |
| if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then | |
| echo "⚠️ Telegram Bot Token 或 Chat ID 未配置,跳过通知" | |
| exit 0 | |
| fi | |
| # 获取构建信息 | |
| VERSION="${{ steps.extract_version.outputs.VERSION }}" | |
| TAG="${{ steps.extract_version.outputs.TAG }}" | |
| BUILD_TYPE="${{ steps.build_config.outputs.BUILD_TYPE }}" | |
| # 构建消息内容(仅包含关键信息) | |
| DEPLOY_DOC_URL="https://github.com/WrBug/PolyHermes/blob/main/docs/zh/DEPLOYMENT.md" | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| RELEASE_URL="${{ github.event.release.html_url }}" | |
| if [ "$BUILD_TYPE" = "package-and-docker" ]; then | |
| MESSAGE="✅ <b>Release 构建成功</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> Docker 升级"$'\n'"🔗 <a href=\"${RELEASE_URL}\">查看 Release</a>"$'\n'"📚 <a href=\"${DEPLOY_DOC_URL}\">Docker 部署文档</a>" | |
| else | |
| MESSAGE="✅ <b>Release 打包成功</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> 在线升级"$'\n'"🔗 <a href=\"${RELEASE_URL}\">查看 Release</a>"$'\n'"📍 <b>升级路径:</b> 系统管理 → 概览 → 检查更新" | |
| fi | |
| else | |
| WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| if [ "$BUILD_TYPE" = "package-and-docker" ]; then | |
| MESSAGE="✅ <b>构建成功</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> Docker 升级"$'\n'"🔗 <a href=\"${WORKFLOW_URL}\">查看 Workflow</a>"$'\n'"📚 <a href=\"${DEPLOY_DOC_URL}\">Docker 部署文档</a>" | |
| else | |
| MESSAGE="✅ <b>打包成功</b>"$'\n'$'\n'"🏷️ <b>Tag:</b> <code>${TAG}</code>"$'\n'"🔧 <b>构建类型:</b> 在线升级"$'\n'"🔗 <a href=\"${WORKFLOW_URL}\">查看 Workflow</a>"$'\n'"📍 <b>升级路径:</b> 系统管理 → 概览 → 检查更新" | |
| fi | |
| fi | |
| # 发送 Telegram 消息(使用 jq 转义 JSON) | |
| curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$(jq -n \ | |
| --arg chat_id "$TELEGRAM_CHAT_ID" \ | |
| --arg text "$MESSAGE" \ | |
| '{chat_id: $chat_id, text: $text, parse_mode: "HTML", disable_web_page_preview: false}')" > /tmp/telegram_response.json | |
| # 检查发送结果 | |
| if [ $? -eq 0 ]; then | |
| RESPONSE=$(cat /tmp/telegram_response.json) | |
| if echo "$RESPONSE" | grep -q '"ok":true'; then | |
| echo "✅ Telegram 通知发送成功" | |
| else | |
| echo "❌ Telegram 通知发送失败: $RESPONSE" | |
| # 构建成功,通知失败不应该导致整个 job 失败 | |
| exit 0 | |
| fi | |
| else | |
| echo "❌ 发送 Telegram 消息时发生错误" | |
| # 构建成功,通知失败不应该导致整个 job 失败 | |
| exit 0 | |
| fi |