mcpField
D
dotnet-nuget-authoring

dotnet-nuget-authoring

github.com/wshaddix開発8671 回インストール35 週間前に更新
リポジトリ

dotnet-nuget-authoring について

.NET ライブラリ開発者向けに、NuGet パッケージのメタデータ、構成、マルチターゲット、署名、検証、バージョン管理を扱うスキルです。公開ワークフローや一般的なプロジェクト設定ではなく、パッケージ作成に焦点を当てています。

主な機能

  1. 01SDK スタイルのパッケージメタデータ
  2. 02ソースジェネレーターのパッケージ構成
  3. 03マルチ TFM パッケージ
  4. 04シンボルパッケージと署名
  5. 05パッケージと API の検証
  6. 06NuGet SemVer バージョン管理

活用シーン

  1. 01ライブラリの NuGet パッケージ準備
  2. 02アナライザーやソースジェネレーターの梱包
  3. 03公開前のパッケージ互換性確認
  4. 04ローカルフィードでのパッケージテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-nuget-authoring

インストール後、Claude Code で/dotnet-nuget-authoringを入力して読み込まれたか確認します。

詳細

dotnet-nuget-authoring

.NET ライブラリの作成者向け NuGet パッケージ作成:SDK スタイルの .csproj パッケージプロパティ(PackageId、PackageTags、PackageReadmeFile、PackageLicenseExpression)、analyzers/dotnet/cs/ フォルダー構成と buildTransitive ターゲットを使用したソースジェネレーターの NuGet パッケージ化、複数 TFM パッケージ、決定論的ビルドによるシンボルパッケージ(snupkg)、パッケージ署名(証明書による作成者署名、リポジトリ署名)、パッケージ検証(API 互換性のための EnablePackageValidation、Microsoft.DotNet.ApiCompat.Task)、NuGet のバージョン管理戦略(SemVer 2.0、プレリリースサフィックス、NBGV 統合)。

バージョンの前提: .NET 8.0 以降をベースラインとします。.NET 8 以降の SDK にバンドルされている NuGet クライアントを使用します。API 互換性の検証には Microsoft.DotNet.ApiCompat.Task 8.0 以降を使用します。

対象範囲の境界: このスキルは、ライブラリ利用者向けの NuGet パッケージ作成(プロパティ、メタデータ、パッケージレイアウト、署名、検証)を扱います。プロジェクトレベルの NuGet 構成(Central Package Management、SourceLink、nuget.config、NuGet Audit、ロックファイル)は [skill:dotnet-project-structure] が担当します。CI/CD の公開ワークフロー(フィードへの NuGet push、コンテナーイメージの push)は [skill:dotnet-gha-publish] と [skill:dotnet-ado-publish] が担当します。CLI ツールのパッケージ化(Homebrew、apt、winget、Scoop、dotnet tool)は [skill:dotnet-cli-packaging] が担当します。

対象外: Central Package Management、SourceLink、nuget.config、NuGet Audit については、[skill:dotnet-project-structure] を参照してください。CI/CD の NuGet push ワークフローについては、[skill:dotnet-gha-publish] と [skill:dotnet-ado-publish] を参照してください。CLI ツールのパッケージ化と配布については、[skill:dotnet-cli-packaging] を参照してください。Roslyn アナライザーの作成(Roslyn API、診断記述子)については、[skill:dotnet-roslyn-analyzers] を参照してください。リリースライフサイクルと NBGV のセットアップについては、[skill:dotnet-release-management] を参照してください。

相互参照:[skill:dotnet-project-structure](CPM、SourceLink、nuget.config)、[skill:dotnet-gha-publish](CI の NuGet push ワークフロー)、[skill:dotnet-ado-publish](ADO の NuGet push ワークフロー)、[skill:dotnet-cli-packaging](CLI ツールの配布形式)、[skill:dotnet-csharp-source-generators](Roslyn ソースジェネレーターの作成)、[skill:dotnet-release-management](リリースライフサイクルと NBGV のセットアップ)、[skill:dotnet-roslyn-analyzers](Roslyn アナライザーの作成)。


SDK スタイルのパッケージプロパティ

