8  GitHub Actionsの基本

Author

Ryo Nakagami

Published

2025-01-14

Modified

2025-11-21

Scope

  • GitHub Actionsの基本構成要素の説明
  • GitHub Actions Contextsの説明
  • GitHub Actionsで利用できるSHELLについて説明

GitHub Actionsの構成要素

GitHub Actionsの

ワークフローサンプル
name: Hallo                         # ワークフロー名(optional)
on: push                            # イベントトリガー
jobs:                               # ジョブの定義
  hallo-world:                      # ジョブID
    runs-on: ubuntu-latest          # ランナー定義
    steps:                          # ステップ定義
      - run: echo "Hallo, world"    # Step 1
      - uses: actions/checkout@4    # Step 2(Step 1の後に実行)
key 概念 説明
name ワークフロー名 ログで表示されるワークフロー名,省略可能
on イベントトリガー ワークフローを開始する条件
jobs ジョブ ワークフローの実行単位.複数定義可能で各ジョブはデフォルトでは並列実行だが,ジョブ間の依存関係も定義可能
hallo-world ジョブID ジョブIDは複数のステップで構成される,ランナーはジョブ単位で指定
runs-on ランナー ジョブが実行される環境, OS
steps ステップ 各ジョブ内で実行される手順の集まりをリスト形式で記述,上から逐次実行される
run シェルスクリプト実行 例: シェルスクリプト echo "Hallo, world の実行
uses アクション呼び出し 例: コードのチェックアウト用アクション actions/checkout を利用

イベントトリガーリスト

Events that trigger workflowsにて, GitHub Actionsで利用可能なイベントトリガー一覧を確認することができます.代表的なものとして

  • pull_request: PR時,typesopenedなどが指定可能
  • push: push時.branchesでブランチ指定可能
  • schedule: スケジュール設定, cronを用いて指定,タイムゾーンはUTC
  • workflow_dispatch: 手動実行時

ジョブ単位での実行

GitHub Actionsワークフロー実行はジョブ単位で実行されます.ジョブを細かく定義することで以下のような利点を得ることができます:

  • 効率性: 並列処理による高速化
  • 柔軟性: 条件分岐や異なる環境への対応
  • メンテナンス性: エラーの特定や設定変更が容易

▶  効率性

  • ジョブを分割することで,依存関係のないタスクを並列実行可能
  • 全体の処理時間を短縮できる
例: テストとビルドの分割
name: Hallo
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build the application
        run: echo "Building..."

  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Run tests
        run: echo "Testing..."

▶  柔軟性

  • ジョブごとに異なる条件 (if ステートメント) を設定できるため,柔軟なフロー設計が可能
  • 各ジョブに異なるランナーや環境(例: OS、Node.jsのバージョン)を割り当てられる
例: 特定のブランチだけでデプロイを実行するジョブを定義
jobs:
  deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Deploy the application
        run: echo "Deploying..."

▶  メンテナンス性

  • GitHub Actionsワークフローがfailedした場合,failedしたジョブ群のみ再実行を試みることができる
  • 複雑なタスクを単一のジョブに詰め込むと,ワークフローが読みづらくなってしまう
Tip🍵 Green Tea Break: ランナーとエフェメラル

GitHub Actionsのワークフローで定義されたジョブを実行する実行環境のことをランナーと呼びます. ランナーに応じてOSやマシンスペックを定義することができます.

GitHub Actionsの文脈では,ランナーはジョブ開始時に起動し,終了すると破棄されます.このことをエフェメラルと呼びます. エフェメラルとは、「一時的な」という意味です.

エフェメラルなランナーは次の利点があります:

  • クリーンな環境: 各ジョブは,クリーンな状態のランナーで実行されるため,ジョブ間の干渉を防ぎ,ワークフローの信頼性を向上させる
  • セキュリティ: エフェメラルなランナーは,ジョブ実行後に破棄されるため,機密データの漏洩のリスクを減らすことができる

ジョブのエラー判定

GitHub Actionsは終了ステータス(Termination status)を用いて,ワークフロー実行のエラー判定をします.

  • 0以外の場合は,エラー判定
  • 0の場合は,正常終了
例: 終了ステータスの確認
invalid-command
echo $?
bash: line 1: invalid-command: command not found
127

上記の例では127が返されますが,このスクリプトを含むジョブはfailed判定されることになります.

