mcpField
D
dotnet-cli-packaging

dotnet-cli-packaging

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

dotnet-cli-packaging について

dotnet-cli-packagingは、.NETコマンドラインツールの保守担当者向けに、配布パッケージの作成方法をまとめたスキルです。Homebrew、apt/deb、winget、Scoop、Chocolatey、dotnet tool、NuGetの形式を扱います。

主な機能

  1. 01Homebrewのformulaとcaskの作成
  2. 02`dpkg-deb` によるapt/debパッケージの構築
  3. 03wingetとScoopのマニフェスト準備
  4. 04Chocolatey向けのツールパッケージ作成
  5. 05`dotnet tool` パッケージの設定
  6. 06NuGetへのパッケージ公開

活用シーン

  1. 01.NETコマンドラインツールのHomebrew向けパッケージ化
  2. 02DebianまたはUbuntu向け`.deb`の準備
  3. 03wingetまたはScoopへのツールパッケージ提出
  4. 04dotnet toolまたはNuGetでのツール配布

インストール

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

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-cli-packaging

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

詳細

dotnet-cli-packaging

.NET CLI ツールのマルチプラットフォーム向けパッケージング:Homebrew フォーミュラの作成(バイナリータップと Cask)、dpkg-deb を使用した apt/deb パッケージング、winget マニフェストの YAML スキーマと winget-pkgs への PR の提出、Scoop マニフェストの JSON、Chocolatey パッケージの作成、dotnet tool のグローバル/ローカルパッケージング、NuGet による配布。

バージョンの前提: .NET 8.0 以降を基準とします。パッケージマネージャーの形式は .NET のバージョン間で安定しています。

対象外: CLI の配布戦略(AOT、フレームワーク依存、dotnet tool のどれを選ぶか)については、[skill:dotnet-cli-distribution] を参照してください。パッケージングを自動化するリリース CI/CD パイプラインについては、[skill:dotnet-cli-release-pipeline] を参照してください。ネイティブ AOT コンパイルについては、[skill:dotnet-native-aot] を参照してください。コンテナーを使用した配布については、[skill:dotnet-containers] を参照してください。一般的な CI/CD パターンについては、[skill:dotnet-gha-patterns] と [skill:dotnet-ado-patterns] を参照してください。

相互参照:[skill:dotnet-cli-distribution] は配布戦略と RID マトリックス、[skill:dotnet-cli-release-pipeline] はパッケージの自動公開、[skill:dotnet-native-aot] は AOT バイナリーの生成、[skill:dotnet-containers] はコンテナーを使用した配布、[skill:dotnet-tool-management] は利用者側でのツールのインストールとマニフェスト管理について説明しています。


Homebrew(macOS / Linux)

Homebrew は macOS の主要なパッケージマネージャーであり、Linux でも広く使用されています。CLI ツール向けには、2 種類の配布形式があります。

バイナリータップ(フォーミュラ)

フォーミュラは、プラットフォームごとにビルド済みバイナリーをダウンロードします。Native AOT CLI ツールには、この方法を推奨します。

# Formula/mytool.rb
class Mytool < Formula
  desc "A CLI tool for managing widgets"
  homepage "https://github.com/myorg/mytool"
  version "1.2.3"
  license "MIT"

  on_macos do
    on_arm do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-osx-arm64.tar.gz"
      sha256 "abc123..."
    end
    # Optional: remove on_intel block if not targeting Intel Macs
    on_intel do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-osx-x64.tar.gz"
      sha256 "def456..."
    end
  end

  on_linux do
    on_arm do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-linux-arm64.tar.gz"
      sha256 "ghi789..."
    end
    on_intel do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-linux-x64.tar.gz"
      sha256 "jkl012..."
    end
  end

  def install
    bin.install "mytool"
  end

  test do
    assert_match version.to_s, shell_output("#{bin}/mytool --version")
  end
end
タップのホスティング

タップは、フォーミュラを含む Git リポジトリです。homebrew-tap という名前のリポジトリを作成します。

myorg/homebrew-tap/
  Formula/
    mytool.rb

ユーザーは次のコマンドでインストールします。

