GitHub Package Registry を npm で使う


GitHub Package Registry を npm で使うためのノウハウをここにまとめます。

Github Package Registry?

名前の通り Github でソフトウェアパッケージ(ライブラリ)をホスティングできるサービスです。 npm とか Ruby Gem とか Maven とかのプライベートなサーバーを用意できるサービスと考えると分かりやすいかもしれません。

公式のドキュメントは About GitHub Package Registry - GitHub Help くらいのようです。

しくみ

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 ヘルプ に従い、個人アクセストークンを作成します。

誤操作で変なバージョンを公開しちゃったりするのを防止するためにも、権限(スコープ)はなるべく少なくしたほうが良いでしょう。 reporead: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 で一つのレポジトリから複数のパッケージを公開したい場合の方法も解説されています。-> Configuring NPM for use with GitHub Package Registry - GitHub Help

その他、本家 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 が自動的に生成されるようです。

パッケージを削除する

要約すると、 public なレポジトリのパッケージは削除できない。 private なレポジトリのパッケージは現在のところ GraphQL API からのみ削除できる。 ということになります。少し試してみましたが、 public なレポジトリを一時的に private にして削除するのはアリのようです(でも、 public なら本家 npmjs に公開するだろうし、あんまり気にしないでいいかな?)。

試したときに使ったクエリをメモしておきます。

  1. レポジトリを private に変更する
  2. 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
          }
        }
      }
    }
  }
}  
  1. GraphQL APIの deletePackageVersion ミューテーションで削除する(パッケージのバージョンが複数ある場合にはこの操作を繰り返す)
mutation {
  deletePackageVersion(input: {
    packageVersionId: PACKAGE_VERSION_ID
  }) {
    clientMutationId
    success
  }
}

GraphQL APIから削除できると言っても RegistryPackageVersion.deleted というフラグがGraphQLスキーマに追加されているように、一覧から見えなくなるだけでgithub内部にデータは残り続けるようです。そのため、削除したものと同じバージョン番号での npm publish はエラーになります。