Contexts

実行時の情報やジョブの実行結果を保持するオブジェクトのことをコンテキストと呼びます. コンテキストは複数のプロパティから構成され,githubコンテキストならば

run : echo "レポジトリ名: ${{ github.repository }}"

のように,github.repositoryプロパティから値を取得します.多くの場合,プロパティは文字列型を返しますが,github.eventのようにオブジェクト型を 返す場合もあるので以下で紹介していきます.

▶  コンテキストの主な種類

Contexts 説明
github GitHubに関する情報を提供
runner ランナーに関する情報を提供
job ジョブに関する情報を提供
steps ステップに関する情報を提供
vars Variablesに登録された変数情報を提供
secrets Secretsに登録された暗号化された変数情報を提供
例: ステップの最終的な結果に応じた条件分岐
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Build application
      id: build
      run: echo "ビルドが成功しました" >> build.txt
    - name: Display build output
      run: cat build.txt
      if: steps.build.conclusion == 'success'

環境変数の定義と参照

環境変数はワークフロー実行中に使用できる名前と値のペアです.

  • GitHub Actionsでは,env keyを用いて環境変数を定義
  • 環境変数はワークフローレベル、ジョブレベル、またはステップレベルで定義可能
  • ただし,単一のワークフローでのみ有効(複数のワークフローで同じ値を使いたい場合は Variables, Secrets を用います)

という特徴があります.

▶  ワークフローレベルでの定義と参照

name: Example Workflow
on: push
env:
  GLOBAL_ENV_VAR: "global_value"

jobs:
  example-job:
    runs-on: ubuntu-latest
    steps:
      - name: Print global environment variable
        run: echo "Global environment variable:" "${GLOBAL_ENV_VAR}"

▶  ジョブレベルでの定義と参照

jobs:
  example-job:
    runs-on: ubuntu-latest
    env:
      BRANCH: "main"
    steps:
      - name: Print job environment variable
        run: echo "${BRANCH}"
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ env.BRANCH }}             # envコンテキスト経由で環境変数を参照

▶  ステップレベルでの定義と参照

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Set, environment variable
      run: echo "MY_SECRET_VALUE=your_secret_value" >> $GITHUB_ENV
    - name: Use, environment variable
      run: echo "秘密の値:" "${{ env.MY_SECRET_VALUE }}"
Tip🍵 Green Tea Break: 環境変数をダブルクォーテーションで囲む

上記のシェルスクリプトにおいて,シェルが変数展開を行うのを防ぐため,環境変数を参照する際はダブルクォーテーションで囲っています. シェルはコマンドを実行する前に,コマンド内の変数を展開するという特徴があります.

MY_VARIABLE="Hello, world!"
echo $MY_VARIABLE

だと,Hello, world! を一回展開してから,echo Hello, world!を実行してしまうため,特殊文字を含んでしまった場合,予期しないエラーが発生するリスクがあります.

また,特殊文字関連の注意点としてLiteral colon character (“:”) in expressions kills YAML parserがあります.

failed, YAML parse error
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Set, environment variable
      run: echo "MY_SECRET_VALUE=your_secret_value" >> $GITHUB_ENV
    - name: Use, environment variable
      run: echo "秘密の値: ${{ env.MY_SECRET_VALUE }}"
worked
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Set, environment variable
      run: echo "MY_SECRET_VALUE=your_secret_value" >> $GITHUB_ENV
    - name: Use, environment variable
      run: echo "秘密の値:" "${{ env.MY_SECRET_VALUE }}"

このように特殊文字を含むシェルスクリプトを利用する場合は,シェルスクリプト起因とYAMLパース起因の2つの軸で注意を払う必要があります.

ステップ間のデータの受け渡し

ステップ間でValueを受け渡したい場合,通常のシェルスクリプトに倣って以下のように定義すると失敗します

例: 受け渡し失敗例
name: share data between steps
on: push
jobs:
  share-fail:
    runs-on: ubuntu-latest
    steps:
      - run: export RESULT="hallo"
      - run: |
          if [ -z "$RESULT" ]; then
            echo "RESULT is empty"
            exit 1
          else
            echo "RESULT is not empty"
            exit 0
          fi

Steps間でシェルスクリプトの実行結果を受け渡したい場合,

  • GITHUB_OUTPUT環境変数
  • GITHUB_ENV環境変数