brew tap myorg/tap
brew install mytool
Homebrew Cask

Cask は GUI アプリケーションやインストーラーを含むツール向けです。CLI 専用ツールには、Cask よりフォーミュラをおすすめします。

# Casks/mytool.rb -- only if the tool has a GUI component
cask "mytool" do
  version "1.2.3"
  sha256 "abc123..."

  url "https://github.com/myorg/mytool/releases/download/v#{version}/mytool-#{version}-osx-arm64.tar.gz"
  name "MyTool"
  homepage "https://github.com/myorg/mytool"

  binary "mytool"
end

apt/deb(Debian/Ubuntu)

dpkg-deb を使用した .deb パッケージのビルド

パッケージのディレクトリ構造を作成します。

mytool_1.2.3_amd64/
  DEBIAN/
    control
  usr/
    bin/
      mytool

Control ファイル:

Package: mytool
Version: 1.2.3
Section: utils
Priority: optional
Architecture: amd64
Maintainer: My Org <[email protected]>
Description: A CLI tool for managing widgets
 MyTool provides fast widget management from the command line.
 Built with .NET Native AOT for zero-dependency execution.
Homepage: https://github.com/myorg/mytool

パッケージをビルドします。

#!/bin/bash
set -euo pipefail

VERSION="${1:?Usage: build-deb.sh <version>}"
ARCH="amd64"  # or arm64
PKG_DIR="mytool_${VERSION}_${ARCH}"

mkdir -p "$PKG_DIR/DEBIAN"
mkdir -p "$PKG_DIR/usr/bin"

# Copy the published binary
cp "artifacts/linux-x64/mytool" "$PKG_DIR/usr/bin/mytool"
chmod 755 "$PKG_DIR/usr/bin/mytool"

# Write control file
cat > "$PKG_DIR/DEBIAN/control" << EOF
Package: mytool
Version: ${VERSION}
Section: utils
Priority: optional
Architecture: ${ARCH}
Maintainer: My Org <[email protected]>
Description: A CLI tool for managing widgets
Homepage: https://github.com/myorg/mytool
EOF

# Build the .deb
dpkg-deb --build --root-owner-group "$PKG_DIR"
echo "Built: ${PKG_DIR}.deb"

RID と Debian アーキテクチャの対応:

.NET RIDDebian アーキテクチャ
linux-x64amd64
linux-arm64arm64
.deb のインストール
sudo dpkg -i mytool_1.2.3_amd64.deb

winget(Windows パッケージマネージャー)

マニフェストの YAML スキーマ

winget マニフェストは、microsoft/winget-pkgs リポジトリ内のバージョン別ディレクトリ構造にある複数の YAML ファイルで構成されます。

ディレクトリ構造:

manifests/
  m/
    MyOrg/
      MyTool/
        1.2.3/
          MyOrg.MyTool.yaml              # Version manifest
          MyOrg.MyTool.installer.yaml    # Installer manifest
          MyOrg.MyTool.locale.en-US.yaml # Locale manifest

バージョンマニフェスト(MyOrg.MyTool.yaml):

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
DefaultLocale: en-US
ManifestType: version
ManifestVersion: 1.9.0

インストーラーマニフェスト(MyOrg.MyTool.installer.yaml):

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
InstallerType: zip
NestedInstallerType: portable
NestedInstallerFiles:
  - RelativeFilePath: mytool.exe
    PortableCommandAlias: mytool
Installers:
  - Architecture: x64
    InstallerUrl: https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip
    InstallerSha256: ABC123...
  - Architecture: arm64
    InstallerUrl: https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-arm64.zip
    InstallerSha256: DEF456...
ManifestType: installer
ManifestVersion: 1.9.0

ロケールマニフェスト(MyOrg.MyTool.locale.en-US.yaml):

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
PackageLocale: en-US
PackageName: MyTool
Publisher: My Org
ShortDescription: A CLI tool for managing widgets
License: MIT
PackageUrl: https://github.com/myorg/mytool
ManifestType: defaultLocale
ManifestVersion: 1.9.0
winget-pkgs への提出
  1. GitHub で microsoft/winget-pkgs をフォークします
  2. 正しいディレクトリ構造にマニフェストファイルを作成します
  3. ローカルで検証します:winget validate --manifest <path>
  4. PR を提出します。マニフェストに対して自動チェックが実行されます
  5. Microsoft チームがレビューし、マージします

