| name: 🐳 Build and Push Docker Images | |
| on: | |
| push: | |
| tags: | |
| - v* | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: '手动指定标签版本 (例如: v1.0.0, dev, test, staging)' | |
| required: true | |
| type: string | |
| force_build: | |
| description: '强制构建 (即使标签不存在)' | |
| required: false | |
| type: boolean | |
| default: false | |
| env: | |
| REGISTRY: docker.io | |
| IMAGE_NAME_SERVER: zhuquelab/aig-server | |
| IMAGE_NAME_AGENT: zhuquelab/aig-agent | |
| jobs: | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: 🛒 Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: 🏷️ Validate and setup tag | |
| id: tag-setup | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| # 手动触发时的标签处理 | |
| INPUT_TAG="${{ github.event.inputs.tag }}" | |
| FORCE_BUILD="${{ github.event.inputs.force_build }}" | |
| echo "手动触发构建,指定标签: $INPUT_TAG" | |
| # 简化的标签格式验证 | |
| # 支持更灵活的标签格式 | |
| if [[ "$INPUT_TAG" =~ ^v[0-9]+(\.[0-9]+)*(-[a-zA-Z0-9]+)*(\+[a-zA-Z0-9]+)*$ ]]; then | |
| echo "✅ 检测到语义版本标签: $INPUT_TAG" | |
| TAG_TYPE="semantic" | |
| elif [[ "$INPUT_TAG" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then | |
| echo "✅ 检测到自定义标签: $INPUT_TAG" | |
| TAG_TYPE="custom" | |
| else | |
| echo "⚠️ 警告: 标签格式可能不规范,但将继续构建: $INPUT_TAG" | |
| TAG_TYPE="custom" | |
| fi | |
| # 检查标签是否存在并处理 | |
| if git tag -l | grep -q "^$INPUT_TAG$"; then | |
| echo "✅ 标签 $INPUT_TAG 存在于仓库中" | |
| # 切换到指定标签 | |
| git checkout $INPUT_TAG | |
| elif [ "$TAG_TYPE" = "custom" ]; then | |
| echo "ℹ️ 自定义标签 $INPUT_TAG 不存在于仓库中" | |
| echo "将基于当前分支构建自定义版本镜像" | |
| # 自定义标签默认允许基于当前代码构建 | |
| elif [ "$FORCE_BUILD" = "true" ]; then | |
| echo "⚠️ 警告: 语义版本标签 $INPUT_TAG 不存在,但启用了强制构建" | |
| echo "将基于当前分支构建,但使用指定的标签名称" | |
| else | |
| echo "❌ 错误: 语义版本标签 $INPUT_TAG 不存在于仓库中" | |
| echo "对于语义版本标签,必须先创建标签或启用 'force_build' 选项" | |
| exit 1 | |
| fi | |
| # 设置环境变量供后续步骤使用 | |
| echo "BUILD_TAG=$INPUT_TAG" >> $GITHUB_ENV | |
| echo "IS_MANUAL_BUILD=true" >> $GITHUB_ENV | |
| echo "TAG_TYPE=$TAG_TYPE" >> $GITHUB_ENV | |
| echo "build_tag=$INPUT_TAG" >> $GITHUB_OUTPUT | |
| echo "tag_type=$TAG_TYPE" >> $GITHUB_OUTPUT | |
| else | |
| # 标签推送触发时的处理 | |
| BUILD_TAG=${GITHUB_REF#refs/tags/} | |
| echo "标签推送触发构建: $BUILD_TAG" | |
| echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV | |
| echo "IS_MANUAL_BUILD=false" >> $GITHUB_ENV | |
| echo "TAG_TYPE=semantic" >> $GITHUB_ENV | |
| echo "build_tag=$BUILD_TAG" >> $GITHUB_OUTPUT | |
| echo "tag_type=semantic" >> $GITHUB_OUTPUT | |
| fi | |
| echo "🏗️ 准备构建标签: $BUILD_TAG" | |
| - name: 🔧 Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| - name: 🔑 Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: 🏷️ Extract metadata for Server image | |
| id: meta-server | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_SERVER }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=raw,value=${{ env.BUILD_TAG }} | |
| type=raw,value=latest,enable=${{ (github.event_name == 'push' && github.ref_name != '' && !contains(github.ref_name, '-')) || (env.IS_MANUAL_BUILD == 'true' && env.TAG_TYPE == 'semantic' && !contains(env.BUILD_TAG, '-')) }} | |
| flavor: | | |
| latest=false | |
| - name: 🏷️ Extract metadata for Agent image | |
| id: meta-agent | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_AGENT }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=raw,value=${{ env.BUILD_TAG }} | |
| type=raw,value=latest,enable=${{ (github.event_name == 'push' && github.ref_name != '' && !contains(github.ref_name, '-')) || (env.IS_MANUAL_BUILD == 'true' && env.TAG_TYPE == 'semantic' && !contains(env.BUILD_TAG, '-')) }} | |
| flavor: | | |
| latest=false | |
| - name: 🔍 Debug metadata output | |
| run: | | |
| echo "🏷️ Server image tags:" | |
| echo "${{ steps.meta-server.outputs.tags }}" | |
| echo "" | |
| echo "🏷️ Agent image tags:" | |
| echo "${{ steps.meta-agent.outputs.tags }}" | |
| echo "" | |
| echo "📋 Environment variables:" | |
| echo " BUILD_TAG: ${{ env.BUILD_TAG }}" | |
| echo " IS_MANUAL_BUILD: ${{ env.IS_MANUAL_BUILD }}" | |
| echo " TAG_TYPE: ${{ env.TAG_TYPE }}" | |
| echo " Event name: ${{ github.event_name }}" | |
| echo " Ref: ${{ github.ref }}" | |
| - name: 🐳 Build and push Server image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta-server.outputs.tags }} | |
| labels: ${{ steps.meta-server.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: 🤖 Build and push Agent image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile_Agent | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta-agent.outputs.tags }} | |
| labels: ${{ steps.meta-agent.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: 📊 Image digest | |
| run: | | |
| echo "Server image digest: ${{ steps.build-server.outputs.digest }}" | |
| echo "Agent image digest: ${{ steps.build-agent.outputs.digest }}" | |
| - name: 📋 Build Summary | |
| run: | | |
| echo "🎉 Docker 镜像构建完成!" | |
| echo "" | |
| echo "📋 构建信息:" | |
| echo " 触发方式: ${{ github.event_name }}" | |
| echo " 构建标签: ${{ env.BUILD_TAG }}" | |
| echo " 手动构建: ${{ env.IS_MANUAL_BUILD }}" | |
| if [ "${{ env.IS_MANUAL_BUILD }}" = "true" ]; then | |
| echo " 标签类型: ${{ env.TAG_TYPE }}" | |
| fi | |
| echo "" | |
| echo "🏷️ Server 镜像标签:" | |
| echo "${{ steps.meta-server.outputs.tags }}" | sed 's/^/ - /' | |
| echo "" | |
| echo "🤖 Agent 镜像标签:" | |
| echo "${{ steps.meta-agent.outputs.tags }}" | sed 's/^/ - /' | |
| echo "" | |
| if [ "${{ env.IS_MANUAL_BUILD }}" = "true" ]; then | |
| echo "⚠️ 注意: 这是手动触发的构建" | |
| if [ "${{ env.TAG_TYPE }}" = "custom" ]; then | |
| echo "🔧 自定义版本: 基于当前分支代码构建" | |
| fi | |
| if [ "${{ github.event.inputs.force_build }}" = "true" ]; then | |
| echo "⚠️ 警告: 使用了强制构建选项" | |
| fi | |
| fi | |