GitHub Organizationから専用のNode.jsのパッケージを展開する

## はじめに
この記事ではGitHub Organization内でのみ利用可能なNode.jsのパッケージを公開する方法を紹介します。

:::note info
パッケージはGitHub内の権限などを活用して公開するため、通常の[npm public registry](https://registry.npmjs.org)に公開するのではなく、GitHub Packagesのnpm registryに公開します。

GitHub Packagesでnpm private registryを利用するには、GitHub Team等のプランに加入する必要があります。利用できる環境にあるか確認してからお試しください。
:::

## パッケージを公開する
### 準備
公開するNode.jsのプロジェクトを準備します。今回は簡単のため2つの数値を足し合わせるプログラムを公開することを考えます。
ますはNodejsのプロジェクトの初期化を行います。対象のディレクトリで以下のコマンドを叩いてください。
```sh
npm init
```
名前は`@NAMESPACE/add_number`のようにGitHub Organizationの名前でスコープを作ってあげます。`repository`はプロジェクトを置くリポジトリのURLが`https://github.com/XXX/YYY`の場合、`https://github.com/XXX/YYY.git`のようにしてください。
他の質問はそれぞれのプロジェクトにあった回答をしてください。
今回紹介する例では`entry point`をデフォルトの`index.js`としたので以下のようなコードを`index.js`に記述します(ES Modulesで書いたので`package.json`には`"type": "module"`を追加しています)。
```index.js
export const add = (a, b) => a + b;
```
これを他のプロジェクトから`npm i @NAMESPACE/add_number`で利用できるようにします。

### ローカルからパッケージを公開する
まずは、GitHub Packagesへの認証をします。ローカルからは`personal access token (classic)`を用いた認証をします。
[GitHubの開発者設定ページ](https://github.com/settings/apps)から「Personal access tokens」の「Tokens（classic）」を選択します。
![スクリーンショット 2024-02-02 18.13.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/bb9307b6-cb73-fa42-26df-a455cb7a8335.png)
そして、「Generate new token」をクリックして「Generate new token（classic）」を選択します。
![スクリーンショット 2024-02-02 18.14.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/5fa64f51-f7ce-5599-7d3f-2c3fa1c04640.png)
選択するとパスワードの入力を求められたのちに、トークンの設定画面に遷移します。
有効期間を設定して、「Select scopes」で「write:packages」を選択すると今回必要なトークンが生成されます。
トークンの準備ができたら、npmにログインを行って、GitHub Packagesへの認証を開始します。
```sh
npm login --scope=@NAMESPACE --auth-type=legacy --registry=https://npm.pkg.github.com
```
上記のように入力すると、「Username」と「Password」を聞かれます。「Username」はGitHubのユーザー名を、「Password」には先ほど生成したトークンを渡してください。

認証が完了したら、GitHub Organizationのレジストリーをnpmに教えてあげます。`.npmrc`に以下の文字列を追加してください(ない場合は作ってください)。
```:.npmrc
@NAMESPACE:registry=https://npm.pkg.github.com
```
`@NAMESPACE`のスコープについてはGitHub Packagesのレジストリに問い合わせさせるような設定です。
ここまで完了したら一度リポジトリに内容を同期させてください。
最後に、`npm publish`を行えば`@NAMESPACE/add_number`というパッケージが公開されているはずです。公開されていることはGitHub OrganizationのPackagesタブで確認可能です。
![スクリーンショット 2024-02-02 18.25.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/88271d3f-2136-371f-1e6e-1dcf3f39c6b2.png)


### GitHub Actionsでパッケージを公開する
次に、GitHub Actions経由でパッケージを公開する方法を紹介します。
GitHub Actions経由でパッケージを公開する場合はGitHub Packagesへの認証は`GITHUB_TOKEN`を通じて行えます。
mainブランチへpushされた時に公開するためには以下のように書きます。

```yml:publish.yml
name: Publish package to GitHub Packages
on:
  push:
    branches:
      - main

jobs:
  publish:
    runs-on: ubuntu-latest
    env:
      NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          registry-url: 'https://npm.pkg.github.com'
          scope: '@NAMESPACE'
      - name: Publish
        run: npm publish
```
環境変数として、`NODE_AUTH_TOKEN`に`GITHUB_TOKEN`を設定して、リポジトリの読み込みとGitHub Packagesへの書き込みを`permissions`で設定しています。また、`actions/setup-node`では`registry-url`でGitHub Packagesへのレジストリを指定して、`scope`で`@NAMESPACE`に反映させています。
これを適用することで`package.json`に設定されたバージョンの公開を`main`ブランチに`push`したタイミングで行うようになります。

多くの場合ビルドなどのステップが`npm publish`前に必要となりますが、それらは`npm publish`前にそのまま記述するだけで多くの場合利用できます。

## パッケージを利用する
### ローカルでパッケージのインストールと利用を行う
[ローカルからパッケージを公開する](#ローカルからパッケージを公開する)と同じように`personal access token (classic)`を用いた認証をします。詳しい手順は[ローカルからパッケージを公開する](#ローカルからパッケージを公開する)を参照してください。
先ほどはトークンの生成時に「Select scopes」で「write:packages」を選択しましたが、今回は読み込むだけなので「read:packages」で十分です。

認証が完了したら`.npmrc`に先ほど同様`@NAMESPACE`のレジストリを伝えるものを加えます(存在しない場合は作ってください)。
```:.npmrc
@NAMESPACE:registry=https://npm.pkg.github.com
```

`.npmrc`の編集まで完了したら通常のパッケージの導入と同じようにプロジェクトで利用可能になります。
```sh
npm i @NAMESPACE/add_number
```

### GitHub Actionsでパッケージのインストールと利用を行う
リポジトリへpushされるたびにNodeプロジェクトを読み込んで、`npm test`を行うようなGitHub Actionsを作っていきます。

まず、GitHub Actionsを実行するリポジトリから対象のパッケージを読み込むための設定をします。
今回の条件では`https://github.com/orgs/NAMESPACE/packages/npm/add_number/settings`から設定できます。
UIからはGitHubのOrgnanizationのPackagesタブから対象のパッケージを選択して、
![スクリーンショット 2024-02-02 18.25.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/88271d3f-2136-371f-1e6e-1dcf3f39c6b2.png)
開かれた画面の右側に「Package settings」があるのでそこをクリックすると同じ画面に行けます。
![スクリーンショット 2024-02-02 18.50.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/4f93267d-b2be-feb9-5132-6a1a098d6cd8.png)

設定画面にたどり着いたら「Manage Actions access」というところで「Add Repository」で対象のリポジトリに対して「Read」権限を付与します。
![スクリーンショット 2024-02-02 18.52.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/7a498752-d93d-d48d-4d5b-0e92e72f5238.png)

そして、環境変数に`NODE_AUTH_TOKEN`で`GITHUB_TOKEN`を設定した状態と、`setup-node`で`@NAMESPACE`のレジストリをGitHub Packagesにするようにymlに書き込めば、GitHub Actionsでパッケージのインストールを行えます。
```yml:test.yml
name: test

on: push

jobs:
  frontend:
    runs-on: ubuntu-latest
    env:
      NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Checkout branch
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          registry-url: https://npm.pkg.github.com/
          scope: "@NAMESPACE"
      - name: Install dependencies
        run: npm ci
      - name: Run test
        run: npm test
```
権限がない場合は`npm ci`が行えないのでManage Actions accessを設定することを忘れないようにしましょう。

## おわりに
GitHub Organizationから専用のNode.jsのパッケージを展開する方法を紹介しました。
GitHub Packagesへの認証が必要な点など管理する上で大変な点はいくつかありますが、GitHub Organization内だけで利用するパッケージを作ることで開発の幅が広がるので機会があれば試してみてください。