name: Build Docker Image on: # 自动触发:push 到 main 分支(纯文档改动跳过) # ⚠️ quirk:git commit --allow-empty 不触发 paths-ignore 过滤的 workflow, # 要强制重新触发必须改一个非 ignore 路径的真实文件(改 build-image.yml 自己最稳) push: branches: [main] paths-ignore: - '**.md' - 'LICENSE' - '.gitignore' - '.dockerignore' # 手动触发:应急通道(重新打包 / 指定自定义 tag) workflow_dispatch: inputs: branch: description: '要打包的分支(仅手动触发生效)' required: true default: 'main' tag: description: '镜像 tag(留空则用 commit short hash)' required: false default: '' # 同分支连续 push 只跑最新的 run,旧 in-progress run 被取消(build + deploy 一起停) concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - name: Checkout target branch uses: actions/checkout@v4 with: ref: ${{ inputs.branch || github.ref_name }} fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: # 钉 v0.13.2(runc 1.1.x)避免 DSM 4.4.x 内核不支持 runc 1.2+ 的 # openat2/fsmount syscall 导致 build 失败 driver-opts: | image=moby/buildkit:v0.13.2 - name: Login to Gitea Container Registry uses: docker/login-action@v3 with: registry: git.zhengchentao.win username: ${{ gitea.actor }} password: ${{ secrets.PACKAGES_TOKEN }} - name: Determine image tag and revision id: meta run: | if [ -n "${{ inputs.tag }}" ]; then IMAGE_TAG="${{ inputs.tag }}" else IMAGE_TAG="$(git rev-parse --short HEAD)" fi echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT echo "full_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "==> Image tag: $IMAGE_TAG" - name: Build and push uses: docker/build-push-action@v5 with: context: . push: true # buildx 每次 CI 起新的 buildkit 实例,layer cache 默认会丢。用 registry # 当跨 CI run 的缓存。 # mode=min:只推最终镜像层引用(默认)。mode=max 会推所有中间层(实测加密 # 机械盘 + Gitea registry 每次 ~4min 还超时,得不偿失)。 # ignore-error=true:万一 cache export 出问题不让 build 标 failure, # 否则 deploy job 会被 skip。 cache-from: type=registry,ref=git.zhengchentao.win/zhengchen.tao/obsidian-mcp:buildcache cache-to: type=registry,ref=git.zhengchentao.win/zhengchen.tao/obsidian-mcp:buildcache,mode=min,ignore-error=true labels: | org.opencontainers.image.source=https://git.zhengchentao.win/zhengchen.tao/obsidian-mcp org.opencontainers.image.revision=${{ steps.meta.outputs.full_sha }} tags: | git.zhengchentao.win/zhengchen.tao/obsidian-mcp:${{ steps.meta.outputs.image_tag }} git.zhengchentao.win/zhengchen.tao/obsidian-mcp:latest - name: Build summary if: always() run: | { echo "## Build Summary" echo "" echo "| 项 | 值 |" echo "|---|---|" echo "| 触发方式 | \`${{ github.event_name }}\` |" echo "| 源分支 | \`${{ inputs.branch || github.ref_name }}\` |" echo "| 源 commit (full) | \`${{ steps.meta.outputs.full_sha }}\` |" echo "| 源 commit (short) | \`${{ steps.meta.outputs.image_tag }}\` |" echo "| 镜像 | \`git.zhengchentao.win/zhengchen.tao/obsidian-mcp:${{ steps.meta.outputs.image_tag }}\` + \`:latest\` |" } >> "$GITHUB_STEP_SUMMARY" deploy: # needs: build 串起来 —— build 失败则 deploy 自动 skip,无需 if 条件 needs: build runs-on: ubuntu-latest steps: # 不再 clone nas-infra:deploy 直接操作 NAS 上 /volume1/docker/compose/obsidian-mcp/。 # 该目录由 gitea-runner 挂载暴露给 runner(host 模式 + bind mount)。 # .env.shared 也在那一层(../.env.shared),不需要再注入凭据。 # nas-infra 的 compose 改动靠 NAS 上手动 `git pull` 同步,不进 CI 链路。 - name: Login to Gitea Container Registry uses: docker/login-action@v3 with: registry: git.zhengchentao.win username: ${{ gitea.actor }} password: ${{ secrets.PACKAGES_TOKEN }} - name: Pull and restart obsidian-mcp run: | set -e cd /volume1/docker/compose/obsidian-mcp docker compose pull docker compose up -d sleep 3 docker compose ps docker compose logs --tail=30 obsidian-mcp