Azure DevOps Serverでの独自パッケージ管理

# TL;DR

- .NET Frameworkで作成した既存のクラスライブラリを、Azure DevOps Server（オンプレ）のAzure Artifactsを利用し独自パッケージ管理を行うフィードへの登録までの手順を記載します。
- 検証したプロジェクトはVB.NETのクラスライブラリ（.NET Framework 4.0）です
    - C#でも同様と思われます。また、.NET Coreでは[パッケージ作成までVisual Studioから行えます](https://news.mynavi.jp/article/zeroazure-29/)。
- 基本的な手順は、スペックファイルの作成、パッケージの作成、そしてプッシュの3ステップです。

# 環境

- Azure DevOps Server 2019 Update 1（Update 1.1 Patch 2）
- Nuget 5.7.0.6726
- Visual Studio 2019


# 手順

## 事前準備

### 1. nuget.exeの準備

NuGetパッケージを作成するには、nuget.exeを使います。以下のページから、Windows用のツールをダウンロードします。

https://www.nuget.org/downloads

適当なフォルダに配置し、フォルダへのパスを通しておきます。

### 2. プッシュ用のフィードの作成

マイナビの[「Azure DevOps」でチーム開発を行おう(5)Azure Artifactsを使ったパッケージ管理](https://news.mynavi.jp/article/zeroazure-29/)の「パッケージをAzure Artifactsに登録する」に従い、Azure Artifactsのフィードを作成します。

💡 プロキシ環境では「このフィードを経由してパブリックソースからパッケージを使用する」を選択すると、後述のNugetパッケージのプッシュでエラーが発生しました。対処として「このフィードに発行されているパッケージのみを使用する」を選択する必要がありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/adf253c7-98a7-89f7-9965-9b2f897492e9.png)

## ビルド～プッシュ

### 1. 対象クラスライブラリプロジェクトのビルド

Visual Studio 2019で対象ソリューションを開き、対象クラスライブラリプロジェクトがReleaseビルドできることを確認します。

💡 検証したプロジェクトはVB.NETのクラスライブラリ（.NET Framework 4.0）のプロジェクト（`.vbproj`）です。

### 2. Releaseビルドファイルの入れ替え

**必須の作業ではありません。**

もし既にReleaseビルドを別の方法で管理している場合[^1]は、`bin\Release`のファイルを先に入れ替えておきます。

[^1]: リポジトリにてバイナリを管理している、共有サーバーでファイル管理しているなど。


💡 パッケージファイル（`.nupkg`）に含むファイルと既存で管理しているファイルと整合性を保つことが目的です。

### 3. スペックファイルの作成

コマンドプロンプトでプロジェクトファイル（`.vbproj`） のフォルダに移動し、以下を実行します。

```bat
nuget spec
```

[公式ドキュメント](https://docs.microsoft.com/ja-jp/nuget/reference/nuspec)を参考に作成された（`.spec`）ファイルを編集します。

特に以下の属性にご注意ください。

- `version`: 既定ではプロジェクトのバージョンを参照します。編集する場合は、[公式ドキュメントの説明](https://docs.microsoft.com/ja-jp/nuget/concepts/package-versioning)を参考に記述します。また[ワイルドカードの使用](https://tsuna-can.hateblo.jp/entry/2019/07/28/014330#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%95%AA%E5%8F%B7%E3%81%AB%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88)には注意が必要です。
- `description`: フィードページに表示される説明です。

またプロジェクトの出力アセンブリ**以外**を含めたい場合には以下のような形とします。

<details><summary>対象が.NET Framework 4.0の場合のspecファイル例。</summary><div>

```xml
<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
  ～
  </metadata>
  <files>
    <file src="bin\Release\*.dll" target="lib\net40" />
    <file src="bin\Release\*.xml" target="lib\net40" />
  </files>
</package>
```

</div></details>

### 4. パッケージの作成

以下を実行して、Release構成のNugetパッケージ（`.nupkg`）を作成します。

```bat
nuget pack -p Configuration=release
```

💡 属性のスペルミス（例：Configu **l** ation）があると、エラーは表示されずに既定値のDebug構成をパッケージしますのでご注意ください。
💡 Nugetパッケージ（`.nupkg`）はZIPファイルのため展開して確認できます。

### 5. プッシュ

フィードページにアクセスし「フィードに接続する」を選択して記載の内容に従います。

**作成したフィードをNugetに追加（初回時のみ）**

```bat
nuget.exe sources Add -Name "<フィード名>" -Source "http://<Azure DevOps ServerのコレクションURL>/_packaging/<フィード名>/nuget/v3/index.json"
```

**作成したフィードをプッシュ**

```bat
nuget.exe push -Source "<フィード名>" -ApiKey AzureDevOps <作成したパッケージ>.nupkg
```

💡 プロキシ環境では「このフィードを経由してパブリックソースからパッケージを使用する」を選択したフィードにプッシュするとエラーが発生しました。

<details><summary>エラー</summary><div>

`http://<Azure DevOps ServerのURL>/_oi/_diagnostics/activityLog`にアクセスして確認。
参考：https://azukipochette.hatenablog.com/entry/2019/12/25/083058

**内容**

```
インデックス	名前	値
-2	ExceptionMessage	アップストリーム パッケージ ソース 'https://api.nuget.org/v3/index.json' からデータを取得できませんでした: An error occurred while sending the request.
```

</div></details>

# 関連

- [ゼロからはじめるAzure(29) 「Azure DevOps」でチーム開発を行おう(5)Azure Artifactsを使ったパッケージ管理 | マイナビニュース](https://news.mynavi.jp/article/zeroazure-29/)
- [.NET FrameworkのNuGetパッケージを作成する - ツナ缶雑記](https://tsuna-can.hateblo.jp/entry/2019/07/28/014330)
- [NuGet CLI パックコマンド | Microsoft Docs](https://docs.microsoft.com/ja-jp/nuget/reference/cli-reference/cli-ref-pack)
- [NuGet CLI ソースコマンド | Microsoft Docs](https://docs.microsoft.com/ja-jp/nuget/reference/cli-reference/cli-ref-sources)
- [NuGet の nuspec ファイルリファレンス | Microsoft Docs](https://docs.microsoft.com/ja-jp/nuget/reference/nuspec)