build(release): 迁移语义化版本打标流程

- 新增 semantic-release 配置并固定 release rules 与 v 前缀 tag 格式

- 重构 auto-tag workflow 为 main 上的真实打标与 workflow_dispatch dry-run 双入口

- 保留现有 publish workflow 并补充 ai-plan 跟踪与验证记录
This commit is contained in:
gewuyou 2026-04-26 09:42:18 +08:00
parent 0c7552e629
commit b194238385
5 changed files with 247 additions and 38 deletions

View File

@ -1,4 +1,4 @@
name: Auto Increment Version and Tag name: Semantic Release Version and Tag
on: on:
workflow_run: workflow_run:
@ -9,28 +9,17 @@ on:
- main - main
workflow_dispatch: workflow_dispatch:
concurrency: concurrency:
group: auto-tag-main group: semantic-release-main
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
auto-tag: dry-run:
if: > if: >
( github.event_name == 'workflow_dispatch' &&
github.event_name == 'workflow_run' && github.ref == 'refs/heads/main'
github.event.workflow_run.conclusion == 'success' &&
contains(github.event.workflow_run.head_commit.message, '[release ci]')
)
||
(
github.event_name == 'workflow_dispatch' &&
github.ref == 'refs/heads/main'
)
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: read
outputs:
tagged: ${{ steps.create_tag.outcome == 'success' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v6 uses: actions/checkout@v6
@ -38,29 +27,64 @@ jobs:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Get next version # 手动触发仅用于验证 semantic-release 的版本推导结果,不会真正推送 tag。
id: version - name: Semantic release dry-run
run: | id: semantic_release
LATEST_TAG=$(git tag --list "v*" --sort=-v:refname | head -n 1) uses: cycjimmy/semantic-release-action@v6
LATEST_TAG=${LATEST_TAG:-v0.0.0} with:
VERSION=${LATEST_TAG#v} dry_run: true
IFS=. read MAJOR MINOR PATCH <<< "$VERSION" ci: false
PATCH=$((PATCH+1))
echo "new_tag=v$MAJOR.$MINOR.$PATCH" >> $GITHUB_OUTPUT
- name: Create tag
env: env:
PAT: ${{ secrets.PAT_TOKEN }} GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ steps.version.outputs.new_tag }}
- name: Show dry-run result
run: | run: |
set -e echo "published=${{ steps.semantic_release.outputs.new_release_published }}"
git config user.name "GitHub Action" echo "last_tag=${{ steps.semantic_release.outputs.last_release_git_tag }}"
git config user.email "action@github.com" echo "next_version=${{ steps.semantic_release.outputs.new_release_version }}"
echo "next_tag=${{ steps.semantic_release.outputs.new_release_git_tag }}"
if git show-ref --tags --verify --quiet "refs/tags/$TAG"; then release-tag:
echo "Tag $TAG already exists, skipping" if: >
exit 0 github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
contains(github.event.workflow_run.head_commit.message, '[release ci]')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.event.workflow_run.head_branch }}
- name: Validate PAT token
run: |
if [ -z "${PAT_TOKEN}" ]; then
echo "::error::PAT_TOKEN is required because a tag created with GITHUB_TOKEN will not trigger publish.yml."
exit 1
fi fi
env:
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
git tag -a "$TAG" -m "Auto tag $TAG" # 真实 workflow_run 负责按 Conventional Commits 计算版本并推送 tag。
git push "https://x-access-token:${PAT}@github.com/${{ github.repository }}.git" "$TAG" - name: Semantic release
id: semantic_release
uses: cycjimmy/semantic-release-action@v6
env:
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
- name: Show release result
env:
PUBLISHED: ${{ steps.semantic_release.outputs.new_release_published }}
LAST_TAG: ${{ steps.semantic_release.outputs.last_release_git_tag }}
NEXT_VERSION: ${{ steps.semantic_release.outputs.new_release_version }}
NEXT_TAG: ${{ steps.semantic_release.outputs.new_release_git_tag }}
run: |
echo "published=${PUBLISHED}"
echo "last_tag=${LAST_TAG}"
echo "next_version=${NEXT_VERSION}"
echo "next_tag=${NEXT_TAG}"

72
.releaserc.json Normal file
View File

