GitHub Actions で再利用可能な Action を作る

GitHub Actions では、よく使う処理を Action として切り出して再利用できます。Marketplace にはすでに多くの Action が登録されています。

GitHub Marketplace · Actions to improve your workflow · GitHub

Action には Docker Container Action と JavaScript Action という2種類の実装方法があります。

Docker Container Action

help.github.com

GitHub Actions が実行される Runner にインストールされていないソフトウェアを Docker コンテナに入れて ENTRYPOINT で実行する用途がメインです。kubectl などをワンショットで実行したい場合です。Docker なので実装する言語を選ばないというのも特徴ですが、シェルスクリプトを使っているケースが多い印象です。

Terraform の公式 Action がこの形式です。

github.com

init / validate / plan と Terraform のサブコマンドを実行するたびに裏では コンテナがビルドされ docker run で実行されます。実行コストは高いけど、GitHub Actions の Runner は Azure の高可用性サーバで実行されてるのでまあいいかという感じ。実装コストは低いので CI で必要な部品を手軽に作って共有できます。

Dockerfile の他に Docker Hub のパブリックなイメージを指定して毎回ビルドが走らないようにすることもできます。GitHub Package Registry のパブリックなイメージは現在のところなぜか利用できません*1

JavaScript Action

help.github.com

JavaScript Action は GitHub 提供の NPM パッケージを使って作る Action です。ワンショットの実行だけでなく環境構築してマルチラインで処理を書きたい場合などに適しています。コンテナではなく Runner の環境に変更を加えることになります。

ソフトウェアのダウンロード、インストール、コマンド実行などをすべて JavaScript (もしくは TypeScript) で書きます。

const core = require("@actions/core");
const tc = require("@actions/tool-cache");
const exec = require("@actions/exec");
const io = require("@actions/io");
const path = require("path");

async function download(url) {
  const downloadPath = await tc.downloadTool(url);
  return downloadPath;
}

async function extract(downloadPath) {
  const folder = await tc.extractTar(downloadPath);
  return folder;
}

async function install(downloadPath, filename) {
  const binPath = "/home/runner/bin";
  await io.mkdirP(binPath);
  await exec.exec("chmod", ["+x", downloadPath]);
  await io.mv(downloadPath, path.join(binPath, filename));
  core.addPath(binPath);
}

Actions のライブラリを使うことで Runner の環境がクリーンナップされているのではないかと思います。

help.github.com

JavaScript Action で helmfile と関連のソフトウェアをインストールする Action 作ってみました。まだ Marketplace には登録していませんが。

github.com

ちなみにこの Organization は僕の所属会社のです。

*1:認証エラーになってしまいます。