🔄

自作 npm パッケージを Azure Artifacts へ手動デプロイおよび自動化

2024/02/26に公開

はじめに

npm の自作パッケージの作り方は以下の記事で書いた。そこで作ったパッケージを Azure Artifacts にデプロイする方法が今回の記事である。

https://zenn.dev/takanari_dev/articles/2024-02-22-npm-component-package

前提

すでに自作パッケージが Azure Repos 上のリポジトリとして存在し、それがローカルにgit clone済みであることを前提とする。またビルドまで済んでいるものとする。もし GitHub 上のリポジトリであれば以下のドキュメントを参考にして [Import repository] すれば、簡単に Azure Repos 上に複製できる。

https://learn.microsoft.com/ja-jp/azure/devops/repos/git/import-git-repository?view=azure-devops

Azure Artifacts の準備

Azure DevOps 側の準備をする。Azure Artifacts にフィードを用意する必要がある。

Azure DevOps のプロジェクトに入って、右のリストから Azure Artifacts をクリックする。 [Create Feed] から適当な名前でフィードを作成する。ここは以下の公式ドキュメントを見ながらやるのが良い。

https://learn.microsoft.com/ja-jp/azure/devops/artifacts/concepts/feeds?view=azure-devops

手動デプロイ

さて、手動デプロイについてだが、これが厄介である。以下の公式ドキュメントを参照するとわかるのは結構手間がかかりそうに見える。(あとホームディレクトリに.npmrcファイルを置かせようとするところがとても嫌だ。)

https://learn.microsoft.com/ja-jp/azure/devops/artifacts/get-started-npm?view=azure-devops&tabs=Other#setup-credentials

もちろん手動デプロイを避けて最初から自動デプロイをすれば良いと考えるかもしれないが、いずれにせよnpm installするときに似たようなことをやらなければならないので避けて通れないのでやるが、少しアレンジする。

スコープの設定

まず、パッケージにスコープをつける。例としてよく見かけるのが@babel/corebabelがスコープ名である。Azure Artifacts にはスコープをつけなくてもパッケージをデプロイできるが、実際にはスコープを設けたほうが内製ライブラリなのかそうでないのかがわかりやすくなり、またスコープに限定して Azure Artifacts から取得するようにできる。

https://learn.microsoft.com/ja-jp/azure/devops/artifacts/npm/scopes?view=azure-devops#scope-setup

したがって、これらに対応するためにまずはpackage.jsonを少し書き換える。

package.json
  {
+   "name": "@<スコープ名>/<パッケージ名>",
-   "name": "<パッケージ名>",
    ...
  }

<スコープ名>に制限はないが、Azure Artifacts のフィードのスコープとできるだけ対応が取れてわかりやすいものが良いだろう。

Personal Access Token の作成と.npmrcファイルの設定

ローカル環境の作業フォルダ直下に.npmrcファイルを作成し、以下の記述をしたい。

.npmrc
@<スコープ名>:registry=<フィードのnpm用URL>
always-auth=true
//<フィードのnpm用URLの'https://'以下>:username="<ユーザー名>"
//<フィードのnpm用URLの'https://'以下>:_password="<BASE64にエンコードしたPAT>"
//<フィードのnpm用URLの'https://'以下>:email=""
  • <スコープ名>

package.jsonnameのところと同じスコープ名にする。

  • <フィードのnpm用URL>

公式のドキュメントを見ると以下の二パターンであるが、[Connect to Feed] から URL を確認&コピーできる。(個人アカウントの場合 URL が異なるかもしれない。)

# プロジェクトスコープの場合
https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/registry/
# 組織スコープの場合
https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/registry/
  • <ユーザー名>

これは任意の文字列でよい。

  • <BASE64にエンコードしたPAT>

これの用意が手間である。PAT とは Personal Access Token の略で認証に必要なものであり、以下の記事を参考に取得する。PAT を発行する際 [Scope] のところは "Packaging" の項目を "Read, write, & manage" にチェックするだけで今回は問題ない。

https://learn.microsoft.com/ja-jp/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows

そうするとランダムのように見える文字列が発行されるので、それをコピーして以下のコマンド[1]<PAT>に入れ、BASE64 にエンコードする。

echo -n "<PAT>" | base64

そうすると別の文字列が CLI 上に出力されるので、それをコピーして.npmrcファイルに値を入れる。

デプロイ

以上の設定をした後、以下のコマンドでデプロイする。

npm publish

これで手動によるデプロイができた。

npm installしてみる

別のフォルダでnpm create vite@latestで React プロジェクトを新規に作成したあと、先ほど作った.npmrcファイルをコピーしてきて以下のコマンドを叩く。