@ -0,0 +1,72 @@
{
"branches": [
"main"
],
"tagFormat": "v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"releaseRules": [
{
"type": "feat",
"release": "minor"
},
{
"type": "fix",
"release": "patch"
},
{
"type": "perf",
"release": "patch"
},
{
"type": "refactor",
"release": "patch"
},
{
"type": "docs",
"release": false
},
{
"type": "test",
"release": false
},
{
"type": "chore",
"release": false
},
{
"type": "build",
"release": false
},
{
"type": "ci",
"release": false
},
{
"type": "style",
"release": false
}
],
"parserOpts": {
"noteKeywords": [
"BREAKING CHANGE",
"BREAKING CHANGES"
]
}
}
],
[
"@semantic-release/release-notes-generator",
{
"parserOpts": {
"noteKeywords": [
"BREAKING CHANGE",
"BREAKING CHANGES"
]
}
}
]
]
}

View File

@ -43,6 +43,10 @@ help the current worktree land on the right recovery documents without scanning
- Purpose: continue the data repository persistence hardening plus the settings / serialization follow-up backlog. - Purpose: continue the data repository persistence hardening plus the settings / serialization follow-up backlog.
- Tracking: `ai-plan/public/data-repository-persistence/todos/data-repository-persistence-tracking.md` - Tracking: `ai-plan/public/data-repository-persistence/todos/data-repository-persistence-tracking.md`
- Trace: `ai-plan/public/data-repository-persistence/traces/data-repository-persistence-trace.md` - Trace: `ai-plan/public/data-repository-persistence/traces/data-repository-persistence-trace.md`
- `semantic-release-versioning`
- Purpose: migrate release version calculation from fixed patch bumps to semantic-release while keeping the existing tag-driven NuGet publish flow.
- Tracking: `ai-plan/public/semantic-release-versioning/todos/semantic-release-versioning-tracking.md`
- Trace: `ai-plan/public/semantic-release-versioning/traces/semantic-release-versioning-trace.md`
## Worktree To Active Topic Map ## Worktree To Active Topic Map
@ -63,6 +67,9 @@ help the current worktree land on the right recovery documents without scanning
- Branch: `feat/data-repository-persistence` - Branch: `feat/data-repository-persistence`
- Worktree hint: `GFramework-data-repository-persistence` - Worktree hint: `GFramework-data-repository-persistence`
- Priority 1: `data-repository-persistence` - Priority 1: `data-repository-persistence`
- Branch: `feat/semantic-release-versioning`
- Worktree hint: `GFramework`
- Priority 1: `semantic-release-versioning`
- Branch: `docs/sdk-update-documentation` - Branch: `docs/sdk-update-documentation`
- Worktree hint: `GFramework-update-documentation` - Worktree hint: `GFramework-update-documentation`
- Priority 1: `documentation-full-coverage-governance` - Priority 1: `documentation-full-coverage-governance`

View File

