GitHub Actionを新しく作るとき、GitHub上でテストしては失敗を繰り返してしまう。actを使って、ある程度ローカルで動作検証した上で、GitHubで動かせるようにする。
インストール
実行にはDocker環境が必要。
macOSの場合、以下でインストールできる。
$ brew install act
mac以外の環境で、goが入ってる場合は、以下でもインストールできる。
$ go install github.com/nektos/act@latest
M1 Macで起動する場合は、「--container-architecture linux/amd64」オプションをつける。
また、以下の問題があり、yarnコマンドが実行できないことがある。
https://github.com/nektos/act/issues/280
「-P」または「--platform」でプラットフォームを指定でき、上のissueに記載されている通り、「-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:js-latest」をつけると、yarnコマンドを実行できるようになった。
初回実行後に作成される「~/.actrc
」にこれらのオプションを記載しておくと、毎回の実行時にこれらのオプションをつけて実行できる。
--container-architecture linux/amd64
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:js-latest
基本的な実行方法
引数に何もつけないとpushイベントをトリガーとしたワークフローが実行される。
$ act
pull_requestイベントをトリガーとしたい場合は以下のように引数を与える。
$ act pull_request
イベントでトリガーされるワークフロー一覧
イベント名の後に「-l」または「--list」オプションをつける。
$ act pull_request -l
Stage Job ID Job name Workflow name Workflow file Events
0 helloworld helloworld Hello World helloworld.yaml pull_request
ワークフローを直接指定して実行
「-W」または「--workflows」で指定したワークフローを実行することができる。
$ act -W .github/workflows/helloworld.yaml pull_request
Pull Requestのマージをローカル実行
マージ時にhello worldと表示するテスト用のworkflowを作成する。 (.github/workflows/helloworld.yaml
)
name: Hello World
on:
pull_request:
types: [closed]
jobs:
hello-world:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- run: echo "Hello World!"
これをローカルで実行してみると、イベントのプロパティが存在しないため、エラーが発生する。
$ act -W .github/workflows/helloworld.yaml pull_request
Error: ❌ Error in if-expression: "if: github.event.pull_request.merged == true" (Unable to dereference 'merged' on non-struct 'invalid')
これを回避するには、以下のようなイベント情報を書き込んだ、jsonファイルを用意し、「-e」または「--eventpath」で指定する。
$ cat pull_request.json
{
"pull_request": {
"merged": true
}
}
$ act -W .github/workflows/helloworld.yaml pull_request -e pull_request.json
[Hello World/hello-world] 🚀 Start image=ghcr.io/catthehacker/ubuntu:js-latest
[Hello World/hello-world] 🐳 docker pull image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 username= forcePull=false
[Hello World/hello-world] 🐳 docker create image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker run image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker exec cmd=[mkdir -m 0777 -p /var/run/act] user=root workdir=
[Hello World/hello-world] ⭐ Run echo "Hello World!"
[Hello World/hello-world] 🐳 docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| Hello World!
[Hello World/hello-world] ✅ Success - echo "Hello World!"
pull_request.jsonのmergedをfalseに書き換えると、実行されないことが確認できる。
$ cat pull_request.json
{
"pull_request": {
"merged": false
}
}
$ act -W .github/workflows/helloworld.yaml pull_request -e pull_request.json
シークレットがある場合
オプション「-s」または「--secret」を使って、シークレットキーを指定できる。複数ある場合は、複数つける。
$ act -s SECRET1=value1 -s SECRET2=value2
実行例(.github/workflows/helloworld.json)
name: Hello World
on:
push:
jobs:
hello-world:
runs-on: ubuntu-latest
steps:
- run: echo "secret1=${{ secrets.SECRET1 }}, secret2=${{ secrets.SECRET2 }}"
実行結果
% act -W .github/workflows/helloworld.yaml -s SECRET1=s1 -s SECRET2=s2
[Hello World/hello-world] 🚀 Start image=ghcr.io/catthehacker/ubuntu:js-latest
[Hello World/hello-world] 🐳 docker pull image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 username= forcePull=false
[Hello World/hello-world] 🐳 docker create image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker run image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker exec cmd=[mkdir -m 0777 -p /var/run/act] user=root workdir=
[Hello World/hello-world] ⭐ Run echo "secret1=${{ secrets.SECRET1 }}, secret2=${{ secrets.SECRET2 }}"
[Hello World/hello-world] 🐳 docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| secret1=***, secret2=***
[Hello World/hello-world] ✅ Success - echo "secret1=${{ secrets.SECRET1 }}, secret2=${{ secrets.SECRET2 }}"
「--secret-file」でシークレットをファイルに書いて、指定してもよい。
$ cat .secret
SECRET1=s1
SECRET2=s2
$ act -W .github/workflows/helloworld.yaml --secret-file .secret
[Hello World/hello-world] 🚀 Start image=ghcr.io/catthehacker/ubuntu:js-latest
[Hello World/hello-world] 🐳 docker pull image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 username= forcePull=false
[Hello World/hello-world] 🐳 docker create image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker run image=ghcr.io/catthehacker/ubuntu:js-latest platform=linux/amd64 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Hello World/hello-world] 🐳 docker exec cmd=[mkdir -m 0777 -p /var/run/act] user=root workdir=
[Hello World/hello-world] ⭐ Run echo "secret1=${{ secrets.SECRET1 }}, secret2=${{ secrets.SECRET2 }}"
[Hello World/hello-world] 🐳 docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| secret1=***, secret2=***
[Hello World/hello-world] ✅ Success - echo "secret1=${{ secrets.SECRET1 }}, secret2=${{ secrets.SECRET2 }}"