すべての NuGet パッケージは、.csproj 内の MSBuild プロパティから始まります。SDK スタイルのプロジェクトでは、.nuspec ファイルを使わずに dotnet pack で NuGet パッケージを生成できます。

必須のパッケージメタデータ
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <PackageId>MyCompany.Widgets</PackageId>
    <Version>1.0.0</Version>
    <Authors>My Company</Authors>
    <Description>A library for managing widgets with fluent API support.</Description>
    <PackageTags>widgets;fluent;dotnet</PackageTags>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/mycompany/widgets</PackageProjectUrl>
    <RepositoryUrl>https://github.com/mycompany/widgets</RepositoryUrl>
    <RepositoryType>git</RepositoryType>

    
    <PackageReadmeFile>README.md</PackageReadmeFile>

    
    <PackageIcon>icon.png</PackageIcon>

    
    <GenerateDocumentationFile>true</GenerateDocumentationFile>

    
    <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
  </PropertyGroup>

  
  <ItemGroup>
    <None Include="README.md" Pack="true" PackagePath="\" />
    <None Include="icon.png" Pack="true" PackagePath="\" />
  </ItemGroup>
</Project>
プロパティのリファレンス
プロパティ目的例
PackageIdnuget.org で一意となるパッケージ識別子MyCompany.Widgets
VersionSemVer 2.0 バージョン1.2.3-beta.1
Authorsカンマ区切りの作成者名Jane Doe, My Company
Descriptionnuget.org に掲載するパッケージの説明Fluent widget management library
PackageTagsセミコロン区切りの検索タグwidgets;fluent;dotnet
PackageLicenseExpressionSPDX ライセンス識別子MIT、Apache-2.0
PackageLicenseFileライセンスファイル(式の代わりに使用)LICENSE.txt
PackageReadmeFilenuget.org に表示する Markdown の readmeREADME.md
PackageIconパッケージのアイコンファイル名icon.png
PackageProjectUrlプロジェクトのホームページ URLhttps://github.com/mycompany/widgets
PackageReleaseNotesこのバージョンのリリースノートAdded widget caching support
Copyright著作権表示Copyright 2024 My Company
RepositoryUrlソースリポジトリの URLhttps://github.com/mycompany/widgets
RepositoryTypeリポジトリの種類git
共有メタデータ用の Directory.Build.props

複数プロジェクトのリポジトリでは、共通プロパティを Directory.Build.props に設定します。


<Project>
  <PropertyGroup>
    <Authors>My Company</Authors>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/mycompany/widgets</PackageProjectUrl>
    <RepositoryUrl>https://github.com/mycompany/widgets</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
    <Copyright>Copyright 2024 My Company</Copyright>
  </PropertyGroup>
</Project>

個々の .csproj ファイルでは、パッケージ固有のプロパティ(PackageId、Description、PackageTags)のみを設定します。


ソースジェネレーターの NuGet パッケージ化

ソースジェネレーターとアナライザーには、特定の NuGet パッケージ構成が必要です。ジェネレーター DLL は lib/ フォルダーではなく、analyzers/dotnet/cs/ フォルダーに配置する必要があります。Roslyn ソースジェネレーターの作成(IIncrementalGenerator、構文/セマンティック解析)については、[skill:dotnet-csharp-source-generators] を参照してください。このセクションでは、ジェネレーターの NuGet パッケージ化 のみを扱います。

ソースジェネレーターパッケージのプロジェクト設定

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
    <IsRoslynComponent>true</IsRoslynComponent>

    
    <PackageId>MyCompany.Generators</PackageId>
    <Description>Source generators for widget auto-registration.</Description>

    
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>

    
    <IsPackable>true</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
  </ItemGroup>

  
  <ItemGroup>
    <None Include="$(OutputPath)$(AssemblyName).dll"
          Pack="true"
          PackagePath="analyzers/dotnet/cs"
          Visible="false" />
  </ItemGroup>
</Project>
Build Props/Targets の追加

ソースジェネレーターが利用側プロジェクトで MSBuild プロパティを設定する必要がある場合は、buildTransitive フォルダーを使用します。


<Project>
  <PropertyGroup>
    <MyCompanyGeneratorsEnabled>true</MyCompanyGeneratorsEnabled>
  </PropertyGroup>
  <ItemGroup>
    
    <CompilerVisibleProperty Include="MyCompanyGeneratorsEnabled" />
  </ItemGroup>
