name: AuTo Docker Image on: push: branches: [main] # 保留手动触发作为备选 workflow_dispatch: inputs: version_type: description: '版本递增类型' required: true default: 'patch' type: choice options: - patch # 0.0.x - minor # 0.x.0 - major # x.0.0 permissions: contents: write # 需要写入权限来更新版本文件 packages: write jobs: version-and-publish: runs-on: ubuntu-latest outputs: new_version: ${{ steps.bump_version.outputs.new_version }} tag: ${{ steps.bump_version.outputs.tag }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # 获取完整历史以便版本计算 token: ${{ secrets.GITHUB_TOKEN }} # 1. 获取或初始化版本号 - name: Get current version id: get_version run: | # 从文件读取版本号,或使用默认值 if [ -f VERSION ]; then CURRENT_VERSION=$(cat VERSION) else CURRENT_VERSION="0.0.0" echo $CURRENT_VERSION > VERSION fi echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT # 分离版本组成部分 MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) PATCH=$(echo $CURRENT_VERSION | cut -d. -f3) echo "major=$MAJOR" >> $GITHUB_OUTPUT echo "minor=$MINOR" >> $GITHUB_OUTPUT echo "patch=$PATCH" >> $GITHUB_OUTPUT # 2. 计算新版本号 - name: Bump version id: bump_version run: | MAJOR=${{ steps.get_version.outputs.major }} MINOR=${{ steps.get_version.outputs.minor }} PATCH=${{ steps.get_version.outputs.patch }} # 手动触发时根据选择递增 if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then TYPE="${{ github.event.inputs.version_type }}" if [ "$TYPE" = "major" ]; then MAJOR=$((MAJOR + 1)) MINOR=0 PATCH=0 elif [ "$TYPE" = "minor" ]; then MINOR=$((MINOR + 1)) PATCH=0 else # patch PATCH=$((PATCH + 1)) fi else # 自动触发时默认 patch 递增 PATCH=$((PATCH + 1)) fi NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT echo "tag=MMTL-v${NEW_VERSION}" >> $GITHUB_OUTPUT echo "tag=mmtl-v${NEW_VERSION}" >> $GITHUB_OUTPUT # 3. 更新 VERSION 文件 - name: Update version file run: | echo "${{ steps.bump_version.outputs.new_version }}" > VERSION # 如果存在 go.mod,也更新其中的版本(可选) # if [ -f go.mod ]; then # sed -i "s/^version .*/version ${{ steps.bump_version.outputs.new_version }}/" go.mod # fi # 4. 提交版本变更 - name: Commit version bump run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add VERSION git commit -m "chore: bump version to ${{ steps.bump_version.outputs.new_version }} [skip ci]" git push # 5. 创建 Git Tag - name: Create and push tag run: | TAG="${{ steps.bump_version.outputs.tag }}" git tag $TAG git push origin $TAG # 6. 设置 Docker QEMU 和 Buildx - uses: docker/setup-qemu-action@v3 - uses: docker/setup-buildx-action@v3 # 7. 登录 GHCR - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # 8. 提取镜像元数据 - name: Extract image metadata id: meta uses: docker/metadata-action@v5 with: images: ghcr.io/${{ github.repository_owner }}/mmtl tags: | type=raw,value=latest type=raw,value=${{ steps.bump_version.outputs.tag }} type=raw,value=${{ steps.bump_version.outputs.new_version }} # 9. 构建并推送 - name: Build & push uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 push: true provenance: false sbom: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ steps.bump_version.outputs.new_version }} cache-from: type=gha cache-to: type=gha,mode=max # 单文件可执行构建:把前端打包进二进制(go:embed),交叉编译 Windows / # Linux / macOS 的 amd64 / arm64 产物,作为 GitHub Release 附件发布。 build-frontend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: web/package-lock.json - name: Install working-directory: web run: npm ci - name: Build SPA working-directory: web run: npm run build - name: Upload web/dist uses: actions/upload-artifact@v4 with: name: web-dist path: web/dist retention-days: 1 # 先创建(幂等)空的 GitHub Release,供后续 build-binaries 并行上传附件, # 也避免矩阵各 job 并发 upload 时 release 尚不存在而互相竞争。 publish-create-release: needs: [version-and-publish] runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - name: Create release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ needs.version-and-publish.outputs.tag }} run: | set -eux # tag 已由 version-and-publish 推送;若 release 已存在则忽略(--verify-tag 幂等) gh release create "$RELEASE_TAG" \ --title "MMTL ${{ needs.version-and-publish.outputs.new_version }}" \ --notes "自动化发布 ${{ needs.version-and-publish.outputs.new_version }}" \ --verify-tag --latest || true build-binaries: needs: [version-and-publish, build-frontend, publish-create-release] runs-on: ubuntu-latest permissions: contents: write strategy: fail-fast: false matrix: include: - goos: linux goarch: amd64 ext: "" - goos: linux goarch: arm64 ext: "" - goos: windows goarch: amd64 ext: .exe - goos: windows goarch: arm64 ext: .exe - goos: darwin goarch: amd64 ext: "" - goos: darwin goarch: arm64 ext: "" steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.25' cache: true - name: Download web/dist uses: actions/download-artifact@v4 with: name: web-dist path: web/dist - name: Build binary run: | CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \ go build -trimpath -ldflags="-s -w -X main.version=${{ needs.version-and-publish.outputs.tag }}" \ -o "dist/mmtl-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}" ./cmd/server - name: Package run: | mkdir -p package/mmtl cp "dist/mmtl-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}" package/mmtl/mmtl${{ matrix.ext }} cp README.md package/mmtl/ 2>/dev/null || true if [ "${{ matrix.goos }}" = "windows" ]; then (cd package && zip -r "../mmtl_${{ matrix.goos }}_${{ matrix.goarch }}.zip" mmtl) else tar -czf "mmtl_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz" -C package mmtl fi - name: Upload to GitHub Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ needs.version-and-publish.outputs.tag }} run: | set -eux PKG="mmtl_${{ matrix.goos }}_${{ matrix.goarch }}.zip" TAR="mmtl_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz" # 并发上传到同一 release 各自文件,--clobber 幂等覆盖 if [ -f "$PKG" ]; then for i in 1 2 3; do gh release upload "$RELEASE_TAG" "$PKG" --clobber && break || sleep 5; done fi if [ -f "$TAR" ]; then for i in 1 2 3; do gh release upload "$RELEASE_TAG" "$TAR" --clobber && break || sleep 5; done fi