📁
GitHub Actionsのworking-directoryの罠:runステップごとにディレクトリがリセットされる仕組み
はじめに
GitHub Actionsでモノレポや複数プロジェクトを扱う際、working-directory
を使ってディレクトリを指定することがよくあります。しかし、このworking-directory
の挙動には注意が必要な罠があります。
今回は、GitHub Actionsのworking-directory
がrunステップごとにリセットされるという重要な仕様について、実例を交えて解説します。
発見したきっかけ
モノレポ構成のプロジェクトで、以下のような構造のリポジトリを扱っていました:
ProjectA/
├── web/
│ ├── productA/
│ │ └── package.json
│ └── package.json
└── api/
このプロジェクトで、web
ディレクトリ配下の処理を実行するためにGitHub Actionsのワークフローを書いていたところ、予期しない挙動に遭遇しました。
問題のコード
最初、以下のようなワークフローを書いていました:
name: Build Web Application
on:
push:
branches: [ main ]
defaults:
run:
shell: bash
working-directory: ./web
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: pwd
# 出力: /home/runner/work/ProjectA/web
- run: |
cd productA
pwd
npm install
# 出力: /home/runner/work/ProjectA/web/productA
- run: pwd
# 期待: /home/runner/work/ProjectA/web/productA
# 実際: /home/runner/work/ProjectA/web 😱
- run: npm run build
# エラー!productAディレクトリではなくwebディレクトリで実行される
何が起きているのか?
上記のコードで、3番目のrun
ステップでcd productA
を実行しているにも関わらず、4番目のrun
ステップでは元のweb
ディレクトリに戻ってしまっています。
これは、GitHub Actionsの各run
ステップが独立したシェルセッションで実行されるためです。つまり:
- 各
run
ステップは新しいシェルプロセスで開始される -
defaults.run.working-directory
で指定したディレクトリから毎回開始される - 前のステップでの
cd
コマンドやその他の環境変更は、次のステップには引き継がれない
正しい解決方法
この問題を解決するには、いくつかの方法があります:
方法1: 各runステップでディレクトリを指定
steps:
- uses: actions/checkout@v3
- run: npm install
working-directory: ./web/productA
- run: npm run build
working-directory: ./web/productA
- run: npm test
working-directory: ./web/productA
方法2: 1つのrunステップ内で複数のコマンドを実行
steps:
- uses: actions/checkout@v3
- run: |
cd productA
npm install
npm run build
npm test
方法3: defaultsを適切に設定
プロジェクト全体で特定のディレクトリを基準にする場合:
defaults:
run:
shell: bash
working-directory: ./web/productA
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm run build
- run: npm test
方法4: 環境変数を使った動的なパス管理
env:
PRODUCT_A_DIR: ./web/productA
steps:
- uses: actions/checkout@v3
- run: npm install
working-directory: ${{ env.PRODUCT_A_DIR }}
- run: npm run build
working-directory: ${{ env.PRODUCT_A_DIR }}
ベストプラクティス
- 明示的なディレクトリ指定: 各ステップで必要なディレクトリを明示的に指定する
- 関連するコマンドはまとめる: 同じディレクトリで実行する一連のコマンドは、1つのrunステップにまとめる
- 環境変数の活用: 頻繁に使用するパスは環境変数として定義する
- コメントの追加: 特にディレクトリ操作がある場合は、期待される動作をコメントで明記する
まとめ
GitHub Actionsのworking-directory
は、各run
ステップごとにリセットされるという重要な仕様があります。これは一見すると直感に反する動作かもしれませんが、各ステップの独立性を保つという観点では理にかなっています。
この仕様を理解し、適切に対処することで、より堅牢なCI/CDパイプラインを構築できます。特にモノレポや複雑なディレクトリ構造を持つプロジェクトでは、この挙動を意識したワークフローの設計が重要です。
Discussion