mcpField
D
dotnet-release-management

dotnet-release-management

github.com/wshaddix开发8670 次安装35 周前更新
代码仓库

关于 dotnet-release-management

dotnet-release-management 是面向 .NET 团队的发布生命周期技能,涵盖版本管理、变更日志、预发布阶段和分支策略,并介绍基于 NBGV 的版本计算。

主要功能

  1. 01NBGV 与 version.json 版本配置
  2. 02按 SemVer 评估变更级别
  3. 03Keep a Changelog 与 git-cliff
  4. 04alpha、beta、rc 发布流程
  5. 05发布分支与 trunk-based 模式

适用场景

  1. 01为 .NET 库判断 major、minor 或 patch
  2. 02从 Git 提交历史计算版本号
  3. 03按 Conventional Commits 生成变更日志
  4. 04规划预发布到稳定版的演进

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-release-management

安装后在 Claude Code 中输入/dotnet-release-management确认已加载。

详细介绍

dotnet-release-management

.NET 项目的发布生命周期管理:使用 version.json 配置 Nerdbank.GitVersioning(NBGV)、计算版本高度,以及管理公开发布与预发布模式;适用于 .NET 库的 SemVer 2.0 策略(何时提升 major/minor/patch 版本、API 兼容性考量)以及适用于应用程序的策略(构建元数据、部署版本管理);生成变更日志(Keep a Changelog 格式,使用 git-cliff 和 conventional commits 自动生成);预发布版本工作流(alpha、beta、rc、stable 的递进);以及发布分支模式(发布分支、热修复分支、带标签的主干开发发布)。

**版本假设:**基准版本为 .NET 8.0+。Nerdbank.GitVersioning 3.6+(当前稳定版)。SemVer 2.0 规范。

**范围边界:**此技能负责发布生命周期策略——版本管理、变更日志、预发布工作流和分支模式。插件专属的发布工作流(dotnet-artisan 版本管理和发布)记录在仓库级 CONTRIBUTING.md 中。CI/CD 发布工作流(NuGet 推送、容器推送、部署)由 [skill:dotnet-gha-publish] 和 [skill:dotnet-ado-publish] 负责。GitHub Release 创建和资源管理由 [skill:dotnet-github-releases] 负责。NuGet 包版本属性(Version、PackageVersion)由 [skill:dotnet-nuget-authoring] 负责。

**范围外:**插件专属的发布工作流——参见仓库级 CONTRIBUTING.md。CI/CD NuGet 推送和部署工作流——参见 [skill:dotnet-gha-publish] 和 [skill:dotnet-ado-publish]。GitHub Release 创建和资源附加——参见 [skill:dotnet-github-releases]。NuGet 包元数据和签名——参见 [skill:dotnet-nuget-authoring]。项目级配置(SourceLink、CPM)——参见 [skill:dotnet-project-structure]。

交叉引用:[skill:dotnet-gha-publish] 介绍 CI 发布工作流,[skill:dotnet-ado-publish] 介绍 ADO 发布工作流,[skill:dotnet-nuget-authoring] 介绍 NuGet 包版本属性。


NBGV(Nerdbank.GitVersioning)

NBGV 根据 git 历史计算确定性版本号。版本由 version.json 文件和 git 提交高度(自设置版本以来的提交数)推导得出,无需手动提升版本,即可为每次提交生成唯一版本。

安装
# Install NBGV CLI tool
dotnet tool install --global nbgv

# Initialize NBGV in a repository
nbgv install

# This creates version.json at the repo root
version.json 配置
{
  "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
  "version": "1.0",
  "publicReleaseRefSpec": [
    "^refs/heads/main$",
    "^refs/tags/v\\d+\\.\\d+(\\.\\d+)?(-.*)?$"
  ],
  "cloudBuild": {
    "buildNumber": {
      "enabled": true
    },
    "setVersionVariables": true
  }
}
version.json 字段参考
字段用途示例
version基础版本(major.minor,可选 patch)"1.0"、"2.3.0"
publicReleaseRefSpec生成公开版本的分支/标签正则表达式模式["^refs/heads/main$"]
cloudBuild.buildNumber.enabled将 CI 构建编号设为计算得出的版本true
cloudBuild.setVersionVariables将版本导出为 CI 环境变量true
nugetPackageVersion覆盖 NuGet 包版本格式{"semVer": 2}
assemblyVersion.precision程序集版本的组件数量"major"、"minor"、"build"、"revision"
inherit从父目录的 version.json 继承true
版本高度的工作原理

