mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
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:
parent
0c7552e629
commit
b194238385
100
.github/workflows/auto-tag.yml
vendored
100
.github/workflows/auto-tag.yml
vendored
@ -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
72
.releaserc.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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`
|
||||||
|
|||||||
@ -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. 若本轮验证通过,按仓库要求创建提交并等待你审阅发版流程细节
|
||||||
@ -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. 向用户说明新的发版链路与可优化点
|
||||||
Loading…
x
Reference in New Issue
Block a user