dotnet-release-management について
dotnet-release-managementは、.NETチーム向けのリリースライフサイクルスキルです。バージョン管理、変更履歴、プレリリース、ブランチ戦略を扱い、NBGVによるバージョン計算も解説します。
主な機能
- 01NBGVとversion.jsonによるバージョン設定
- 02SemVerに基づく変更レベルの判断
- 03Keep a Changelogとgit-cliff
- 04alpha、beta、rcのリリース手順
- 05リリースブランチとtrunk-based方式
活用シーン
- 01.NETライブラリのmajor、minor、patchの判断
- 02Gitのコミット履歴からのバージョン計算
- 03Conventional Commitsに基づく変更履歴の生成
- 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 戦略(メジャー/マイナー/パッチをいつ上げるか、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 | ベースバージョン(メジャー.マイナー、パッチは任意) | "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 フィールドが最後に変更されてからのコミット数を数えます。この数がパッチバージョンになります。
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
モノレポの NBGV 設定
プロジェクトごとに独立したバージョンを付けるモノレポでは、各プロジェクトディレクトリに 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 の変更 | メジャー | パブリックな型やメンバーの削除、メソッドシグネチャの変更、名前空間の変更 |
| 新機能(後方互換性あり) | マイナー | パブリックな型やメンバーの追加、新しい拡張メソッド、新しいオーバーロード |
| バグ修正(後方互換性あり) | パッチ | 誤った動作の修正、パフォーマンスの改善、内部リファクタリング |
.NET 固有の破壊的変更に関する考慮事項
| 変更 | 破壊的変更か | 備考 |
|---|---|---|
| パブリックな型の削除 | はい(メジャー) | その型を参照している利用者のコードはコンパイルに失敗します |
| パブリックなメソッドの削除 | はい(メジャー) | 直接呼び出しているコードは失敗します |
| パブリックなメソッドへの必須パラメーターの追加 | はい(メジャー) | 既存の呼び出し元はそのパラメーターを指定しません |
| パブリックなメソッドへの省略可能なパラメーターの追加 | いいえ(マイナー) | バイナリ互換ですが、名前付き引数を使用する呼び出し元のソースコードとの互換性は損なわれます |
| 戻り値の型の変更 | はい(メジャー) | バイナリとソースコードの両方の互換性が損なわれます |
| 新しいパブリックな型の追加 | いいえ(マイナー) | 既存のコードには影響しません |
| 新しいオーバーロードの追加 | いいえ(マイナー) | 既存の呼び出しは引き続き解決されます |
| 内部実装の変更 | いいえ(パッチ) | パブリック API に変更はありません |
| 省略可能なパラメーターの既定値の変更 | いいえ(パッチ) | バイナリ互換です(再コンパイル時に呼び出し箇所へ値が埋め込まれます) |
| 以前は継承可能だったクラスをシールする | はい(メジャー) | そのクラスを継承している利用者のコードは失敗します |
| 仮想メソッドを非仮想にする | はい(メジャー) | そのメソッドをオーバーライドしている利用者のコードは失敗します |
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 | このリリースで削除された機能 |
Fixed | バグ修正 |
Security | 脆弱性の修正 |
git-cliff による自動生成
git-cliff は、Conventional Commits から変更履歴を生成します。
# 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
.NET の Conventional Commits パターンに合わせて cliff.toml を設定します。
# 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 },
]
Conventional Commit 形式
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 で十分です。複数のサポート対象バージョンを同時に維持する製品では、リリースブランチを使用してください。
エージェント利用時の注意点
-
NBGV の
version.jsonでは major.minor のみを指定し、major.minor.patch は指定しません -- パッチバージョンはコミット数から計算されます。"version": "1.2.3"と設定すると、パッチが 3 に固定され、自動バージョン管理の目的が損なわれます。 -
NBGV がバージョンの高さを計算するには Git の履歴が必要です -- 浅いクローン(
git clone --depth 1)では、正しくないバージョンが生成されます。CI ではactions/checkoutにfetch-depth: 0を指定して、完全な履歴を取得してください。 -
publicReleaseRefSpecのパターンは glob ではなく正規表現です --mainではなく^refs/heads/main$を使用してください。アンカーがないと、意図しない ref に一致します。 -
SemVer のプレリリース順序では、数値以外のセグメントは辞書順で比較されます -- アルファベット順の比較により、
alpha<beta<rcとなります。数値セグメントは整数として比較されるため、beta.2<beta.10となります(2 < 10 のため)。数値識別子も辞書順で並ぶと想定しないでください。 -
NuGet ライブラリでは CalVer を使用しないでください -- NuGet の依存関係解決は SemVer の順序に依存します。
2024.1.0のような CalVer バージョンは機械的には機能しますが、API の安定性を示すシグナルに関する利用者の期待に反します。 -
VersionPrefixとVersionSuffixを組み合わせるとVersionになります -- 3 つすべてを設定すると競合が発生します。Versionのみを使用するか、VersionPrefixとVersionSuffixを組み合わせて使用してください。両方を併用しないでください。 -
Keep a Changelog の
[Unreleased]セクションはリリース前に更新する必要があります --[Unreleased]の項目を新しいバージョンのセクションに移動し、比較リンクを更新して、新しい空の[Unreleased]セクションを追加してください。 -
nbgv prepare-releaseは新しいブランチと現在のブランチの両方を変更します -- 現在のブランチのバージョンを次のマイナーバージョンに更新します。開発を続けるブランチ(通常はmain)から実行してください。