</Project>

パッケージに buildTransitive の内容を含めます。


<ItemGroup>
  
  <None Include="build\MyCompany.Generators.props"
        Pack="true"
        PackagePath="buildTransitive\MyCompany.Generators.props" />
  <None Include="build\MyCompany.Generators.targets"
        Pack="true"
        PackagePath="buildTransitive\MyCompany.Generators.targets" />
</ItemGroup>
マルチターゲットのアナライザーパッケージ(アナライザー + ライブラリ)

アナライザーとランタイムライブラリの両方を同じパッケージに含める場合:


<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
    <PackageId>MyCompany.Widgets</PackageId>
  </PropertyGroup>

  
  <ItemGroup>
    <ProjectReference Include="..\MyCompany.Widgets.Generators\MyCompany.Widgets.Generators.csproj"
                      OutputItemType="Analyzer"
                      ReferenceOutputAssembly="false" />
  </ItemGroup>
</Project>
NuGet パッケージのフォルダー構成
MyCompany.Generators.1.0.0.nupkg
  analyzers/
    dotnet/
      cs/
        MyCompany.Generators.dll          <-- generator/analyzer assembly
  buildTransitive/
    MyCompany.Generators.props            <-- auto-imported MSBuild props
    MyCompany.Generators.targets          <-- auto-imported MSBuild targets
  lib/
    netstandard2.0/
      _._                                <-- empty marker (no runtime lib)

マルチ TFM パッケージ

マルチターゲットにすると、各ターゲットフレームワーク用のアセンブリを含む単一の NuGet パッケージが生成されます。利用側は最適なアセンブリを自動的に取得します。

マルチターゲットを使用する場合
シナリオ方法
ライブラリが net8.0 のみで動作する単一 TFM:<TargetFramework>net8.0</TargetFramework>
ライブラリに netstandard2.0 と net8.0 の API が必要マルチ TFM:<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
ライブラリが net9.0 固有の API(例:SearchValues)を使用するポリフィルまたは条件付きコードを使用してマルチターゲットにする
ライブラリが .NET Framework の利用側を対象とするnet472 または netstandard2.0 の TFM を含める
マルチ TFM の構成
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net8.0;net9.0</TargetFrameworks>
  </PropertyGroup>

  
  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <PackageReference Include="System.Memory" Version="4.6.0" />
    <PackageReference Include="System.Text.Json" Version="8.0.5" />
  </ItemGroup>
</Project>
条件付きコンパイル
public static class StringExtensions
{
    public static bool ContainsIgnoreCase(this string source, string value)
    {
#if NET8_0_OR_GREATER
        return source.Contains(value, StringComparison.OrdinalIgnoreCase);
#else
        return source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
#endif
    }
}
NuGet パッケージのフォルダー構成(マルチ TFM)
MyCompany.Widgets.1.0.0.nupkg
  lib/
    netstandard2.0/
      MyCompany.Widgets.dll
    net8.0/
      MyCompany.Widgets.dll
    net9.0/
      MyCompany.Widgets.dll

シンボルパッケージと決定的ビルド

シンボルパッケージ(.snupkg)を使用すると、NuGet シンボルサーバーを通じてパッケージ利用者がソースレベルでデバッグできます。

シンボルパッケージの有効化
<PropertyGroup>
  
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>

  
  <Deterministic>true</Deterministic>
  <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>

  
  <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

dotnet nuget push を使用すると、snupkg は nupkg とともに自動的にプッシュされます。

# Push both .nupkg and .snupkg to nuget.org
dotnet nuget push "bin/Release/*.nupkg" \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY"

SourceLink の統合: 実際のソースリポジトリへのリンクを使ったソースレベルのデバッグを行うには、プロジェクトで SourceLink を構成します。SourceLink の設定については [skill:dotnet-project-structure] を参照してください。ここではその構成を重複して記載しないでください。

PDB を埋め込む代替方法

別個のシンボルパッケージが望ましくないパッケージの場合:

<PropertyGroup>
  <DebugType>embedded</DebugType>
</PropertyGroup>

これにより、PDB がアセンブリ DLL に直接埋め込まれます。トレードオフとしてパッケージのサイズは大きくなりますが、配布は簡単になります。


