LoginSignup
35
17

More than 1 year has passed since last update.

あの時の俺に言いたい。NPMにpublishしたら(ほぼ)消せないことを

Last updated at Posted at 2021-12-14

この記事はタイムリープTypeScript 〜TypeScript始めたてのあの頃に知っておきたかったこと〜
15日目の記事です。

みなさんはnpmにパッケージをpublishしたことがありますか?私はあります。
このNPM、実は一度publishしたパッケージはpublishしてから72時間以内でないと非常に削除がしづらくなります。一応削除するためにはnpm unpublishというコマンドがあるのですが、そのパッケージがpublishされてから72時間以内かどうかで対応が変わります。

npm Unpublish Policy
ここに説明があるのですが、72時間以内であれば

For newly created packages, as long as no other packages in the npm Public Registry depend on your package, you can unpublish anytime within the first 72 hours after publishing.

つまり、npmの他の(publicである)パッケージが依存していない限り削除できます。一方72時間を超えると

Regardless of how long ago a package was published, you can unpublish a package that:
- no other packages in the npm Public Registry depend on
- had less than 300 downloads over the last week
- has a single owner/maintainer

npmのpublicであるパッケージが依存しておらず、直近1週間のダウンロード数が300未満であり、オーナーまたはメンテナーが1人でなければ削除できません。

組織内で使う共通ライブラリやビジネスロジックなどを誤ってpublishしてしまうと迅速にunpublishしない限り非常に削除しづらくなってしまいます。

👶ではどうすればいいんですか

このようなデジタルタトゥーをこれ以上生み出さないためにも今回紹介するのはnpmではなくGitHubのパッケージレジストリ、その名もGitHub Package Registry(以下GPRと称します)にパッケージをGitHub Actionsからpublishし、それを使用する方法を紹介いたします。

GPRにpublishする

publishするためには大まかには以下の手順になります。

  1. package.jsonのname@xxx(スコープ)を追加する
  2. package.jsonのprivateをfalseにする
  3. package.jsonにpublishConfigを書き込む

package.jsonのname@xxx(スコープ)を追加する

パッケージの名前をyyyから@xxx/yyyに変更します。一般的にxxxはパッケージのオーナーの名前を使い、常に@から始まります。

例: "name": "awesome-package" -> "name": "@jamashita/awesome-package"

package.jsonのprivateをfalseにする

これはnpmにパッケージを登録するときと同じです。

例: "private": true -> "private": false

package.jsonにpublishConfigを書き込む

以下を追加します。

"publishConfig": {
  "access": "restricted",
  "registry": "https://npm.pkg.github.com/"
}

accessについてはpublicパッケージにしたければpublicにし、privateパッケージにしたければrestrictedに設定します。

あとはGitHub ActionsでGPRにpublishするjobを設定します。以下はそのサンプルです。

jobs:
  release:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16.0
          registry-url: https://npm.pkg.github.com
          scope: '@xxx'
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - run: npm install
      - run: npm publish
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}

普通のpublishを行うときと異なるのは4点です。

actions/setup-node@v2registry-url

ここでpublishする向き先をhttps://npm.pkg.github.comに変更します。

actions/setup-node@v2scope

package.jsonで指定した@xxx(スコープ)を指定します。

actions/setup-node@v2env.NODE_AUTH_TOKEN

ここには${{ secrets.GITHUB_TOKEN }}を設定します。

publishするときのenv: NPM_TOKEN

NPM_TOKEN${{ secrets.GITHUB_TOKEN }}を設定します。

これでGPRにGitHub Actionsを使ってパッケージをpublishできるようになりました。

GPRのパッケージを取得する

GPRに登録されたパッケージを取得するには以下の手順が必要になります。

  1. read:packages権限のPersonal access token(以下PATと称します)を取得する
  2. ~/.npmrcに先ほどのPATを書き込む
  3. 使用したいプロジェクトの.npmrcにスコープの参照先を変更するよう記述する

read:packages権限のPersonal access tokenを取得する

PATはユーザーのSettings > Developer settings > Personal access tokensで取得できます。このときの権限は上述のとおりread:packagesのみです。

~/.npmrcに先ほどのPATを書き込む

~/.npmrcに取得したPATを書き込みます。PATをxxxxyyyyzzzzとした場合、以下の一文を追加してください

//npm.pkg.github.com/:_authToken=xxxxyyyyzzzz                                                                                                         

使用したいプロジェクトの.npmrcにスコープの参照先を変更するよう記述する

使用したいプロジェクトのルートディレクトリに.npmrcを置き、以下の一文を加えます。

@xxx:registry = https://npm.pkg.github.com

@xxxはスコープです。こうすることによってこのスコープが付けられたパッケージだけはGPRにパッケージを探しに行くようになります。

これで通常どおりnpm installでGPRに登録されたパッケージを使うことができるようになります。

登録したパッケージをGitHub Actionsで使いたい

CIなど、GitHub Actionsで登録したパッケージを使いたいときがあります。そのときは登録したパッケージがGPRにあることをGitHub Actionsに教えてあげないとたとえ使う側、使われる側が同じオーナーであってもパッケージをインストールすることができません。そこで以下のようにします。

read:packages権限のPATを取得する

これは上述のGPRのパッケージを取得するread:packages権限のPersonal access tokenを取得すると同じです。

PATを使う側のプロジェクトのSecretsに追加する

使う側のプロジェクトにあるSettings > Secretsに先ほどのPATを追加します。

GitHub Actionsで先ほど登録したPATを参照してnpm installをする

追加したPATの名前がGPR_TOKENならGitHub Actionsのjobは以下のようになります。

jobs:
  ci:
    runs-on: 'ubuntu-latest'
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16.0
          registry-url: https://npm.pkg.github.com
          scope: '@xxx'
      - run: npm install
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GPR_TOKEN }}
      - run: npm test

特筆すべきところは1点です。

npm install時にenv.NODE_AUTH_TOKENを設定する

ここで先ほど取得したPATの名前の前にsecrets.を加えます。するとGitHub Actionsは@xxxのスコープのパッケージをGPRから取得できるようになります。

🤖個人だけではなく組織でも使いたい

組織の場合、個人のようにPATを取得することができません。ではGPRを使ったパッケージ管理ができないかというとできます。方法は簡単で組織に属しているメンバーの誰かがPATを取得し、同じようにすることでGitHub Actionsでパッケージの取得ができるようになります。
このときPATをプロジェクトのSecretsに加えても、組織のSecretsに加えても同様に機能します。

🧟注意すること

  1. GPRにあるパッケージはNPMと異なり削除が容易です。誤って消してしまったり組織のメンバーの謀反に遭うとパッケージが消える恐れがあります
  2. できるだけ辞めなさそうな組織のメンバーにPATを取得してもらってください
35
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
17