NugetでリポジトリにAWS CodeArtifactを設定してみる。

# はじめに

これまでプライベートなパッケージリポジトリにはMyGetを別途契約して利用していたんですが、いつの間にかVisual Studioの`Nugetパッケージ マネージャー`メニューに追加されていたCodeArtifactでもいいんじゃない？ということで、とりあえずパッケージをホストして利用できるまでを確認してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/0d47721f-9524-093c-7c4c-60771e73ec48.png)

# CodeArtifact とは

AWS が提供するパッケージリポジトリで、AWSのIAMを使ったアクセス制御やEventBusなどのAWSの各種サービスとの連携が容易なのが特徴です。
https://aws.amazon.com/jp/codeartifact/

下記のパッケージマネージャーに対応していて、アップストリームに各パッケージマネージャーを指定可能です。
また、GitHubActionやAWS CodeBuildなどの各種CIとの連携も可能になっています。

- Maven
- npm
- Python
- Nuget

# ドメインとリポジトリの作成

パッケージをホストする入れ物を作成していきます。
GUIでの操作やドメインやリポジトリなどの言葉の定義はこちらの記事が参考になります。
[AWS CodeArtifact でプライベートリポジトリを作ろう](https://qiita.com/hayao_k/items/d55576a2920cb859901c)
ここではCLIで作業をしていきます。

ドメインの作成

```
❯ aws codeartifact create-domain --domain testpackage
{
    "domain": {
        "name": "testpackage",
        "owner": "6006XXXXXXXX",
        "arn": "arn:aws:codeartifact:ap-northeast-1:6006XXXXXXXX:domain/testpackage",
        "status": "Active",
        "createdTime": "2021-07-26T08:16:47.211000+09:00",
        "encryptionKey": "arn:aws:kms:ap-northeast-1:6006XXXXXXXX:key/e90d9369-9a27-4d43-97b2-7a98XXXXXXXX",
        "repositoryCount": 0,
        "assetSizeBytes": 0,
        "s3BucketArn": "arn:aws:s3:::assets-6006XXXXXXXX-ap-northeast-1"
    }
}
```

リポジトリの作成

```
 aws codeartifact create-repository --domain testpackage --repository dotnet
{
    "repository": {
        "name": "dotnet",
        "administratorAccount": "6006XXXXXXXX",
        "domainName": "testpackage",
        "domainOwner": "6006XXXXXXXX",
        "arn": "arn:aws:codeartifact:ap-northeast-1:6006XXXXXXXX:repository/testpackage/dotnet",
        "upstreams": [],
        "externalConnections": []
    }
}
```

NuGetをアップストリームに設定

```
aws codeartifact associate-external-connection --domain testpackage --repository dotnet --external-connection public:nuget-org
{
    "repository": {
        "name": "dotnet",
        "administratorAccount": "6006XXXXXXXX",
        "domainName": "testpackage",
        "domainOwner": "6006XXXXXXXX",
        "arn": "arn:aws:codeartifact:ap-northeast-1:6006XXXXXXXX:repository/testpackage/dotnet",
        "upstreams": [],
        "externalConnections": [
            {
                "externalConnectionName": "public:nuget-org",
                "packageFormat": "nuget",
                "status": "AVAILABLE"
            }
        ]
    }
}
```

# Visual Studioからの利用

Visual Studioに[AWS Toolkit for Visual Studio](https://docs.aws.amazon.com/ja_jp/toolkit-for-visual-studio/latest/user-guide/welcome.html)をインストールしてあれば、AWS Explorerから先ほど作成したCodeArtifactのドメインやリポジトリを参照できます。このリポジトリを利用するためには、コンテキストメニューから`Copy NuGet Source Endpoint`を選択してエンドポイントのURLをコピーし、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/30c999ee-5b9d-013e-f992-c90feed0b147.png)

ツール > NuGetパッケージ マネージャー > パッケージ マネージャー設定で表示されるNuGetのパッケージソース画面で先ほどのURLを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/74cc47d7-1ab2-e59f-23b4-b86e2dc2b11e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/ca23b5c5-29a5-f4bb-e3a1-260240455428.png)
NuGetの管理画面から、上で作成したCodeArtifactのパッケージソースを選択してパッケージをインストールすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/abfceb58-01f7-7ee2-f496-154a91e558a1.png)

# dotnet コマンドからの利用