パッケージの署名

NuGet は、作成者署名(パッケージの出所を証明)とリポジトリ署名(特定のフィードから提供されたことを証明)をサポートしています。

証明書による作成者署名
# Sign a package with a PFX certificate
dotnet nuget sign "MyCompany.Widgets.1.0.0.nupkg" \
  --certificate-path ./signing-cert.pfx \
  --certificate-password "$CERT_PASSWORD" \
  --timestamper http://timestamp.digicert.com

# Sign with a certificate from the certificate store (Windows)
dotnet nuget sign "MyCompany.Widgets.1.0.0.nupkg" \
  --certificate-fingerprint "ABC123..." \
  --timestamper http://timestamp.digicert.com
証明書の要件
要件詳細
鍵の用途コード署名(1.3.6.1.5.5.7.3.3)
アルゴリズムRSA 2048 ビット以上
タイムスタンプ長期的な有効性のために必須
信頼できる CAnuget.org では DigiCert、Sectigo、またはその他の信頼できる CA
自己署名プライベートフィードでは受け入れられますが、nuget.org では拒否されます
リポジトリ署名

リポジトリ署名はフィード運営者によって適用されます(例:nuget.org はすべてのパッケージに署名します)。パッケージ作成者がリポジトリ署名を構成する必要はありません。フィードのインフラストラクチャによって自動的に適用されます。

パッケージ署名の検証
# Verify a signed package
dotnet nuget verify "MyCompany.Widgets.1.0.0.nupkg"

# Verify with verbose output
dotnet nuget verify "MyCompany.Widgets.1.0.0.nupkg" --verbosity detailed

パッケージの検証

パッケージ検証では、公開前に API の破壊的変更、無効なパッケージ構成、互換性の問題を検出します。

組み込みのパック検証
<PropertyGroup>
  
  <EnablePackageValidation>true</EnablePackageValidation>
</PropertyGroup>

次の項目を検証します。

  • すべての TFM で互換性のある API サーフェスがあること
  • パッケージのバージョン間で API が誤って削除されていないこと
  • パッケージ構成が NuGet の規則に従っていること
ベースラインバージョンとの API 互換性

現在のパッケージを以前に公開したベースラインバージョンと比較して、破壊的変更を検出します。

<PropertyGroup>
  <EnablePackageValidation>true</EnablePackageValidation>
  
  <PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
</PropertyGroup>
Microsoft.DotNet.ApiCompat.Task

アセンブリ間の高度な API 互換性チェックには、次を使用します。

<ItemGroup>
  <PackageReference Include="Microsoft.DotNet.ApiCompat.Task" Version="8.0.0" PrivateAssets="all" />
</ItemGroup>

<PropertyGroup>
  
  <ApiCompatEnableRuleAttributesMustMatch>true</ApiCompatEnableRuleAttributesMustMatch>
  <ApiCompatEnableRuleCannotChangeParameterName>true</ApiCompatEnableRuleCannotChangeParameterName>
</PropertyGroup>
既知の破壊的変更の抑制

意図的な API 変更を行う場合は、抑制ファイルを生成してコミットします。

# Generate suppression file for known breaks
dotnet pack /p:GenerateCompatibilitySuppressionFile=true

これにより、CompatibilitySuppressions.xml が作成されます。


<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:ns="https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids">
  <Suppression>
    <DiagnosticId>CP0002</DiagnosticId>
    <Target>M:MyCompany.Widgets.Widget.OldMethod</Target>
    <Left>lib/net8.0/MyCompany.Widgets.dll</Left>
    <Right>lib/net8.0/MyCompany.Widgets.dll</Right>
  </Suppression>
</Suppressions>

抑制ファイルを参照します。

<ItemGroup>
  <ApiCompatSuppressionFile Include="CompatibilitySuppressions.xml" />
</ItemGroup>

NuGet のバージョン管理戦略

NuGet の SemVer 2.0

NuGet はセマンティック バージョニング 2.0 に準拠しています。

バージョン意味
1.0.0安定版リリース
1.0.1パッチ(バグ修正、API 変更なし)
1.1.0マイナー(新機能、後方互換性あり)
2.0.0メジャー(破壊的変更)
1.0.0-alpha.1プレリリースのアルファ版
1.0.0-beta.1プレリリースのベータ版
1.0.0-rc.1リリース候補
プレリリースのサフィックス