NBGV 统计自 version.json 中 version 字段上次更改以来的提交数。该计数会成为 patch 版本:

version.json: "version": "1.2"

Commit history:
  abc1234  feat: add caching          -> 1.2.3
  def5678  fix: null check            -> 1.2.2
  ghi9012  chore: update deps         -> 1.2.1
  jkl3456  Bump version to 1.2        -> 1.2.0  (version.json changed here)

版本高度确保每次提交都有唯一版本,无需人工干预。

预发布与公开发布
{
  "version": "1.2-beta",
  "publicReleaseRefSpec": [
    "^refs/heads/main$",
    "^refs/tags/v\\d+\\.\\d+(\\.\\d+)?(-.*)?$"
  ]
}
分支/引用计算得出的版本说明
main(公开)1.2.5-beta公开预发布版本,高度=5
feature/foo(非公开)1.2.5-beta.gcommithash包含 git 哈希后缀
标签 v1.2.5(公开)1.2.5创建标签前移除 -beta

要发布稳定版本,请在发布提交前从 version.json 中移除预发布后缀:

{
  "version": "1.2"
}
NBGV CLI 命令
# Show the current calculated version
nbgv get-version

# Show specific version properties
nbgv get-version -v NuGetPackageVersion
nbgv get-version -v SemVer2

# Prepare for a release (creates release branch, bumps version)
nbgv prepare-release

# Set version variables for CI
nbgv cloud
Monorepo NBGV 配置

对于包含独立版本项目的 monorepo,请将 version.json 放在每个项目目录中,并使用 inherit:

repo-root/
  version.json              <- { "version": "1.0" }
  src/
    LibraryA/
      version.json          <- { "version": "2.3", "inherit": true }
    LibraryB/
      version.json          <- { "version": "1.1-beta", "inherit": true }

inherit 字段会从父级 version.json 中继承设置(例如 publicReleaseRefSpec 和 cloudBuild),同时覆盖版本号。


.NET 库的 SemVer 策略

何时提升版本号

SemVer 2.0 指定的版本格式为 MAJOR.MINOR.PATCH:

变更类型版本提升示例
破坏性 API 变更Major移除公共类型/成员、更改方法签名、重命名命名空间
新功能(向后兼容)Minor添加公共类型/成员、新扩展方法、新重载
Bug 修复(向后兼容)Patch修复错误行为、性能改进、内部重构
.NET 特有的破坏性变更注意事项
变更是否具有破坏性?备注
移除公共类型是(Major)引用该类型的使用者将无法编译
移除公共方法是(Major)直接调用方将无法使用
为公共方法添加必需参数是(Major)现有调用方不会传入该参数
为公共方法添加可选参数否(Minor)二进制兼容,但对使用命名参数的调用方而言会造成源代码破坏
更改返回类型是(Major)破坏二进制兼容性和源代码兼容性
添加新的公共类型否(Minor)不影响现有代码
添加新重载否(Minor)现有调用仍可正常解析
更改内部实现否(Patch)不更改公共 API
更改可选参数的默认值否(Patch)二进制兼容(重新编译时,该值会嵌入调用位置)
将之前未密封的类设为密封是(Major)继承该类的使用者将无法使用
将虚方法改为非虚方法是(Major)重写该方法的使用者将无法使用
API 兼容性验证

使用 EnablePackageValidation 检查意外的破坏性变更。完整的软件包验证设置请参阅 [skill:dotnet-nuget-authoring]。

<PropertyGroup>
  <EnablePackageValidation>true</EnablePackageValidation>
  <PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
</PropertyGroup>

应用程序的 SemVer 策略

应用程序(Web 应用、桌面应用、服务)的版本控制注意事项与库不同,因为它们没有公共 API 使用者。

应用程序版本控制方法
方法格式最适用于
SemVer(由功能驱动)1.2.3用户可见版本号的已安装桌面/移动应用
CalVer(基于日历)2024.1.15持续部署的 SaaS 应用
构建编号1.2.3+42使用构建元数据进行 CI 驱动的版本控制
NBGV 高度1.2.42根据 git 提交自动进行版本控制
构建元数据

SemVer 2.0 允许使用以 + 为后缀的构建元数据;它不会影响版本优先级:

1.2.3+build.42        Build number
1.2.3+abcdef          Git commit hash
1.2.3+2024.01.15      Build date
1.2.3-beta.1+42       Pre-release with build metadata

构建元数据有助于追溯已部署的二进制文件对应的源代码提交。NBGV 会自动追加 git 元数据。

