プライベートリポジトリにあるGitHub Workflowをほかのリポジトリで使う

Today I Learned

この記事では、プライベートリポジトリにおいたReusable Workflowを、他のリポジトリで参照して使う方法を説明する。

プライベートリポジトリに置いたワークフローを参照して使えるようになった

処理内容が変わらないワークフローを、複数のリポジトリで実行させたいケースが多くある。
たとえばJavaScriptのプロジェクトの場合は、どのリポジトリでもESLintを実行したい。
GitHub Actionsでそれを実現するには、それぞれのリポジトリでワークフローファイルを持つ必要があり、それらのファイルをメンテナンスしていくのが手間である。

その解決手段のひとつとして、GitHubのReusable Workflowがある。
Reusable Workflowは、ひとつのワークフローを他のリポジトリで共有して使うことができる仕組みである。
ただし共有するワークフローファイルはパブリックなリポジトリに置く必要があり、公開したくないワークフローファイルに対しての運用ができなかった。

しかし、2022年12月14日に、プライベートリポジトリにあるActionやReusable Workflowを、ほかリポジトリから参照して使うことができるようになった。

GitHub Actions – Sharing actions and reusable workflows from private repositories is now GA

具体的には、プライベートリポジトリに置いたReusable Workflowを参照できる参照できる設定が追加された。
同じユーザーアカウントや組織内であれば、プライベートリポジトリに置いたワークフローを他のリポジトリと共有できるようになった。

Reusable Workflow を置くリポジトリのワークフロー

Reusable Workflow を作る

複数のリポジトリで共有して使うワークフローを定義する。
例としてESLintを実行するワークフローを作ることにする。

  1. GitHubにプライベートリポジトリを作る。
    このリポジトリを、複数のリポジトリ間で共有するワークフローの置き場所とする。
    リポジトリ名は「github-actions-shared-workflows」とした。

  2. 次の内容で、「.github/workflows」の下に共有するワークフローを作成する。 ファイル名はeslint.ymlとした。
    ワークフローをReusable Workflowにするには、on.workflow_callを指定する。

.github/workflows/eslint.yml
name: eslint

on:
  workflow_call:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run lint
        run: npm run eslint

Actions のアクセス許可を有効にする

プライベートリポジトリに置いたReusable Workflowを共有するには、リポジトリの設定で、Actionsのアクセス許可を有効にする。

  1. Reusable Workflowを置いたリポジトリの[Settings]を開く。
  2. サイドメニューの[Actions]を展開し、[General]を選択する。
  3. 「Access」セクションで、「Accessible from repositories owned by the user 'USER_NAME'」を選択する。
  4. [Save]をクリックする。

Reusable Workflow を参照して使うワークフロー

Reusable Workflowを参照して使う側のワークフローを作成する。
このリポジトリには、すでにESLintが導入されているとする。そのため、ESLintの設定方法はこの記事に記載しない。

次の内容で、Reusable Workflowを参照するワークフローを「.github/workflows」の下に作成する。
他のリポジトリにあるReusable Workflowを参照するには、job.<job_name>.usesで使うワークフローのパスを指定する。

.github/workflows/eslint.yml
name: eslint

on:
  pull_request:

jobs:
  lint:
    uses: chick-p/github-actions-shared-workflows/.github/workflows/eslint.yml@main

動作確認

今回参照する側のワークフローでは、Pull Requestを作成したときに実行されるように設定した。
そのためPull Requestを作って動作を確認する。

スクリーンショット:ワークフローの実行結果

プライベートリポジトリに置いたReusable Workflowが呼び出されて実行できている。
このリポジトリではESLintがエラーで落ちるような内容にしているため、CIとしては失敗することが期待値である。

リポジトリごとに個別の値を渡したい

実際の運用では、Reusable Workflowを参照するリポジトリごとに、ワークフローの微妙な違いが発生することもある。
たとえば、Node.jsのパッケージマネージャーがYarnである場合や、リポジトリごとに少し異なるコマンドを使いたい場合が考えられる。
Reusable Workflowでは、参照して使う側から入力値を渡すことができるため、このようなケースでも対応できる。

Reusable Workflow を置くリポジトリ側

参照するワークフロー側から入力値を渡すには、workflow_call.inputに変数名や型を定義する。
定義した変数は、${{ inputs.<variable_name }}` で取り出せる。
参照:Using inputs and secrets in a reusable workflow

修正後のワークフローでは、次のことを対応することにした。

  • パッケージマネージャーをnpmかyarnを選べる
  • Lintのコマンドを渡せるようにする
.github/workflows/eslint.yml
name: eslint
on:
  workflow_call:
+    inputs:
+      manager:
+        required: false
+        type: string
+        default: 'npm'
+      command:
+        required: false
+        type: string
+        default: 'npm run eslint'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Use Node.js
        uses: actions/setup-node@v3
+        with:
+          node-version: 16
+          cache: ${{ inputs.manager }}

-      - name: Install dependencies
+      - name: Install dependencies (npm)
+        if: ${{ inputs.manager == 'npm' }}
        run: npm ci

+      - name: Install dependencies (yarn)
+        if: ${{ inputs.manager == 'yarn' }}
+        run: yarn install

      - name: Run lint
-        run: npm run eslint
+        run: ${{ inputs.command }}

Reusable Workflow を参照して使う側

参照して使う側から入力値を設定するには、with.<variale_name>を使う。

.github/workflows/eslint.yml
name: eslint

on:
  pull_request:

jobs:
  lint:
    uses: chick-p/github-actions-workflow-provider/.github/workflows/eslint.yml@main
+    with:
+      manager: "yarn"
+      command: "yarn lint:eslint"

動作確認

参照して使う側のリポジトリで、パッケージマネージャーをYarnにして、Pull Requestを作成する。

スクリーンショット:ワークフローの実行結果

無事、managercommandに設定した値が使われた。