[gem編] GitHub Package Registry (beta) を使ってみる

beta アクセスの invitation が届いていたのでテストしてみます。

# GitHub Package Registry
https://help.github.com/ja/articles/about-github-package-registry

> GitHub パッケージレジストリ はソフトウェアパッケージホスティングサービスで、npmjs.org、rubygems.org、hub.docker.com に似ており、あなたがパッケージとコードを一カ所でホストできるようにします。 ソフトウェアパッケージをプライベートでもパブリックでもホストでき、それらをプロジェクト中で依存関係として利用できます。

### 対応しているパッケージクライアント

\* 2019年7月5日時点

| パッケージクライアント | パッケージフォーマット |
|:--|:--|
|npm (Node)|package.json|
|gem (Ruby)|Gemfile|
|mvn (Java)|pom.xml|
|docker|container|
|nuget (.NET)|nupkg|

# gem package を GitHub Package Registry に公開する

## GitHub の設定

### Personal access token に権限を追加

GitHub Package Registry を使うには personal access token に対して `read:packages` `write:packages` の scope を新たに追加する必要があります。
https://github.com/settings/tokens から当該の token を選択し、下記を選択します。

\* パッケージの公開先が private repo の場合には、下記に加えて `repo` の scope も必要です。

![Screen Shot 2019-07-05 at 10.37.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19942/7984ba74-789f-59ea-fa36-b41781f6a884.png)

## gem & bundle の設定

複数の token を管理するため、`keycutter`をインストールします。

```
$ gem install keycutter
```

先程 scope 設定を変更した personal access token を `~/.gem/credentials` に設定します。

```
---
:github: Bearer ${TOKEN}
```

bundler の設定をします。
`OWNER` は公開したい gem パッケージの repository を実際に保持している GitHub ユーザー、または組織アカウントの名前です。続けて GitHub の username, personal access token をここでも入力します。

```
$ bundle config https://rubygems.pkg.github.com/OWNER(or ORG) USERNAME:TOKEN
```

## パッケージを公開 (gem push) する

### 注意事項

#### 公開したパッケージは削除できない
現状、GitHub Package Registry では一度公開した pacakge を削除することはできないとのことです。
また、公開済みの特定のバージョンの削除も同様にサポートされていません。gem パッケージだけ？と思って他のパッケージの場合も確認してみましたが、ドキュメント上では全て削除には対応していない同様の文言でした。

> あなたのパッケージに依存しているかもしれないプロジェクトを壊すことがないよう、GitHub パッケージレジストリはパッケージの削除や、パッケージのバージョンの削除をサポートしていません。法的な理由やGDPR標準といった特別な状況下では、GitHub Supportを通じてパッケージの削除をリクエストできます。連絡フォームを使って「GitHub パッケージレジストリ」というタイトル行でGitHub Supportに連絡してください。

#### パッケージの push 先 repository

GitHub Package Registry はデフォルトでは、gem の package name = GitHub repository name とみなしてパッケージを公開します。つまり、gemspec ファイルに下記の設定があるとすると、パッケージは `https://github.com/USER(or ORG)/mygem` に対して push されます。

```ruby
Gem::Specification.new do |s|
  s.name        = 'mygem'
  ...
```

え、名前一致してないんだけど、という場合は、push 先の repository を下記のように指定できます。
また、下記の設定を使うことで、名前の異なる複数の gem パッケージを単一の repository に対して公開することもできるようです。

```ruby
Gem::Specification.new do |s|
  s.name        = 'mygem'
  ...
  s.metadata = { "github_repo" => "ssh://github.com/USER(or ORG)/reponame" }
```

#### push した時の挙動

push されたパッケージは repository の `Releases` ページから確認ができます。
これまでの `Release` `Tags` に加えて、ここに `Packages` が加わります。

<img width="839" alt="Screen Shot 2019-07-05 at 10.58.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19942/9e696762-7f47-d507-ad1c-9e2599d8b473.png">

#### version の運用

特に何も考えずに `gem push` すると、デフォルトでは gemspec の version 情報を元に、もしまだ push 先の repository にその version の release/tag が存在していなければ、自動的に tag を切りその version で release まで作ってくれます。
この時の release の description は gemspec の description がそのまま適用されるようでした。

<img width="791" alt="Screen Shot 2019-07-05 at 11.21.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19942/0f894f5c-2c54-6964-0e83-33e6a5a5d72e.png">

もし push 先の repository にその version の release/tag が既に存在している場合、上記の画像のように、自動的にその release に対して package が紐付けられます。

### gem push

```
$ gem push --key github --host https://rubygems.pkg.github.com/USER(or ORG) mygem.gem
Pushing gem to https://rubygems.pkg.github.com/xxxx...
Successfully registered gem: mygem (x.x.x)
```

公開済みの version を再度 push するとエラーになります。

```
$ gem push --key github --host https://rubygems.pkg.github.com/USER(or ORG) mygem.gem
Pushing gem to https://rubygems.pkg.github.com/xxxx...
Error: Version x.x.x of "mygem" has already been pushed.
```

# GitHub Package Registry から gem をインストールする
`Gemfile` に新しく `source "https://rubygems.pkg.github.com/USER(or ORG)"` を追加する例がドキュメントに公開されています。
https://help.github.com/en/articles/configuring-rubygems-for-use-with-github-package-registry#installing-a-package

`gem install` の `--source` オプションでもいけるんですかね、未検証です。