actions/github-script と composite アクションでカスタムアクションをかんたんに作れる

GitHub

GitHub Actions 小ネタです。 actions/github-script と composite アクションを使えば、再利用可能なアクションかんたんに作ることができます。

前提

この記事は 2022 年 05 月に書きました。 時間が経つと GitHub Actions の仕様変更などで情報が古くなるので参考にされる際は注意してください。

おさらい

GitHub Actions とは

GitHub Actions とは GitHub 上で使える作業自動化の仕組みです。

GitHub Actions

2018 年に発表され 2019 年年末に一般公開されたサービスです。 CI サービスとしてはかなり後発ですが、元々の GitHub の利用者数の多さを背景にいまではソフトウェアエンジニアに最も多く利用されている CI サービスのひとつになっています。

actions/github-script とは

actions/gitub-script とは GitHub が作成・公開している GitHub Actions 用アクションです。

actions/gitub-script を使えばちょっとした処理を JavaScript で手軽に書くことができます。

たとえば、 output として「 Hello 」を返すアクションは actions/gitub-script を使って次のように書くことができます(公式 REAMDE のサンプルです):

- uses: actions/github-script@v6
  id: set-result
  with:
    script: return "Hello!"
    result-encoding: string
- name: Get result
  run: echo "${{steps.set-result.outputs.result}}"

実行したい JavaScript コードを with.script で指定します。 id はその後のステップで参照するために必要なだけなので処理には影響しません。

with.script のコードでは以下のパッケージが利用できます:

  • otcokit/rest
  • @actions/core
  • @actions/glob
  • @actions/io
  • @actions/exec

私が理解するかぎり GitHub / GitHub Actions の API を使用する処理のほとんどをこれひとつで書けるようになっています。

なお、 script に渡されたコードは JavaScript の async 関数の body として実行されるので、 await キーワードも使うことができます。

await を使ったサンプル:

- name: npm outdated を実行して結果をサマリーに出力する
  uses: actions/github-script@v6
  id: set-result
  with:
    script: |
      const { stdout } = await exec.getExecOutput('npm outdated', [], {
        ignoreReturnCode: true,
      })

      await core.summary
        .addHeading('Outdated packages')
        .addCodeBlock(stdout)
        .write()

actions/github-script の詳細についてはリポジトリのページを参照してください。

composite アクションとは

composite アクションとは GitHub Actions のカスタムアクション(≒再利用可能なアクション)を作成する方法の 1 つです。

A composite action allows you to combine multiple workflow steps within one action. For example, you can use this feature to bundle together multiple run commands into an action, and then have a workflow that executes the bundled commands as a single step using that action.

拙訳:

composite アクションを使えば、ワークフローの複数のステップを組み合わせて 1 つのアクションにすることができます。 たとえば、複数の run コマンドを 1 つのアクションにまとめて、そのアクションを 1 つのステップとしてワークフローから呼び出して実行することができます。

composite アクションは通常のワークフローと作り方が似ているため、通常のワークフローとほぼ同じ感覚で作ることができます。 ワークフローの設定を作ったことがある人であれば初期にかかる学習コストはわずかです。

カスタムアクションを作る方法として composite アクションの他に「 Docker コンテナアクション」「 JavaScript アクション」の 2 つがありますが、 composite アクションは Docker コンテナアクションや JavaScript アクションに比べてかんたんに作れることが大きな特徴です。 composite アクションの最小構成は定義ファイル action.yml 1 つだけです。

次のサンプルは「 Hello world 」メッセージを出力するだけの composite アクションです(公式のサンプルを少し変えたものです):

action.yml:

name: 'Hello World'
description: 'Greet someone'
inputs:
  who-to-greet:
    description: 'Who to greet'
    required: true
    default: 'World'
runs:
  using: "composite"
  steps:
    - run: echo Hello ${{ inputs.who-to-greet }}.
      shell: bash

