175 lines
8.0 KiB
YAML
175 lines
8.0 KiB
YAML
# ═══════════════════════════════════════════════════════════════
|
||
# Release 工作流 — Tag 触发:构建正式版镜像并推送到 Gitea 镜像仓库
|
||
#
|
||
# 触发条件:push 符合 v* 格式的 tag(如 v1.0.0、v2.1.3-rc1)
|
||
# 镜像标签:
|
||
# v1.2.3 → :1.2.3 + :1.2 + :1 + :latest
|
||
#
|
||
# 前置配置(Gitea → 仓库 → 设置 → Secrets):
|
||
# REGISTRY_TOKEN — 具有 package:write 权限的 Gitea Access Token
|
||
# (注意:Gitea 禁止使用 GITEA_ / GITHUB_ 前缀的 Secret 名称)
|
||
# ═══════════════════════════════════════════════════════════════
|
||
|
||
name: Release — Docker Build & Push
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
|
||
# release 工作流互斥:同时只允许一次 release 跑,避免与 ci.yml 争抢 buildx
|
||
concurrency:
|
||
group: release-build
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
REGISTRY: git.hty1024.com
|
||
|
||
jobs:
|
||
release:
|
||
name: Release Image
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 40
|
||
|
||
steps:
|
||
# ── 1. 检出代码(完整历史,用于生成 changelog)──────────
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
# ── 2. 生成小写镜像名 ────────────────────────────────────
|
||
- name: 生成小写镜像名
|
||
id: image
|
||
run: |
|
||
REPO=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
|
||
echo "name=${{ env.REGISTRY }}/${REPO}" >> $GITHUB_OUTPUT
|
||
# 提取不含 v 前缀的版本号,如 v1.2.3 → 1.2.3
|
||
VERSION="${{ github.ref_name }}"
|
||
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
|
||
echo "镜像名: ${{ env.REGISTRY }}/${REPO} 版本: ${VERSION}"
|
||
|
||
# ── 3. 校验版本号格式(SemVer)───────────────────────────
|
||
- name: 校验版本号格式
|
||
run: |
|
||
VERSION="${{ github.ref_name }}"
|
||
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-].+)?$ ]]; then
|
||
echo "::warning::标签 '$VERSION' 不符合 vX.Y.Z 格式,仍会构建但建议规范版本号"
|
||
else
|
||
echo "版本号格式正确: $VERSION"
|
||
fi
|
||
|
||
# ── 4. 设置 Docker Buildx ────────────────────────────────
|
||
- name: 设置 Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
with:
|
||
driver-opts: |
|
||
network=host
|
||
buildkitd-flags: --debug --oci-worker-gc-keepstorage 5000
|
||
|
||
# ── 5. 登录 Gitea 镜像仓库 ──────────────────────────────
|
||
# logout: false —— 避免 act_runner Post 阶段 "Cannot find module" 报错
|
||
- name: 登录 Gitea 镜像仓库
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.REGISTRY }}
|
||
username: ${{ gitea.actor }}
|
||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||
logout: false
|
||
|
||
# ── 6. 提取镜像元数据 ────────────────────────────────────
|
||
# metadata-action 对 semver tag 会自动生成多级标签:
|
||
# v1.2.3 → :1.2.3、:1.2、:1、:latest
|
||
- name: 提取镜像元数据
|
||
id: meta
|
||
uses: docker/metadata-action@v5
|
||
with:
|
||
images: ${{ steps.image.outputs.name }}
|
||
tags: |
|
||
# semver 完整版本号:1.2.3
|
||
type=semver,pattern={{version}}
|
||
# 主版本.次版本:1.2
|
||
type=semver,pattern={{major}}.{{minor}}
|
||
# 主版本号:1(仅非 0.x 版本)
|
||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
|
||
# 正式 release 同时打 latest
|
||
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }}
|
||
flavor: |
|
||
latest=false
|
||
labels: |
|
||
org.opencontainers.image.title=个人资料库
|
||
org.opencontainers.image.description=个人多媒体资料管理系统
|
||
org.opencontainers.image.vendor=HTY1024
|
||
org.opencontainers.image.version=${{ steps.image.outputs.version }}
|
||
|
||
# ── 7. 构建并推送正式版镜像 ──────────────────────────────
|
||
- name: 构建并推送镜像
|
||
id: build
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: .
|
||
file: ./Dockerfile
|
||
push: true
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
labels: ${{ steps.meta.outputs.labels }}
|
||
provenance: false
|
||
# 复用 CI 构建的缓存层,加速 release 构建
|
||
# mode=min:只导出最终层引用,减小磁盘 I/O 与 registry 带宽
|
||
cache-from: type=registry,ref=${{ steps.image.outputs.name }}:buildcache
|
||
cache-to: type=registry,ref=${{ steps.image.outputs.name }}:buildcache,mode=min
|
||
# 构建参数:写入版本号到镜像内
|
||
build-args: |
|
||
APP_VERSION=${{ steps.image.outputs.version }}
|
||
|
||
# ── 7.5 清理 buildx 缓存 ─────────────────────────────────
|
||
- name: 清理 buildx 构建缓存
|
||
if: always()
|
||
run: |
|
||
docker buildx prune -f --keep-storage 2GB || true
|
||
docker image prune -f || true
|
||
|
||
# ── 8. 生成两次 tag 之间的变更日志 ───────────────────────
|
||
- name: 生成变更日志
|
||
id: changelog
|
||
run: |
|
||
# 获取上一个 tag
|
||
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
||
if [ -n "$PREV_TAG" ]; then
|
||
RANGE="${PREV_TAG}..HEAD"
|
||
echo "上一版本: $PREV_TAG → 当前版本: ${{ github.ref_name }}"
|
||
else
|
||
RANGE="HEAD"
|
||
echo "首次发布"
|
||
fi
|
||
# 收集提交日志
|
||
LOG=$(git log $RANGE --pretty=format:"- %s (%h)" --no-merges 2>/dev/null | head -30)
|
||
# 写入多行输出
|
||
EOF_MARKER=$(dd if=/dev/urandom bs=15 count=1 2>/dev/null | base64)
|
||
echo "log<<${EOF_MARKER}" >> $GITHUB_OUTPUT
|
||
echo "${LOG:-"- 首次发布"}" >> $GITHUB_OUTPUT
|
||
echo "${EOF_MARKER}" >> $GITHUB_OUTPUT
|
||
|
||
# ── 9. 输出发布摘要 ──────────────────────────────────────
|
||
- name: 输出发布摘要
|
||
run: |
|
||
echo "## 🚀 版本发布:${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 版本号 | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 镜像摘要 | \`${{ steps.build.outputs.digest }}\` |" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 提交 SHA | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**推送的镜像标签:**" >> $GITHUB_STEP_SUMMARY
|
||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
|
||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**本次变更:**" >> $GITHUB_STEP_SUMMARY
|
||
echo "${{ steps.changelog.outputs.log }}" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**拉取镜像:**" >> $GITHUB_STEP_SUMMARY
|
||
echo '```bash' >> $GITHUB_STEP_SUMMARY
|
||
echo "docker pull ${{ steps.image.outputs.name }}:${{ steps.image.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||
echo '```' >> $GITHUB_STEP_SUMMARY
|