<Version>1.2.3</Version>


<Version>1.2.3-beta.1</Version>



NBGV の統合

Nerdbank.GitVersioning(NBGV)は、git の履歴からバージョンを計算します。NBGV のセットアップと version.json の設定については、[skill:dotnet-release-management] を参照してください。このスキルでは、NBGV が生成したバージョンと NuGet パッケージングの連携について説明します。

<PropertyGroup>
  
  
</PropertyGroup>

NBGV は 1.2.42-beta+abcdef のようなバージョンを生成します。

  • 1.2 は version.json に由来します
  • 42 は git コミットの高さです
  • -beta は version.json のプレリリースサフィックスです
  • +abcdef は git コミットハッシュです(ビルドメタデータであり、NuGet の解決では無視されます)
バージョンプロパティのリファレンス
プロパティ用途設定元
VersionSemVer の完全なバージョン(PackageVersion を決定)手動または NBGV
PackageVersionNuGet パッケージのバージョン(デフォルトは Version)手動または NBGV
AssemblyVersionCLR アセンブリのバージョン手動または NBGV
FileVersionWindows ファイルのバージョン手動または NBGV
InformationalVersionメタデータを含む完全なバージョン文字列手動または NBGV

パッケージ化とローカルテスト

パッケージのビルド
# Pack in Release configuration
dotnet pack --configuration Release

# Pack with specific version override
dotnet pack --configuration Release /p:Version=1.2.3-beta.1

# Output to specific directory
dotnet pack --configuration Release --output ./artifacts
ローカルフィードでのテスト

公開する前に、パッケージをローカルでテストします。

# Create a local feed directory
mkdir -p ~/local-nuget-feed

# Add the package to the local feed
dotnet nuget push "bin/Release/MyCompany.Widgets.1.0.0.nupkg" \
  --source ~/local-nuget-feed

# In the consuming project, add the local feed
dotnet nuget add source ~/local-nuget-feed --name LocalFeed
パッケージ内容の確認
# List package contents (nupkg is a zip file)
unzip -l MyCompany.Widgets.1.0.0.nupkg

# Verify analyzer placement
unzip -l MyCompany.Generators.1.0.0.nupkg | grep analyzers/

エージェントが注意すべき点

  1. PackageLicenseExpression と PackageLicenseFile の両方を設定しないでください。これらは相互に排他的です。標準の SPDX 識別子には PackageLicenseExpression を、カスタムライセンスには PackageLicenseFile のみを使用します。

  2. ソースジェネレーターは必ず netstandard2.0 をターゲットにしてください。Roslyn ホストがこれを必要とします。ジェネレーター自体をマルチターゲットにしないでください。ジェネレータープロジェクトを参照するランタイムライブラリをマルチターゲットにします。

  3. ライブラリプロジェクトで IncludeBuildOutput を false に設定しないでください。ランタイムアセンブリを含めない純粋なアナライザー/ジェネレータープロジェクトでのみ設定します。

  4. buildTransitive と build フォルダーの違い。推移的な PackageReference 依存関係にも適用する props/targets には buildTransitive を使用します。build フォルダーは直接のコンシューマーにのみ影響します。

  5. パッケージ検証の抑制には、PackageValidationSuppression MSBuild 項目ではなく、CompatibilitySuppressions.xml とともに ApiCompatSuppressionFile を使用します。/p:GenerateCompatibilitySuppressionFile=true を指定してファイルを生成します。

  6. SDK スタイルのプロジェクトは、すべての *.cs ファイルを自動的に含めます。先に Compile Remove を指定せずに TFM 条件付きの Compile Include を追加すると、重複項目が原因で NETSDK1022 が発生します。

  7. CLI の例に API キーをハードコードしないでください。必ず環境変数のプレースホルダー($NUGET_API_KEY)を使用し、CI のシークレットストレージについて注記してください。

  8. ContinuousIntegrationBuild は CI 実行時にのみ設定してください。無条件に設定すると、PDB にローカルのファイルパスが含まれて再現性が失われ、ローカルでのデバッグに支障が出ます。

コメント