GitHub Package Registry を npm で使うためのノウハウをここにまとめます。
Github Package Registry?
名前の通り Github でソフトウェアパッケージ(ライブラリ)をホスティングできるサービスです。 npm とか Ruby Gem とか Maven とかのプライベートなサーバーを用意できるサービスと考えると分かりやすいかもしれません。
公式のドキュメントは以下です。合わせてご覧ください。
しくみ
Github Package Registry に配置したパッケージを利用したいプロジェクトのルート( package.json があるディレクトリ)に次のような1行の .npmrc ファイルを作成しておきます。
registry=https://npm.pkg.github.com/OWNER
( OWNER
には github のアカウント名やチーム名が入ります。先頭に @
は不要です)
そうすると、npm install
等々のコマンドが npmjs.com ではなく、 GitHub Package Registry にアクセスするようになります。 GitHub Package Registry は、自分のところに無いパッケージは npmjs.com から取得してくれるので、いつもの npm
と同じ感覚で使いつつ、プライベートなパッケージも入れることができるようになります。
下準備
「いつもの npm
と同じ感覚で使える」と書きましたが、初回のみ若干の下準備が必要です。というのは npm.pkg.github.com にアクセスするにはログインが必要だからです。ログインは、 Github のユーザー名+パスワードではなく、 個人アクセストークン でおこないます。 npm install
npm ci
を実行するユーザーは全員、以下の手順で ~/.npmrc
に個人アクセストークンを設定しておく必要があります。
1. 個人アクセストークンを作成する
個人アクセストークンを使用する - GitHub Docs の「トークンの作成」に従い、個人アクセストークンを作成します。
誤操作で変なバージョンを公開しちゃったりするのを防止するためにも、権限(スコープ)はなるべく少なくしたほうが良いでしょう。 repo
と read:packages
だけで十分です。トークンの権限は後から修正することもできます。
2. ~/.npmrc
にログイン情報を記入する
echo "//npm.pkg.github.com/:_authToken=TOKEN" >> ~/.npmrc
TOKEN
には個人アクセストークンを入れます。もちろん、テキストエディタで ~/.npmrc
を修正してもOKです。
公式ドキュメントでは ~/.npmrc
を修正する方法と、 npm login
コマンドを使用する方法が並列で紹介されていますが、どちらでも同じ効果となります。 npm login
コマンドは同じように ~/.npmrc
を修正してくれるだけです。
3. ログインの確認
先ほどの .npmrc のあるディレクトリ(またはその子ディレクトリ)で npm whoami
を実行して、あなたのユーザー名が表示されることを確認してみてください。
以上で下準備は完了です。今度こそ、いつもの npm
と同じ感覚で使えます。
パッケージを登録する
以降はパッケージを登録・管理する人向けの解説となります。
1. 権限の追加
パッケージの管理を担当する人は、 write:packages
の権限も必要となります。 Github の Developer settings -> Personal access tokens のページから権限を追加するか、パッケージ登録用のトークンを別に作成してください。
2. package.json の修正
パッケージを公開する上で、いくつか package.json の修正が必要になります。
- パッケージ名は「
@
(オーナー名を小文字にしたもの)/
(レポジトリ名)」とする必要があります(@nuxtjs/vuetify
みたいな形式です。 scoped NPM package というやつらしい)。 package.json のname
を修正しましょう。 - 必須ではありませんが、 package.json に以下を追加しておきましょう。「誤って本家 npmjs に公開してしまった」みたいな問題を避けることができます。
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
}
- package.json の
repository
が間違っていないことを確認しましょう。 Github Package Registry はrepository
またはname
から対象レポジトリが判定されるため、誤っているとエラーとなります。
補足:公式では、いわゆる monorepo で一つのレポジトリから複数のパッケージを公開したい場合の方法も解説されています。
その他、本家 npmjs で公開する際の一般的な注意点が適用されます。 main
または bin
があるかとか、 version
は更新したかとか、 "private": true
になってないかとかです。その辺は適宜ググって qiita にでも聞いてください。
3. npm publish
あとは本家に公開するときと同じく npm publish
するだけです。
npm publish
misc
パッケージの public/private
※ ここは公式ドキュメントに記述が全然無いので、挙動からの推測となります。
You can host software packages privately or publicly and use them as dependencies in your projects.
と書いているわりにパッケージの public/private についての説明が一切ないので調べました。結論から言うと、 親であるレポジトリの public/private に依存して見えるか否かが変わる ようです。
まず、本家が参考情報としてしかレポジトリ情報を持っていないのとは異なり、 Github Package Regisry では「Github レポジトリがパッケージを持っている」という関係性になっているようです。そのため、 Github レポジトリではないソースからパッケージを作ることはできません。この「どのレポジトリから作られたパッケージか?」というのは、前述のように package.json の repository
および name
から判定されています。
GraphQL API で見ても RegistryPackage
型は public/private のフラグを持っていないので、親であるレポジトリのステータスに依存すると考えて良さそうです。
すなわち、 .npmrc が以下のようだったなら、、
registry=https://npm.pkg.github.com/OWNER
- OWNER の public レポジトリに属するパッケージは見える
- OWNER の private レポジトリのうち権限を付与されているものに属するパッケージは見える
- 本家 npmjs で公開されているパッケージは、全部見える
ということになります。ぐだぐだ書きましたが 「レポジトリが見えるならそのパッケージも見える」 ということで、レポジトリと親子関係を持っていることさえ理解すれば割とシンプルです。
補足になりますが、
- OWNER 以外が publish したパッケージは、 public レポジトリであっても 見えない
という点は注意しないといけないかも知れません。複数のOWNERのパッケージを使う方法についても公式に書いてあります. -> Installing packages from other organizations
CodeBuild, etc
CI/CD サービスの中ででも ~/.npmrc
ファイルを作成することで Github Package Registry にアクセスできるようになります。
echo "//npm.pkg.github.com/:_authToken=TOKEN" >> ~/.npmrc
npm ci # or, npm install
Github Actions
Github Actions では、あらかじめ Github Package Registry にアクセスする権限を持ったトークンが secrets.GITHUB_TOKEN
にセットされています。それを actions/setup-node と組み合わせて使います。
- uses: actions/setup-node@v1
with:
registry-url: https://npm.pkg.github.com/
scope: '@your-github-username'
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
NODE_AUTH_TOKEN
という環境変数が出てきますが、これは Github Actions 独自の仕組みです。 actions/setup-node で Node.js をセットアップすると、この環境変数を参照する ~/.npmrc
が自動的に生成されるようです。
パッケージを削除する
現在はGraphQLを使わなくとも、Web上からも削除できるようになりました。(2022/07/25 追記)
要約すると、 public なレポジトリのパッケージは削除できない。 private なレポジトリのパッケージは現在のところ GraphQL API からのみ削除できる。 ということになります。少し試してみましたが、 public なレポジトリを一時的に private にして削除するのはアリのようです。 Github Pacage Registry を使う理由はプライベートなレポジトリが欲しいからという人が多いだろういし、あんまり気にしないでいいかもしれません。
試したときに使ったクエリをメモしておきます。
- レポジトリを private に変更する
- GraphQL APIでpackageVersionIdを調べる
query {
repository(owner: OWNER, name: PACKAGE_NAME){
id
name
registryPackages(first: 10, publicOnly: false) {
nodes {
id
name
versions(first: 10) {
nodes {
id
version
}
}
}
}
}
}
- GraphQL APIの
deletePackageVersion
ミューテーションで削除する(パッケージのバージョンが複数ある場合にはこの操作を繰り返す)
mutation {
deletePackageVersion(input: {
packageVersionId: PACKAGE_VERSION_ID
}) {
clientMutationId
success
}
}
GraphQL APIから削除できると言っても RegistryPackageVersion.deleted
というフラグがGraphQLスキーマに追加されているように、一覧から見えなくなるだけでgithub内部にデータは残り続けるようです。そのため、削除したものと同じバージョン番号での npm publish
はエラーになります。