部署版本控制

对于持续部署的服务,版本标记有助于排查问题:

<PropertyGroup>
  
  <InformationalVersion>1.2.3+abcdef.2024-01-15</InformationalVersion>
</PropertyGroup>

在运行时读取:

var version = typeof(Program).Assembly
    .GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>()
    ?.InformationalVersion;
// Returns "1.2.3+abcdef.2024-01-15"

变更日志生成

Keep a Changelog 格式

Keep a Changelog 格式是一种广泛采用的标准:

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Widget caching support for improved throughput

## [1.2.0] - 2024-03-15

### Added
- Fluent API for widget configuration
- Batch processing support

### Changed
- Improved error messages for invalid widget states

### Fixed
- Memory leak in widget pool under high concurrency
- Timezone handling in scheduled widget operations

### Deprecated
- `Widget.Create()` static method -- use `WidgetBuilder` instead

## [1.1.0] - 2024-01-10

### Added
- Widget serialization support

[Unreleased]: https://github.com/mycompany/widgets/compare/v1.2.0...HEAD
[1.2.0]: https://github.com/mycompany/widgets/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/mycompany/widgets/releases/tag/v1.1.0
章节类型
章节用途
Added新功能
Changed对现有功能的更改
Deprecated将在未来版本中移除的功能
Removed此版本中移除的功能
FixedBug 修复
Security漏洞修复
使用 git-cliff 自动生成

git-cliff 会根据约定式提交生成变更日志:

# Install git-cliff
cargo install git-cliff

# Generate changelog for all versions
git cliff --output CHANGELOG.md

# Generate changelog for unreleased changes only
git cliff --unreleased --output CHANGELOG.md

# Generate notes for a specific tag range
git cliff --tag v1.2.0 --unreleased

配置 cliff.toml 以适配 .NET 约定式提交模式:

