PrivateリポジトリのActionsWorkflow内Stepを共有するためCompositeRunStepを外部参照無しに同リポジトリ内で完結させてみた

複数のWorkflowで同一なStepが増えて、流石にそれぞれを対処すると手間がかかりすぎると思い対策を検討していたところ、パブリックリポジトリ前提と認識していたCompositeRunStepがプライベートリポジトリ内で完結できることを知って試してみました。
2021.06.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

GitHub Actionsで複数Workflowを追加していくと、Workflow間でStepが重複している事はよくあります。重複部分を共有化できる機能としてcomposite run stepsも既にリリースされていますが、正直色々ちょっとわかりにくい。原因としては以下あたり。

  • 今使っているリポジトリで有効か分からない
  • 使えるとしてどう使えばいいのかわからない

最初にこの機能を知ったときには「共有化したStepをパブリックにすること前提」という一文を見かけて「あ、オープンソースじゃないと使えないな」と判断したのですが、最近幾つか検索して見当たった事例をみると同一リポジトリ内に設置できることを知り、実際にやってみました。

Composite Run Stepを使える条件

GitHub Actionsが使えるなら使えます。Actionsが使える条件は新プランであること(プライベートリポジトリ作成数無制限)。指定が若干異なってきますが、リポジトリがプライベート・パブリックのいずれもOK。

同一リポジトリで構成する

同一リポジトリ内で管理したい場合は以下の構成に従います。Composite Run StepはWorkflowとは別ディレクトリ管理になります。

Type Path
Workflow .github/workflow/TEMPLATE.yml
CompositeRunStep .github/actions/TEMPLATE/action.yml

TEMPLATEの箇所がユーザ定義となります。Workflowの場合はファイル名が、CompositeRunStepの場合はディレクトリ名で見分けをつける形です。

テンプレートファイルの書き方

これもPublicリポジトリと変わりません。内容については公式ドキュメントのサンプルを挙げてみます。

name: 'Hello World'
description: 'Greet someone'
inputs:
  who-to-greet:  # id of input
    description: 'Who to greet'
    required: true
    default: 'World'
outputs:
  random-number:
    description: "Random number"
    value: ${{ steps.random-number-generator.outputs.random-id }}
runs:
  using: "composite"
  steps:
    - run: echo Hello ${{ inputs.who-to-greet }}.
      shell: bash
    - id: random-number-generator
      run: echo "::set-output name=random-id::$(echo $RANDOM)"
      shell: bash
    - run: ${{ github.action_path }}/goodbye.sh
      shell: bash

runs:steps:以降にWorkflowの重複Stepを持ってきます。他のActionをuse不可能なことだけ注意が必要です。複数のStepを纏めてCompositeに持ってきたい場合は事前に順番を整理しておくとよいでしょう。

inputはActionを利用する際のWithが該当し、outputsはActionで生成された値を用いる場合に使う${{ steps.foo.outputs.random-number }}の指定用です。

制約はあるものの、重複部分を抽出したテンプレートの書き方はとてもシンプルです。

実際にWorkflowで使う場合

ポイントは呼び出し方。Workflowの一部を抜粋したものを例にします。env:ENVIRONMENT:の指定でわかるように、環境別でWorkflowを替えているケースです。ここからCompositeの対処を入れてみます。

name: "Develop: Deploy Redash"

on: [workflow_dispatch]

env:
  ENVIRONMENT: develop

defaults:
  run:
    working-directory: tools/redash

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-18.04

    steps:
    - name: Set up Node
      uses: actions/setup-node@v1
      with:
        node-version: '10.x'

    - uses: actions/setup-python@v2
      with:
        python-version: '3.7'

    - name: Checkout
      uses: actions/checkout@v2

    - name: Install System Dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y --no-install-recommends libssl-dev libcurl4-openssl-dev

外部Actionを使っていないのはInstall System DependenciesのStepだけですが、インストールするライブラリをWorkflow毎に管理するのはトラブルの原因なのでまとめることにします。

公式ドキュメントのサンプルをベースにしつつ、今回不要なもの(inputs, outputs)は外します。

% vim .github/actions/install_dependecies/action.yml
name: 'Install System Dependencies'
description: 'dependencies install step'
runs:
  using: "composite"
  steps:
    - run: |
        sudo apt-get update
        sudo apt-get install -y --no-install-recommends libssl-dev libcurl4-openssl-dev
      shell: bash

次にこれをWorkflowから呼び出します。

name: "Develop: Deploy Redash"

on: [workflow_dispatch]

env:
  ENVIRONMENT: develop

defaults:
  run:
    working-directory: tools/redash

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-18.04

    steps:
    - name: Set up Node
      uses: actions/setup-node@v1
      with:
        node-version: '10.x'

    - uses: actions/setup-python@v2
      with:
        python-version: '3.7'

    - name: Checkout
      uses: actions/checkout@v2

    - name: Install System Dependencies
      uses: ./.github/actions/install_dependecies

指定する際のポイントとしては、

  1. actions/checkoutにてソースコードをチェックアウトしておく
  2. ワークスペースからの相対指定が必要(NG: .github, OK: ./.github)

1についてはチェックアウトしないと共通化したテンプレートが見つからないためです。2は相対指定にしなかった場合外部リポジトリを探そうとします。

The workflow is not valid. .github/workflows/deploy.yml (Line: 16, Col: 15): Expected format {org}/{repo}[/path]@ref. Actual '.github/actions/hello_world' Input string was not in a correct format.

あとがき

一度理解するとWorkflowの整理に俄然乗り出したくなりますが、Composite内でActionは利用不可です。また、外部Actionを自作してComposite化する手もありますが、その分メンテナンスの負担が増します。無理なくそつない感じで使ってみましょう。

参考リンク