のいずれかを経由して受け渡す必要があります.

  • stepsコンテキスト経由でValueの受け渡しをする
  • Step IDをkeyとして使用して,そのValueに対して変数のkey-valueペアが紐づくイメージ
  • 基本構文としては echo "<key>=<value>"形式で変数を定義して,${{ steps.<step-id>.outputs.<key> }}で取得する
  • 記述量は増えるが依存関係が明確になるというメリットがある
name: share data between steps
on: push
jobs:
  share-via-github-output:
    runs-on: ubuntu-latest
    steps:
      - id: source-via-output
        run: echo "RESULT=hallo" >> "${GITHUB_OUTPUT}"
      - id: check-via-output
        env:
          RESULT: ${{ steps.source-via-output.outputs.RESULT }}  
        run: echo "${RESULT}"
  • ステップ内で,echo "変数名=値" >> $GITHUB_ENVコマンドを使用し GITHUB_ENVに新しい環境変数を追加
  • ステップ間の依存関係が分かりづらくなるデメリットがある(例: 上書きされた場合は最新の値を参照する)
name: share data between steps
on: push
jobs:
  share-via-gitrhub-env:
      runs-on: ubuntu-latest
      steps:
        - id: source-via-env
          run: echo "RESULT=hallo" >> "${GITHUB_ENV}"
        - id: check-via-env
          run: echo "${RESULT}"

GitHub Actionsにおけるシェル

GitHub Actionsのワークフローでシェルを指定したい場合,

  • 起動シェルをステップごとに指定
  • ワークフロートップでデフォルトシェルとして指定

することができます.

▶  サポートされてるシェル一覧

Shell サポートランナー 説明
bash Linux, macOS, Windows Linux, macOSでのデフォルトのシェル
sh Linux, macOS パスで bash が見つからなかった場合のフォールバック動作
pwsh Windows Windowsで使われるデフォルトのシェル, PowerShell Core, GitHub によってスクリプト名に拡張子 .ps1 が追加される
powershell Windows GitHub によってスクリプト名に拡張子 .ps1 が追加される
cmd Windows GitHub によってスクリプト名に拡張子 .cmd が追加される
python Linux, macOS, Windows Pythonのコマンド

デフォルトシェルの指定

デフォルトシェルはワークフロートップで以下のように指定することができます

name: setup default shell
on: push
defaults:
  run:
    shell: bash
    working-directory: ./script

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ls
      - run: bash hallo-world.sh

ジョブで定義されたデフォルト設定は,同じ名前を持つワークフローで定義されたデフォルト設定をオーバーライドします. これはシェルでも同様です

$ tree
├── .github
   └── workflows
       └── shellcheck.yaml
├── script
   └── hallo-world.sh
├── script2
   └── hallo-world.sh
└── README.md

というレポジトリ構造をまず考えます.

  • script/hallo-world.sh: echo "これはdefault shell"
  • script2/hallo-world.sh: echo "これはjob default shell"

という内容とします.ここで

shellcheck.yaml
name: setup default shell
on: push
defaults:
  run:
    shell: bash
    working-directory: ./script

jobs:
  defaultshell:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ls
      - run: bash hallo-world.sh
  stepshell:
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
        working-directory: ./script2
    steps:
      - uses: actions/checkout@v4
      - run: bash hallo-world.sh

とすると,

  • job defaultshell: これはdefault shell
  • job stepshell: これはjob default shell

という実行結果になります.

シェル指定は明示すべき

ランナーがLinux/macOSのとき,デフォルトで起動するシェルはBashですが,シェルで指定した場合のBashと動作が異なります.

ケース 起動オプション 効果
省略時 bash -e {0} エラーが発生したらスクリプトの実行を停止するが,パイプ処理中のエラーは無視
明示時 bash --noprofile --norc -eo pipefail {0} プロファイルファイルを読み込まない,パイプ処理中のエラーはパイプ全体の失敗と判定

従って,Bashを利用する場合もワークフローのデバッギングの観点からshell: bashと記述することが推奨されます.

▶  Options

  • --noprofile--norc: プロファイルファイルとrcファイルをロードしない = ランナーに個別の環境設定が反映されない
  • -eo pipefail: パイプラインの最後のコマンドが失敗した場合,パイプライン全体を失敗と判定

References