# cliff.toml
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
{% if version %}\
    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
    ## [Unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message | upper_first }}\
    {% endfor %}
{% endfor %}\n
"""
trim = true

[git]
conventional_commits = true
filter_unconventional = true
commit_parsers = [
    { message = "^feat", group = "Added" },
    { message = "^fix", group = "Fixed" },
    { message = "^perf", group = "Changed" },
    { message = "^refactor", group = "Changed" },
    { message = "^docs", group = "Documentation" },
    { message = "^chore\\(deps\\)", group = "Dependencies" },
    { message = "^chore", skip = true },
    { message = "^ci", skip = true },
    { message = "^test", skip = true },
]
常规提交格式
feat: add widget caching support
fix: correct timezone handling in scheduler
feat!: rename Widget.Create() to WidgetBuilder.Build()
chore(deps): update System.Text.Json to 8.0.5
docs: update API reference for caching

Breaking change in body:
feat: redesign widget API

BREAKING CHANGE: Widget.Create() has been removed. Use WidgetBuilder instead.
前缀SemVer 影响更新日志章节
feat:次要版本新增
fix:修订版本修复
feat!: 或 BREAKING CHANGE:主版本重大变更
perf:修订版本变更
refactor:修订版本变更
docs:无文档
chore:无(跳过)

预发布版本工作流

标准预发布版本递进
alpha -> beta -> rc -> stable

1.0.0-alpha.1  Early development, API unstable
1.0.0-alpha.2  Continued alpha iteration
1.0.0-beta.1   Feature-complete, API stabilizing
1.0.0-beta.2   Beta bug fixes
1.0.0-rc.1     Release candidate, final validation
1.0.0-rc.2     RC bug fix (if needed)
1.0.0          Stable release
NBGV 预发布工作流
# Start with pre-release suffix in version.json
# version.json: { "version": "1.0-alpha" }
# Produces: 1.0.1-alpha, 1.0.2-alpha, ...

# Promote to beta
# Edit version.json: { "version": "1.0-beta" }
# Produces: 1.0.1-beta, 1.0.2-beta, ...

# Promote to rc
# Edit version.json: { "version": "1.0-rc" }
# Produces: 1.0.1-rc, 1.0.2-rc, ...

# Promote to stable
# Edit version.json: { "version": "1.0" }
# Produces: 1.0.1, 1.0.2, ...
手动预发布工作流

对于未使用 NBGV 的项目:


<PropertyGroup>
  <VersionPrefix>1.0.0</VersionPrefix>
  <VersionSuffix>beta.1</VersionSuffix>
  
</PropertyGroup>

从 CI 覆盖:

# CI sets the pre-release suffix
dotnet pack /p:VersionSuffix="beta.$(BUILD_NUMBER)"

# Stable release: omit VersionSuffix
dotnet pack
NuGet 预发布排序

NuGet 遵循 SemVer 2.0 的预发布优先级规则:

1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.2
1.0.0-alpha.2 < 1.0.0-beta
1.0.0-beta < 1.0.0-beta.1
1.0.0-rc.1 < 1.0.0

数字标识符按整数比较;字母标识符按字典序比较。


发布分支模式

基于主干并使用标签

最简单的发布模式。所有开发都在 main 上进行,发布通过标签标记。

main:  A -- B -- C -- D -- E -- F -- G
                 |              |
              v1.0.0         v1.1.0
# Tag and push for release
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0

适用于: 库、小型团队、持续交付。

发布分支

创建发布分支进行稳定化,同时 main 继续开发。

main:      A -- B -- C -- D -- E -- F -- G
                      \
release/1.0:           C' -- D' -- E'
                              |
                           v1.0.0
# Create release branch
git checkout -b release/1.0 main

# Stabilize on release branch (bug fixes only)
git commit -m "fix: correct null check in widget pool"

# Tag and release
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin release/1.0 v1.0.0

# Merge fixes back to main
git checkout main
git merge release/1.0

适用于: 有支持合同的产品、LTS 版本,以及需要并行开发与稳定化的团队。

NBGV prepare-release

NBGV 可自动创建发布分支并提升版本:

# Creates release/v1.0 branch, bumps main to 1.1-alpha
nbgv prepare-release

# What this does:
# 1. Creates branch "release/v1.0" from current commit
# 2. On release branch: removes pre-release suffix (version: "1.0")
# 3. On main: bumps to "1.1-alpha" (next development version)
热修复分支

针对已发布版本的紧急修复:

main:         A -- B -- C -- D -- E
                         \
release/1.0:              C' -- v1.0.0
                                  \
hotfix/1.0.1:                      F' -- v1.0.1
# Branch from the release tag
git checkout -b hotfix/1.0.1 v1.0.0

# Fix the critical issue
git commit -m "fix: critical security vulnerability in auth handler"

# Tag and release the hotfix
git tag -a v1.0.1 -m "Hotfix v1.0.1"
git push origin hotfix/1.0.1 v1.0.1

# Merge hotfix back to main
git checkout main
git merge hotfix/1.0.1
分支模式比较
模式发布节奏并行版本复杂度
主干 + 标签持续否低
发布分支定期是中
GitFlow(完整)定期是高

对于大多数 .NET 开源库,基于主干并使用标签搭配 NBGV 已足够。仅当产品需要同时维护多个受支持版本时,才使用发布分支。


Agent 注意事项

  1. NBGV 的 version.json 仅使用 major.minor(而非 major.minor.patch)——修订版本由提交高度计算。设置 "version": "1.2.3" 会将修订版本固定为 3,违背自动版本管理的初衷。

  2. NBGV 需要 Git 历史记录来计算版本高度——浅克隆(git clone --depth 1)会生成错误的版本。在 CI 中,使用 actions/checkout 并设置 fetch-depth: 0 以获取完整历史记录。

  3. publicReleaseRefSpec 模式是正则表达式,不是 glob——应使用 ^refs/heads/main$,而非 main。缺少锚点会匹配到非预期的引用。

  4. SemVer 预发布版本中,非数字段按字典序排序——由于按字母顺序比较,alpha < beta < rc。数字段按整数比较,因此 beta.2 < beta.10(因为 2 < 10)。不要假定数字标识符按字典序排序。

  5. 不要对 NuGet 库使用 CalVer——NuGet 的版本解析依赖 SemVer 排序。像 2024.1.0 这样的 CalVer 版本虽然在机制上可用,但不符合使用者对 API 稳定性信号的预期。

  6. VersionPrefix + VersionSuffix 会组合成 Version——同时设置三者会导致冲突。应单独使用 Version,或同时使用 VersionPrefix/VersionSuffix,不要两者兼用。

  7. 发布前必须更新 Keep a Changelog 的 [Unreleased] 章节——将条目从 [Unreleased] 移至新版本章节,更新比较链接,并添加一个新的空 [Unreleased] 章节。

  8. nbgv prepare-release 会同时修改新分支和当前分支——它会将当前分支的版本提升到下一个次要版本。应在你打算继续开发的分支上运行(通常是 main)。

评论

支持 Markdown