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

TIL
December 16, 2022

この記事では、プライベートリポジトリにおいた 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 に設定した値が使われた。