winget の PR 作成を自動化する方法については、[skill:dotnet-cli-release-pipeline] を参照してください。


Scoop(Windows)

Scoop は、Windows のパワーユーザーに人気があります。マニフェストは、バケットリポジトリ内の JSON ファイルです。

Scoop マニフェスト
{
  "version": "1.2.3",
  "description": "A CLI tool for managing widgets",
  "homepage": "https://github.com/myorg/mytool",
  "license": "MIT",
  "architecture": {
    "64bit": {
      "url": "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip",
      "hash": "abc123..."
    },
    "arm64": {
      "url": "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-arm64.zip",
      "hash": "def456..."
    }
  },
  "bin": "mytool.exe",
  "checkver": {
    "github": "https://github.com/myorg/mytool"
  },
  "autoupdate": {
    "architecture": {
      "64bit": {
        "url": "https://github.com/myorg/mytool/releases/download/v$version/mytool-$version-win-x64.zip"
      },
      "arm64": {
        "url": "https://github.com/myorg/mytool/releases/download/v$version/mytool-$version-win-arm64.zip"
      }
    }
  }
}
Scoop バケットのホスティング

scoop-mytool(または scoop-bucket)という名前の GitHub リポジトリを作成します。

myorg/scoop-mytool/
  bucket/
    mytool.json

ユーザーは次のコマンドでインストールします。

scoop bucket add myorg https://github.com/myorg/scoop-mytool
scoop install mytool

Chocolatey

Chocolatey は、バイナリー配布において Windows で最も広く確立されたパッケージマネージャーです。

パッケージ構造
mytool/
  mytool.nuspec
  tools/
    chocolateyInstall.ps1
    LICENSE.txt

mytool.nuspec:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.xmldata.org/2004/07/nuspec">
  <metadata>
    <id>mytool</id>
    <version>1.2.3</version>
    <title>MyTool</title>
    <authors>My Org</authors>
    <projectUrl>https://github.com/myorg/mytool</projectUrl>
    <license type="expression">MIT</license>
    <description>A CLI tool for managing widgets.</description>
    <tags>cli dotnet tools</tags>
  </metadata>
</package>

tools/chocolateyInstall.ps1:

$ErrorActionPreference = 'Stop'

$packageArgs = @{
  packageName    = 'mytool'
  url64bit       = 'https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip'
  checksum64     = 'ABC123...'
  checksumType64 = 'sha256'
  unzipLocation  = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
}

Install-ChocolateyZipPackage @packageArgs
ビルドと公開
# Pack the .nupkg
choco pack mytool.nuspec

# Test locally
choco install mytool --source="." --force

# Push to Chocolatey Community Repository
choco push mytool.1.2.3.nupkg --source https://push.chocolatey.org/ --api-key $env:CHOCO_API_KEY

dotnet tool(グローバルとローカル)

dotnet tool は、.NET 開発者にとって最もシンプルな配布方法です。ツールは NuGet パッケージとして配布されます。

ツールのパッケージングに向けたプロジェクト構成
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>

    
    <PackAsTool>true</PackAsTool>
    <ToolCommandName>mytool</ToolCommandName>
    <PackageId>MyOrg.MyTool</PackageId>
    <Version>1.2.3</Version>
    <Description>A CLI tool for managing widgets</Description>
    <Authors>My Org</Authors>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/myorg/mytool</PackageProjectUrl>
    <PackageReadmeFile>README.md</PackageReadmeFile>
  </PropertyGroup>

  <ItemGroup>
    <None Include="../../README.md" Pack="true" PackagePath="/" />
  </ItemGroup>
</Project>
ビルドと公開
# Pack the tool
dotnet pack -c Release

# Publish to NuGet.org
dotnet nuget push bin/Release/MyOrg.MyTool.1.2.3.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY"
dotnet ツールのインストール
# Global tool (available system-wide)
dotnet tool install -g MyOrg.MyTool