composite アクションの場合はこの定義ファイル action.yml を所定の場所に設置すればすぐに再利用可能なアクションとして利用し始めることができます。

composite アクションの action.yml の置き場所には 2 つの選択肢があります:

タイプ 設置場所 公開設定 利用範囲
A) リポジトリの .github/actions/[アクション名]/ ディレクトリ以下 public / private どちらも可 同一リポジトリ内
B) リポジトリのルート直下 public のみ 制限なし

A) のタイプのアクションは同一リポジトリ内のワークフローから利用できます。 リポジトリの公開設定は public でも private でもどちらでも大丈夫です。

B) のタイプのアクションは他のリポジトリからも利用できます。 ただし、アクションを提供する側のリポジトリの公開設定を public にしておく必要があります。

actions/github-script と composite アクションでカスタムアクションを作る

本題の actions/github-script を使って composite アクションをカスタムアクションを作る方法についてです。 今回は上の A) B) のうち B) のタイプで作る想定です。

手順は次のとおりです。

  1. public なリポジトリを作る
  2. action.yaml を追加する
  3. タグを付ける

1. public なリポジトリを作る

GitHub 上で公開設定を public にしてリポジトリを作成します。 以下 owner/repo を gh640/hello-composite-action にした想定で話を進めます。

2. action.yml を追加する

続いて action.yml ファイルを作成してコミット & リポジトリにプッシュします。 設置場所はリポジトリのルートである必要があります。 名前は action.yml でも action.yaml でもどちらでも問題ありません。

この action.yml の中で actions/github-script を呼び出して使用します。 次のサンプルは Hello World を出力するアクションです。

action.yml:

name: 'Hello World'
description: 'Greet someone'
inputs:
  who-to-greet:
    description: 'Who to greet'
    required: true
    default: 'World'
runs:
  using: "composite"
  steps:
    - uses: actions/github-script@v6
      with:
        script: |
          const { WHO_TO_GREET } = process.env
          console.log(`Hello ${WHO_TO_GREET}.`)
      env:
        WHO_TO_GREET: ${{ inputs.who-to-greet }}

アクションに渡された input を actions/github-scriptscript の中で利用したい場合は、環境変数を介して渡します(公式の README にそのように説明されています)。 ここではアクションの inputWHO_TO_GREET という環境変数を介して script に渡しています。

script には JavaScript で処理を記述しますが、ここでは GitHub / GitHub Actions の API を使用するために便利な変数がもろもろ利用できるようになっています。

公式 README の拙訳:

  • github 認証済みの octokit/rest.js クライアント(ページネーションプラグイン付き)
  • context ワークフローランのコンテキスト を格納したオブジェクト
  • core @actions/core パッケージへの参照
  • glob @actions/glob パッケージへの参照
  • io @actions/io パッケージへの参照
  • exec @actions/exec パッケージへの参照
  • require Node.js の通常の require のプロキシラッパー。作業ディレクトリからの相対パスでスクリプトを読み込める。作業ディレクトリにインストールされた npm パッケージも読み込める。

3. タグを付ける

action.yml をリポジトリのルートに追加できたら最後にタグを付けます。

git tag v1
git tag v1.0.0

厳密に言うとタグをつけなくてもアクションを利用することはできますが、タグを付けておくと

  • 将来破壊的な変更を入れやすくなる
  • Marketplace で公開するときには必須となる

ので、個人利用の場合でも最初からタグを付けて運用するのがよいのかなと思います。

これにて actions/github-script を使用した composite アクションの作成は完了です。 あとはどのリポジトリでもよいのでワークフローを作成して uses でこのアクションを利用します。

uses: gh640/hello-composite-action@v1

(実際にはこの gh640/hello-composite-action リポジトリは存在しません)

以上です。

サンプル

npm outdated を実行してその出力をサマリーに表示するアクションです。

参考


アバター
後藤隼人 ( ごとうはやと )

ソフトウェア開発やマーケティング支援などをしています。詳しくはこちら