一連のワークフロー開発はますますGithub Actionに任せるようになりそうなので(Agentic Workflowのメモ)、そのGithub Actionをローカルで実行できるactで遊んでいた。

とはいえ、Github Actionで動いているスクリプトがそのまま動く、何て素敵なことはないので、直した部分のメモ

環境変数の設定

例えば actions/configure-pages@v5 が設定しているGithub PagesのURL。

run: |
    if [ "${{ github.actor }}" = "nektos/act" ]; then
        BASE_URL="http://localhost:8080"
    else
        BASE_URL="${{ steps.pages.outputs.base_url }}/"
    fi

環境変数によっては、設定ファイルでactに渡したり、 $GITHUB_OUTPUT に入れることも可能

ARCHの設定

ARCH依存のパッケージを使用している場合は切り替えられるようにする。例えば、Hugoコマンドを自力でセットアップしている場合の例

run: |
    if [ "$(uname -m)" = "x86_64" ]; then
        ARCH="amd64"
    else
        ARCH="arm64"
    fi
    wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-${ARCH}.deb \
    && sudo dpkg -i ${{ runner.temp }}/hugo.deb

手元の環境がARM系だったので、そうじゃなければ気にしなくてもいいかも。

Github API

PagesへのデプロイやPRの送付はスキップして、代わりにログ出力にする。

if: github.actor != 'nektos/act'

env.ACTじゃなくてgithub.actorと使うのはただの好み。

ファイルパス

実行環境の設定次第でパスは変わるので、例えば絶対パスをキーにするような処理には対応する必要がある。

これまではdockerを使って、どの環境でも絶対パスを一致させていたが、どうやらact内でdockerを動かすの難しいらしい1。Docker in Dockerの構図になるため、そもそもDockerを使わない方が良さそうと判断。

これは絶対パスを使うスクリプト側を直した。あるスクリプトはuvベースだったので

$ uv run --project path/to/script path/to/script/process.py

のように -project オプションを使えば、いちいち cd しなくてもスクリプトが実行できる。これを使用して、相対パスが同じになるようにした

GITHUB_TOKEN

Github Actionsが自動で設定する GITHUB_TOKEN を使う処理は gh auth すれば良い。明示的に渡すなら以下。

$ act -s GITHUB_TOKEN="$(gh auth token)"

ところで、actのログが先頭に絵文字を使うスタイルで、とりあえずログの見た目は派手。

[Job example] ⭐ Run Post Cache Hugging Face models
[Job example]   🐳  docker exec cmd=[/usr/local/bin/node /var/run/act/actions/actions-cache@v4/dist/save/index.js] user= workdir=
| Cache hit occurred on the primary key huggingface-plamo-embedding-1b-, not saving cache.
[Job example]   ✅  Success - Post Cache Hugging Face models [100.418ms]
[Job example] ⭐ Run Complete job
[Job example] Cleaning up container for job update-related-posts
[Job example]   ✅  Success - Complete job
[Job example] 🏁  Job succeeded

  1. 部分的に対応しているcontextや、docker.sockを共有する方法は、自分はうまくいかなかった。あまり深掘りしていない。 ↩︎