# Local tool (per-project, tracked in .config/dotnet-tools.json)
dotnet new tool-manifest  # first time only
dotnet tool install MyOrg.MyTool

# Update
dotnet tool update -g MyOrg.MyTool

# Run local tool
dotnet tool run mytool
# or just:
dotnet mytool
グローバルツールとローカルツール
項目グローバルツールローカルツール
スコープシステム全体(ユーザー単位)プロジェクトディレクトリ単位
インストール先~/.dotnet/tools.config/dotnet-tools.json
バージョン管理手動で更新ソース管理で追跡
CI/CD使用前にインストールが必要dotnet tool restoreですべてを復元
最適な用途個人の生産性向上ツールプロジェクト固有のビルドツール

NuGet での配布

NuGet パッケージとして配布されるツール(dotnet toolまたはスタンドアロン)の場合:

パッケージメタデータ
<PropertyGroup>
  <PackageId>MyOrg.MyTool</PackageId>
  <Version>1.2.3</Version>
  <Description>A CLI tool for managing widgets</Description>
  <Authors>My Org</Authors>
  <PackageLicenseExpression>MIT</PackageLicenseExpression>
  <PackageProjectUrl>https://github.com/myorg/mytool</PackageProjectUrl>
  <PackageReadmeFile>README.md</PackageReadmeFile>
  <PackageTags>cli;tools;widgets</PackageTags>
  <RepositoryUrl>https://github.com/myorg/mytool</RepositoryUrl>
  <RepositoryType>git</RepositoryType>
</PropertyGroup>
NuGet.org への公開
# Pack
dotnet pack -c Release -o ./nupkgs

# Push (use env var for API key -- never hardcode)
dotnet nuget push ./nupkgs/MyOrg.MyTool.1.2.3.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY"
プライベートフィードでの配布
# Push to a private feed (Azure Artifacts, GitHub Packages, etc.)
dotnet nuget push ./nupkgs/MyOrg.MyTool.1.2.3.nupkg \
  --source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
  --api-key "$AZURE_ARTIFACTS_PAT"

パッケージ形式の比較

形式プラットフォーム.NET が必要自動更新難易度
Homebrew formulamacOS、Linuxいいえ(バイナリタップ)brew upgrade中
apt/debDebian/Ubuntuいいえ(AOT バイナリ)apt リポジトリ経由中
wingetWindows 10 以降いいえ(ポータブル)winget upgrade中
ScoopWindowsいいえ(ポータブル)scoop update低
ChocolateyWindowsいいえchoco upgrade中
dotnet toolクロスプラットフォームはい(SDK)dotnet tool update低
NuGet(ライブラリ)クロスプラットフォームはい(SDK)NuGet の復元低

エージェント向けの注意点

  1. パッケージマニフェストに SHA-256 ハッシュをハードコードしないでください。 プレースホルダー値ではなく、実際のリリース成果物からチェックサムを生成してください。すべてのパッケージマネージャーは、ダウンロードしたファイルに対してチェックサムを検証します。
  2. winget のポータブル CLI ツールにInstallerType: exeを使用しないでください。 スタンドアロン実行ファイルには、NestedInstallerType: portableを指定したInstallerType: zipを使用してください。exeタイプは、サイレントインストール用フラグを持つインストーラーを意味します。
  3. dotnet tool プロジェクトでPackAsToolを忘れないでください。 <PackAsTool>true</PackAsTool>がない場合、dotnet packはインストール可能なツールではなく、ライブラリパッケージを生成します。
  4. パッケージ化スクリプトに API キーをハードコードしないでください。 環境変数の参照($NUGET_API_KEY、$env:CHOCO_API_KEY)を使い、CI のシークレット設定についてのコメントを記載してください。
  5. 同じ CLI ツールに対して Homebrew formula と cask を併用しないでください。 純粋な CLI ツールには formula を使用してください。cask は、macOS アプリバンドルを含む GUI アプリケーション向けです。
  6. Homebrew formula のtestブロックを省略しないでください。 Homebrew CI は formula のテストを実行します。テストブロックがないと、レビューで却下されます。最低限、--versionの出力をテストしてください。

参考資料

コメント