dotnetコマンドでCodeArtifactを利用する方法は3つありますが、ここでは1つ目のパッケージのエンドポイントを設定する方法について説明します。他の方法を確認した場合は[AWSのドキュメント](https://docs.aws.amazon.com/ja_jp/codeartifact/latest/ug/nuget-cli.html)を参照してください。

- 方法 1: CodeArtifact 資格情報プロバイダーによる構成
- 方法 2: login コマンドで nuget または dotnet を設定する
- 方法 3: ログインコマンドなしでナゲットまたはドットネットを設定する

3つ目のログインコマンドなしで設定する方法はVisual Studioでエンドポイントを設定した方法に近くて良いのですが、ここで利用するトークンの期限は最大12時間という制限があるので注意してください。

## 方法 1: CodeArtifact 資格情報プロバイダーによる構成

dotnet コマンドに CodeArtifact 用のサブコマンドをインストールし、

```
❯ dotnet tool install -g AWS.CodeArtifact.NuGet.CredentialProvider
次のコマンドを使用してツールを呼び出せます。dotnet-codeartifact-creds
ツール 'aws.codeartifact.nuget.credentialprovider' (バージョン '1.0.0') が正常にインストールされました。
```
ローカルのAWSのクレデンシャル情報をコピーして、

```
❯ dotnet codeartifact-creds install
Existing installation found. Removing it
Uninstalling AWS CodeArtifact NuGet credential provider
Leaving configuration file
Installing AWS CodeArtifact NuGet credential provider to C:\Users\xxxxxxx\.nuget\plugins\netcore\AWS.CodeArtifact.NuGetCredentialProvider
Installing AWS CodeArtifact NuGet credential provider to C:\Users\xxxxxxx\.nuget\plugins\netfx\AWS.CodeArtifact.NuGetCredentialProvider
```
デフォルトで利用するAWSプロファイルを設定します。

```
❯ dotnet codeartifact-creds configure set profile lab
Setting configuration to use AWS profile named 'lab'
```

CodeArtifactのエンドポイントのURLを--sourceパラメーターに設定し、パッケージを取得します。

```
dotnet add package Serilog --source "$(aws codeartifact get-repository-endpoint --domain testpackage --repository dotnet --format nuget --query repositoryEndpoint --output text)v3/index.json"
  復元対象のプロジェクトを決定しています...
  Writing C:\Users\YoichiSugiyama\AppData\Local\Temp\tmp1DB2.tmp
info : パッケージ 'Serilog' の PackageReference をプロジェクト 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' に追加しています。
info :   CACHE https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v3/registration5-gz-semver2/serilog/index.json
info : C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj のパッケージを復元しています...
info : パッケージ 'Serilog' は、プロジェクト 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' のすべての指定されたフレームワークとの互換性があります。
info : ファイル 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' に追加されたパッケージ 'Serilog' バージョン '2.10.0' の PackageReference。
info : 復元をコミットしています...
info : アセット ファイルをディスクに書き込んでいます。パス: C:\temp\samplecodeartifactpackage\obj\project.assets.json
log  : C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj を復元しました (84 ms)。
```
んー、、、対話的に実行するのにこのコマンドはさすがに覚えられないですね。
先にパッケージソースを登録しておき、`dotnet nuget list source`コマンドでエンドポイントを参照してからコピペしたほうがよさそうですね。

```
❯ dotnet nuget list source
  1.  nuget.org [有効]
      https://api.nuget.org/v3/index.json
  2.  Microsoft Visual Studio Offline Packages [有効]
      C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\
  3.  codeartifact [有効]
      https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v3/index.json
dotnet add package serilog --source https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v3/index.json
  復元対象のプロジェクトを決定しています...
  Writing C:\Users\YoichiSugiyama\AppData\Local\Temp\tmp286B.tmp
info : パッケージ 'serilog' の PackageReference をプロジェクト 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' に追加しています。
info :   CACHE https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v3/registration5-gz-semver2/serilog/index.json
info : C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj のパッケージを復元しています...
info : パッケージ 'serilog' は、プロジェクト 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' のすべての指定されたフレームワークとの互換性があります。
info : ファイル 'C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj' に追加されたパッケージ 'serilog' バージョン '2.10.0' の PackageReference。
info : 復元をコミットしています...
info : アセット ファイルは変更されていません。アセット ファイルの書き込みを省略します。パス: C:\temp\samplecodeartifactpackage\obj\project.assets.json
log  : C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj を復元しました (78 ms)。
```

# パッケージをCodeArtifactに公開する

ここまでくれば、NuGetに公開する場合とほとんど一緒ですね。
パッケージ設定を諸々終わらせた後に、Releaseでパッケージして、

```
❯ dotnet pack -c Release
.NET 向け Microsoft (R) Build Engine バージョン 16.10.2+857e5a733
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  C:\temp\samplecodeartifactpackage\samplecodeartifactpackage.csproj を復元しました (119 ms)。
  samplecodeartifactpackage -> C:\temp\samplecodeartifactpackage\bin\Release\net5.0\samplecodeartifactpackage.dll
  パッケージ 'C:\temp\samplecodeartifactpackage\bin\Release\samplecodeartifactpackage.1.0.0.nupkg' が正常に作成されました。
```
こちらも source にCodeArtifactのエンドポイントを指定してpushすれば公開されます。

```
❯ dotnet nuget push .\bin\Release\samplecodeartifactpackage.1.0.0.nupkg --source https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v3/index.json
warn : 'https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v2/package' の API キーが指定されず、API キーが見つかりませんでした。ソースの API キーを保存するには、'setApiKey' コマンドを使用します。
samplecodeartifactpackage.1.0.0.nupkg を 'https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v2/package' にプッシュしています...
  PUT https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v2/package/
  Created https://testpackage-6006XXXXXXXX.d.codeartifact.ap-northeast-1.amazonaws.com/nuget/dotnet/v2/package/ 1626 ミリ秒
パッケージがプッシュされました。
```
ちょっと適当すぎますが公開されましたね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/af8c7c4e-bf85-14c2-b3fb-e2a08f921284.png)

あとはCodeBuildやGitHubActionなどを利用してCIに組み込めば、タグをつけたバージョンをCodeArtifactにPushするといったフローも作れそうですね。