docker-publish.yml
1 name: 🐳 Build and Push Docker Images 2 3 on: 4 push: 5 tags: 6 - v* 7 workflow_dispatch: 8 inputs: 9 tag: 10 description: '手动指定标签版本 (例如: v1.0.0, dev, test, staging)' 11 required: true 12 type: string 13 force_build: 14 description: '强制构建 (即使标签不存在)' 15 required: false 16 type: boolean 17 default: false 18 19 env: 20 REGISTRY: docker.io 21 IMAGE_NAME_SERVER: zhuquelab/aig-server 22 IMAGE_NAME_AGENT: zhuquelab/aig-agent 23 24 jobs: 25 build-and-push: 26 runs-on: ubuntu-latest 27 permissions: 28 contents: read 29 packages: write 30 31 steps: 32 - name: 🛒 Checkout repository 33 uses: actions/checkout@v4 34 with: 35 fetch-depth: 0 36 37 - name: 🏷️ Validate and setup tag 38 id: tag-setup 39 run: | 40 if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then 41 # 手动触发时的标签处理 42 INPUT_TAG="${{ github.event.inputs.tag }}" 43 FORCE_BUILD="${{ github.event.inputs.force_build }}" 44 45 echo "手动触发构建,指定标签: $INPUT_TAG" 46 47 # 简化的标签格式验证 48 # 支持更灵活的标签格式 49 if [[ "$INPUT_TAG" =~ ^v[0-9]+(\.[0-9]+)*(-[a-zA-Z0-9]+)*(\+[a-zA-Z0-9]+)*$ ]]; then 50 echo "✅ 检测到语义版本标签: $INPUT_TAG" 51 TAG_TYPE="semantic" 52 elif [[ "$INPUT_TAG" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then 53 echo "✅ 检测到自定义标签: $INPUT_TAG" 54 TAG_TYPE="custom" 55 else 56 echo "⚠️ 警告: 标签格式可能不规范,但将继续构建: $INPUT_TAG" 57 TAG_TYPE="custom" 58 fi 59 60 # 检查标签是否存在并处理 61 if git tag -l | grep -q "^$INPUT_TAG$"; then 62 echo "✅ 标签 $INPUT_TAG 存在于仓库中" 63 # 切换到指定标签 64 git checkout $INPUT_TAG 65 elif [ "$TAG_TYPE" = "custom" ]; then 66 echo "ℹ️ 自定义标签 $INPUT_TAG 不存在于仓库中" 67 echo "将基于当前分支构建自定义版本镜像" 68 # 自定义标签默认允许基于当前代码构建 69 elif [ "$FORCE_BUILD" = "true" ]; then 70 echo "⚠️ 警告: 语义版本标签 $INPUT_TAG 不存在,但启用了强制构建" 71 echo "将基于当前分支构建,但使用指定的标签名称" 72 else 73 echo "❌ 错误: 语义版本标签 $INPUT_TAG 不存在于仓库中" 74 echo "对于语义版本标签,必须先创建标签或启用 'force_build' 选项" 75 exit 1 76 fi 77 78 # 设置环境变量供后续步骤使用 79 echo "BUILD_TAG=$INPUT_TAG" >> $GITHUB_ENV 80 echo "IS_MANUAL_BUILD=true" >> $GITHUB_ENV 81 echo "TAG_TYPE=$TAG_TYPE" >> $GITHUB_ENV 82 echo "build_tag=$INPUT_TAG" >> $GITHUB_OUTPUT 83 echo "tag_type=$TAG_TYPE" >> $GITHUB_OUTPUT 84 85 else 86 # 标签推送触发时的处理 87 BUILD_TAG=${GITHUB_REF#refs/tags/} 88 echo "标签推送触发构建: $BUILD_TAG" 89 echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV 90 echo "IS_MANUAL_BUILD=false" >> $GITHUB_ENV 91 echo "TAG_TYPE=semantic" >> $GITHUB_ENV 92 echo "build_tag=$BUILD_TAG" >> $GITHUB_OUTPUT 93 echo "tag_type=semantic" >> $GITHUB_OUTPUT 94 fi 95 96 echo "🏗️ 准备构建标签: $BUILD_TAG" 97 98 - name: 🔧 Set up Docker Buildx 99 uses: docker/setup-buildx-action@v3 100 with: 101 platforms: linux/amd64,linux/arm64 102 103 - name: 🔑 Log in to Docker Hub 104 uses: docker/login-action@v3 105 with: 106 registry: ${{ env.REGISTRY }} 107 username: ${{ secrets.DOCKERHUB_USERNAME }} 108 password: ${{ secrets.DOCKERHUB_TOKEN }} 109 110 - name: 🏷️ Extract metadata for Server image 111 id: meta-server 112 uses: docker/metadata-action@v5 113 with: 114 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_SERVER }} 115 tags: | 116 type=ref,event=branch 117 type=semver,pattern={{version}} 118 type=raw,value=${{ env.BUILD_TAG }} 119 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, '-')) }} 120 flavor: | 121 latest=false 122 123 - name: 🏷️ Extract metadata for Agent image 124 id: meta-agent 125 uses: docker/metadata-action@v5 126 with: 127 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_AGENT }} 128 tags: | 129 type=ref,event=branch 130 type=semver,pattern={{version}} 131 type=raw,value=${{ env.BUILD_TAG }} 132 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, '-')) }} 133 flavor: | 134 latest=false 135 136 - name: 🔍 Debug metadata output 137 run: | 138 echo "🏷️ Server image tags:" 139 echo "${{ steps.meta-server.outputs.tags }}" 140 echo "" 141 echo "🏷️ Agent image tags:" 142 echo "${{ steps.meta-agent.outputs.tags }}" 143 echo "" 144 echo "📋 Environment variables:" 145 echo " BUILD_TAG: ${{ env.BUILD_TAG }}" 146 echo " IS_MANUAL_BUILD: ${{ env.IS_MANUAL_BUILD }}" 147 echo " TAG_TYPE: ${{ env.TAG_TYPE }}" 148 echo " Event name: ${{ github.event_name }}" 149 echo " Ref: ${{ github.ref }}" 150 151 - name: 🐳 Build and push Server image 152 uses: docker/build-push-action@v5 153 with: 154 context: . 155 file: ./Dockerfile 156 platforms: linux/amd64,linux/arm64 157 push: true 158 tags: ${{ steps.meta-server.outputs.tags }} 159 labels: ${{ steps.meta-server.outputs.labels }} 160 cache-from: type=gha 161 cache-to: type=gha,mode=max 162 163 - name: 🤖 Build and push Agent image 164 uses: docker/build-push-action@v5 165 with: 166 context: . 167 file: ./Dockerfile_Agent 168 platforms: linux/amd64,linux/arm64 169 push: true 170 tags: ${{ steps.meta-agent.outputs.tags }} 171 labels: ${{ steps.meta-agent.outputs.labels }} 172 cache-from: type=gha 173 cache-to: type=gha,mode=max 174 175 - name: 📊 Image digest 176 run: | 177 echo "Server image digest: ${{ steps.build-server.outputs.digest }}" 178 echo "Agent image digest: ${{ steps.build-agent.outputs.digest }}" 179 180 - name: 📋 Build Summary 181 run: | 182 echo "🎉 Docker 镜像构建完成!" 183 echo "" 184 echo "📋 构建信息:" 185 echo " 触发方式: ${{ github.event_name }}" 186 echo " 构建标签: ${{ env.BUILD_TAG }}" 187 echo " 手动构建: ${{ env.IS_MANUAL_BUILD }}" 188 if [ "${{ env.IS_MANUAL_BUILD }}" = "true" ]; then 189 echo " 标签类型: ${{ env.TAG_TYPE }}" 190 fi 191 echo "" 192 echo "🏷️ Server 镜像标签:" 193 echo "${{ steps.meta-server.outputs.tags }}" | sed 's/^/ - /' 194 echo "" 195 echo "🤖 Agent 镜像标签:" 196 echo "${{ steps.meta-agent.outputs.tags }}" | sed 's/^/ - /' 197 echo "" 198 if [ "${{ env.IS_MANUAL_BUILD }}" = "true" ]; then 199 echo "⚠️ 注意: 这是手动触发的构建" 200 if [ "${{ env.TAG_TYPE }}" = "custom" ]; then 201 echo "🔧 自定义版本: 基于当前分支代码构建" 202 fi 203 if [ "${{ github.event.inputs.force_build }}" = "true" ]; then 204 echo "⚠️ 警告: 使用了强制构建选项" 205 fi 206 fi