npm install @<スコープ名>/<パッケージ名>

するとインストールできるので、importしてみて使えるかどうか確かめてみる。

import { ... } from "@<スコープ名>/<パッケージ名>";

デプロイ自動化

手動デプロイが少し複雑なうえにこれを毎回手元で行うのはミスもしやすくリスクがある。ということで次は Azure Pipelines を利用した自動化をしてみる。

パイプラインの準備

.azure-pipelinesフォルダを作成して、その中にdeploy.ymlを以下のように作成する。

.azure-pipelines/deploy.yml
trigger:
  branches:
    include:
      - main

pool:
  vmImage: "ubuntu-latest"

jobs:
  - job: "release"

    variables:
      PROJECT: $(System.TeamProject) # 組織スコープの場合不要
      FEED: npm-test-lib

    steps:
    - task: UseNode@1
      inputs:
        version: '20.x'
      displayName: 'Install Node.js'

    - script: |
        npm ci
      displayName: 'npm install'

    - script: |
        npm run build
      displayName: 'npm build'

    - task: Npm@1
      inputs:
        command: publish
        publishRegistry: useFeed
        publishFeed: $(PROJECT)/$(FEED) # 組織スコープの場合 $(PROJECT)/ が不要

基本的な流れは以下のようである。

  1. mainブランチにマージされたタイミングで発火する。
  2. Ubuntu 仮想環境を用意する。
  3. UseNode@1タスクを使用して Node.js をインストールする。
  4. npm ciで依存関係をインストールする。
  5. npm run buildでライブラリをビルドする。
  6. Npm@1タスクで Azure Artifacts にデプロイする。

このパイプラインを作成するにあたって参考にしたドキュメントは以下のとおり。

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/ecosystems/javascript?view=azure-devops&pivots=pipelines-yaml
https://learn.microsoft.com/ja-jp/azure/devops/pipelines/artifacts/npm?view=azure-devops&tabs=yaml

トリガー条件は下記のようにvからはじまるタグを切ったときだけにした方が望ましいかもしれない。

trigger:
  tags:
    include:
      - "v*"

手動デプロイのときと違い、Npm@1タスクが認証も含めてやってくれるので PAT を自前で用意する必要がない点が非常に便利である。

Azure Pipelines に登録する

.azure-pipelines/deploy.ymlのファイルをmainブランチにマージしてみると、実はパイプラインが発火しない。これは Azure Pipelines にこのファイルを登録してからでないと動作しないからである。なので、今回作成したファイルを登録する。

Azure DevOps のプロジェクトに入り、右のサービスリストから [Pipelines] > [Pipelines] のページを開く。
そのページにはおそらく [Create Pipeline] というのが表示されており、そのボタンを押す。

  1. Connect
    What is your code?と聞かれるので [Azure Repos Git] を選択する。

  2. Select
    Select a repositoryで自作パッケージのリポジトリ(catlib)を選択する。

  3. Configure
    Configure your pipelineではすでにあるパイプラインを参照するので [Existing Azure Pipelines YAML file] を選択し、Path を .azure-pipelines/test.ymlにする。

  4. Review
    [Run] を押して実行するか、[Run] の隣にマークがあり、それを押すと [Save] があるので、セーブするだけでもよい。

Azure Artifacts に Azure Pipelines からデプロイできるようにする

これで実行してみたいところだが、このまま実行しても実はうまくいかない。これは Azure Pipelines の実行系にフィードに対しての write 権限がないためである。

フィードの<プロジェクト名> Build Service (<組織ID>)に対してContributorのロールを付与することで解決できる。
以下の公式ドキュメントを参考にして設定すればよいが、少しわかりにくいのが [Permissions] のところで、すでにリストにある User/Group でも [Add users/groups] からロールを変えることである。

https://learn.microsoft.com/ja-jp/azure/devops/artifacts/feeds/feed-permissions?view=azure-devops#pipelines-permissions

実行

package.jsonversionを変更してmainブランチにマージして正常に終了すれば成功である。
フィードに置いてあるライブラリのversionも期待通りの値かも確認しておこう。

今後の課題

package.jsonversionと Azure Repos のtagを一致するように自動化できたら良い。

脚注
  1. Power Shell だと動かないと思われる。Windows でも Git を導入しているのであれば Git Bash も同梱してくるはずである。これを使えば Bash ライクに操作できる。https://qiita.com/alpaca-honke/items/c7516823671e499eac7d
    問題はパッケージのユーザーが顧客で Git 環境もない場合だが、配布側で PAT を Base64 にエンコードし、それを相手に教えれば良いだけである。 ↩︎

Discussion