@ -0,0 +1,67 @@
# Semantic Release 版本迁移跟踪
## 目标
将版本管理从固定 `patch + 1` 的自动打 tag 迁移到 `semantic-release`,同时保留现有 `.github/workflows/publish.yml`
的 tag 触发打包、NuGet 发布、GitHub Packages 发布和 GitHub Release 流程。
- 用 `cycjimmy/semantic-release-action` 替换 `auto-tag.yml` 的版本判断和打 tag 逻辑
- 保留 `publish.yml` 的现有发布实现,不重写 NuGet 流程
- 避免 `semantic-release``publish.yml` 重复创建 GitHub Release
- 将版本规则固定为 `feat -> minor``fix/perf/refactor -> patch``BREAKING CHANGE``! -> major`
- 为手动 `workflow_dispatch` 保留 dry-run 验证入口,先验证最近提交会算出什么版本
## 当前恢复点
- 恢复点编号:`SEMREL-RP-001`
- 当前阶段:`Phase 1`
- 当前焦点:
- 增加 `.releaserc.json`,仅启用版本分析与 release notes 生成,不启用 GitHub Release 发布插件
- 将 `auto-tag.yml` 改成 `workflow_run` 真正打 tag、`workflow_dispatch` 只做 dry-run 的双入口
- 明确 `PAT_TOKEN``GITHUB_TOKEN` 的职责边界,确保 tag 继续触发 `publish.yml`
### 已知风险
- `GITHUB_TOKEN` 推送 tag 不会再触发另一个 workflow真实发布仍需要 `PAT_TOKEN`
- `semantic-release` 的版本判断完全依赖 Conventional Commits不规范提交会直接影响版本计算
- 当前仓库本地 `dotnet clean/build` 仍受 WSL fallback NuGet 路径影响,验证时需要继续采用已知可用的直接构建命令
## 已完成
- 已确认当前版本入口为 `.github/workflows/auto-tag.yml`,现状始终执行 `PATCH + 1`
- 已确认当前 `.github/workflows/publish.yml` 由 tag 触发,并负责 `.nupkg` 打包、发布和 GitHub Release
- 已确认最新 tag 为 `v0.0.222`
- 已确认 `v0.0.222..HEAD` 之间存在 `feat(...)` 提交,按目标规则首次 dry-run 预期版本应为 `v0.1.0`
- 已新增 `.releaserc.json`,仅保留 `@semantic-release/commit-analyzer`
`@semantic-release/release-notes-generator`,避免 `semantic-release` 直接创建 GitHub Release
- 已将 `.github/workflows/auto-tag.yml` 重写为:
- `workflow_run``main` 上、CI 成功且提交消息包含 `[release ci]` 时执行真实打 tag
- `workflow_dispatch` 只执行 dry-run输出 `last_tag``next_version``next_tag`
- 已明确真实打 tag 仍使用 `PAT_TOKEN`,因为 `GITHUB_TOKEN` 推送的 tag 不会继续触发 `publish.yml`
## 验证
- `git describe --tags --abbrev=0`
- 结果:通过
- 备注:当前最新 tag 为 `v0.0.222`
- `git log --pretty=format:%h%x09%s v0.0.222..HEAD`
- 结果:通过
- 备注:最近版本窗口内存在多条 `feat(...)`,后续 dry-run 预期应提升 `minor`
- `dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`
- 结果:通过
- 备注:`GFramework.Core.Abstractions``GFramework.Cqrs.Abstractions` Release 构建通过,`0 warning / 0 error`
- `npx --yes semantic-release --dry-run --no-ci`
- 结果:受阻
- 备注:当前工作树的本地 tag 历史在 `git fetch --tags` 阶段出现 `would clobber existing tag` 冲突,不能直接作为 dry-run 环境
- `git clone --branch main --single-branch git@github.com:GeWuYou/GFramework.git /tmp/gframework-semrel-dryrun`
- 结果:通过
- 备注:已建立干净临时克隆用于 dry-run 验证
- `npx --yes semantic-release --dry-run --no-ci`(在 `/tmp/gframework-semrel-dryrun`
- 结果:通过
- 备注dry-run 成功识别 `v0.0.222` 为最新 release并分析 `269` 个提交;按当前规则会提升到下一次 `minor` 发布,预期 tag 为 `v0.1.0`
## 下一步
1. 复核 `workflow_dispatch` dry-run 输出格式是否还需要额外收窄或增加说明
2. 评估是否要把 `workflow_run``[release ci]` 门闸改成更显式的 PR label 或 manual approval
3. 若本轮验证通过,按仓库要求创建提交并等待你审阅发版流程细节

View File

@ -0,0 +1,39 @@
# Semantic Release 版本迁移追踪
## 2026-04-26
### 阶段方案落地准备SEMREL-RP-001
- 读取当前 `auto-tag.yml``publish.yml`,确认最小侵入改法应只替换版本判断与打 tag保留 tag 触发发布链
- 核对最近 tag 与提交历史:
- 最新 tag 为 `v0.0.222`
- `v0.0.222..HEAD` 含多条 `feat(...)`,按目标规则首次 dry-run 预期结果为 `v0.1.0`
- 补建本主题的 active tracking / trace 入口,并在 `ai-plan/public/README.md` 中为
`feat/semantic-release-versioning` 建立 worktree 映射
### 阶段配置落地与验证SEMREL-RP-001
- 新增 `.releaserc.json`,显式固定:
- `feat -> minor`
- `fix/perf/refactor -> patch`
- `docs/test/chore/build/ci/style -> no release`
- `BREAKING CHANGE` / `BREAKING CHANGES` 作为 major 信号
- 重写 `auto-tag.yml`
- 保留 `workflow_run` 监听 `CI - Build & Test`
- `workflow_dispatch` 变为 dry-run 入口
- 真实打 tag 改由 `semantic-release-action` 处理,并要求 `PAT_TOKEN`
- 完成最小构建验证:
- `dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`
- 结果:通过,`0 warning / 0 error`
- 直接在当前工作树执行 `semantic-release --dry-run` 时命中本地 tag 抓取冲突:
- `git fetch --tags ... would clobber existing tag`
- 结论:当前工作树不适合作为 dry-run 验证环境
- 改用干净临时克隆 `/tmp/gframework-semrel-dryrun` 再跑 dry-run
- 成功识别 `v0.0.222` 为最新 release
- 成功分析 `269` 个提交
- 按当前规则得出下一次应为 `minor` 发布,预期版本窗口从 `0.0.222` 提升到 `0.1.0`
### 下一步
1. 复核变更 diff 并创建提交
2. 向用户说明新的发版链路与可优化点