👏

monorepoでPR中のコードをnpmパッケージとしてcanary releaseするGitHub Actions

2021/07/30に公開

lernaなどを使ってmonorepoでライブラリを開発している場合に、パッケージの動作を実際のアプリケーションに組み込んでテストしたいことがあります。

パッケージが一つの場合は npm link(symlink)やinstall-local(copy)などでパッケージをインストールしてテストできます。
しかし、monorepoの場合は複数のパッケージが相互に依存しているため、一つのパッケージだけ入れても動きません。

そのため、monorepoのパッケージをbetaバージョンとしてpublishして、betaバージョンのパッケージをインストールしてテストできるようにするのが一番手軽です。

npmにはdist-tagという仕組みがあり、Stableリリース(latestタグ)とは別のタグを付けてパッケージを公開できます。

そのためnextのようなdist-tagをつけてパッケージを公開すれば、次のように@タグをつけてそのバージョンをインストールできます。

npm install package-example@next

GitHub Actions + lernaでcanaryリリース

次のようなGitHub Actionsを設定することで、PR中に/canary-release というコメントをすると、そのPRのコードをcanaryリリースできるようになります。

Requirements:

name: '/canary-release'
on:
  issue_comment:
    types: [ created ]

permissions:
  contents: read # for checkout
  pull-requests: write  # for comments
  packages: write # for publish

jobs:
  canary-release:
    name: canary-release
    runs-on: ubuntu-latest
    if: |
      # コメントを扱う制限
      # ここの制限は https://docs.github.com/en/graphql/reference/enums#commentauthorassociation を参照して設定してください
      github.event_name == 'issue_comment' &&
      (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR') &&
      startsWith(github.event.comment.body, '/canary-release')
    steps:
      - name: get pr information
        uses: actions/github-script@v4
        id: pr
        with:
          script: |
            const request = {
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number
            }
            core.info(`Getting PR #${request.pull_number} from ${request.owner}/${request.repo}`)
            try {
              const result = await github.pulls.get(request)
              core.info(`Got PR: ${JSON.stringify(result.data)}`)
              return result.data
            } catch (err) {
              core.setFailed(`Request failed with error ${err}`)
            }
      - name: checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ fromJSON(steps.pr.outputs.result).head.ref }}
          repository: ${{ fromJSON(steps.pr.outputs.result).head.repo.full_name }}
          fetch-depth: 0
      - name: setup Node
        uses: actions/setup-node@v2
        with:
          node-version: 14.x
      - name: install
        run: yarn
      - name: Publish
        run: yarn lerna publish --canary --preid next --dist-tag next --force-publish='*' --no-push --no-git-tag-version --yes
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - uses: actions/github-script@v4
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '🎉 Canary Release. You can install canary version via `npm install package@next`'
            })

つぎのような手順で PR のコードを実際のアプリケーションなどでもテストできます。

  1. PR 作る
  2. PR のコメントで /canary-release
  3. Publish されるので@nextタグのパッケージをインストールして試す → 2,3 を繰り返す
  4. 確認できたらバージョンをあげて、マージして Publish

Canary 版は パッケージ名@next という dist-tag をつけて公開します。
次のようにすれば、ローカルでもそのPR時点のものをテストできます。

npm install パッケージ名@next

またはpackage.jsonnextというバージョンを参照して npm install などでインストールします。

  "dependencies": {
       "パッケージ名": "next"
  }

Discussion