T-CREATOR

GitHub Actions コンテキスト&式の早見表:fromJson/toJson/hashFiles まで

GitHub Actions コンテキスト&式の早見表:fromJson/toJson/hashFiles まで

GitHub Actions でワークフローを書いていると、${{ }} の中で使える便利な機能がたくさんあることに気づきますよね。でも、いざ使おうとすると「あれ、この関数って何だっけ?」「コンテキストってどうアクセスするんだっけ?」と迷ってしまうことも多いのではないでしょうか。

本記事では、GitHub Actions のコンテキストと**式(Expression)**について、実務でよく使う機能を早見表形式でまとめました。fromJsontoJsonhashFiles といった便利な関数の使い方を、具体例とともにわかりやすく解説します。これを読めば、GitHub Actions の表現力がグッと広がり、より柔軟なワークフローが書けるようになるでしょう。

早見表:主要なコンテキスト一覧

GitHub Actions で利用できる主要なコンテキストを以下の表にまとめました。

#コンテキスト名概要よく使うプロパティ例利用シーン
1githubイベント、リポジトリ、コミット情報github.event_name, github.sha, github.refブランチ名取得、コミット SHA 参照
2env環境変数(グローバル・ジョブ・ステップ)env.NODE_ENV, env.API_KEY環境変数の参照
3job現在のジョブ情報job.status, job.container.idジョブステータス確認
4steps前ステップの出力・結果steps.<step_id>.outputs, steps.<step_id>.outcomeステップ間のデータ受け渡し
5runnerランナー環境情報runner.os, runner.temp, runner.tool_cacheOS 判定、一時ディレクトリ利用
6secretsリポジトリ・Organization のシークレットsecrets.GITHUB_TOKEN, secrets.DEPLOY_KEY認証情報の安全な参照
7inputsワークフロー呼び出し時の入力inputs.environment, inputs.version再利用可能ワークフローのパラメータ
8matrixマトリックス戦略の現在値matrix.os, matrix.node-version複数環境での並列実行

早見表:主要な式関数一覧

GitHub Actions で利用できる便利な式関数を以下の表にまとめました。

#関数名構文例戻り値用途
1fromJsonfromJson('{"key":"value"}')オブジェクトJSON 文字列をオブジェクトに変換
2toJsontoJson(github.event)文字列オブジェクトを JSON 文字列に変換
3hashFileshashFiles('**​/​package-lock.json')文字列ファイルのハッシュ値を計算(キャッシュキーに使用)
4formatformat('Hello {0}', 'World')文字列フォーマット文字列の生成
5containscontains(github.ref, 'main')真偽値文字列・配列に値が含まれるか判定
6startsWithstartsWith(github.ref, 'refs​/​tags​/​')真偽値文字列が特定の値で始まるか判定
7endsWithendsWith(github.ref, '​/​main')真偽値文字列が特定の値で終わるか判定
8joinjoin(matrix.os, '-')文字列配列を区切り文字で結合
9success()if: success()真偽値前のステップが成功したか判定
10failure()if: failure()真偽値前のステップが失敗したか判定
11always()if: always()真偽値常に実行(ステップ結果に関わらず)
12cancelled()if: cancelled()真偽値ワークフローがキャンセルされたか判定

背景

GitHub Actions の式とコンテキストの役割

GitHub Actions でワークフローを記述する際、静的な設定だけでは柔軟な処理を実現できません。たとえば、以下のようなニーズがあります。

  • プルリクエストのブランチ名に応じて、デプロイ先の環境を切り替えたい
  • 前のステップで生成されたビルド成果物のパスを、次のステップで使いたい
  • 複数の OS やバージョンでテストを並列実行し、結果を統合したい
  • キャッシュキーをファイルの内容に基づいて動的に生成したい

これらを実現するために、GitHub Actions では**式(Expression)コンテキスト(Context)**という仕組みが用意されています。

mermaidflowchart TB
  workflow["ワークフロー実行"]
  context["コンテキスト<br/>(実行環境の情報)"]
  expression["式<br/>(動的な値の計算)"]
  action["アクション実行"]

  workflow --> context
  context --> expression
  expression --> action

  context -.-> |"github, env, steps など"| expression
  expression -.-> |"fromJson, contains, hashFiles など"| action

上図のように、コンテキストは実行時の情報(イベント、環境変数、前ステップの結果など)を保持し、はそれらを組み合わせて動的に値を計算します。この 2 つを組み合わせることで、GitHub Actions の表現力が飛躍的に高まるのです。

式の基本構文

式は ${{ }} で囲んで記述します。この中では、JavaScript に似た構文で条件分岐、関数呼び出し、プロパティアクセスなどが可能です。

typescript// 基本的な式の構文
${{ expression }}
yaml# 実際の使用例
steps:
  - name: Conditional step
    if: ${{ github.ref == 'refs/heads/main' }}
    run: echo "This is main branch"

ここでは github.ref というコンテキストプロパティにアクセスし、== 演算子で比較しています。if 条件での利用が最も一般的ですが、runwithenv などあらゆる場所で式を活用できます。

課題

GitHub Actions の式・コンテキストで直面する課題

GitHub Actions を使い始めると、以下のような課題に直面することが多いでしょう。

課題 1:どのコンテキストを使えばよいか分からない

GitHub Actions には githubenvjobstepsrunnersecretsinputsmatrix など、多数のコンテキストが存在します。初めて使うときは、「イベント情報はどこから取得するの?」「前のステップの出力はどうやって参照するの?」と迷ってしまいがちです。

課題 2:JSON データの扱い方が分からない

GitHub Actions では、イベントペイロードやステップの出力が JSON 形式で提供されることがあります。しかし、そのままでは文字列として扱われるため、オブジェクトとして操作するには fromJson 関数が必要です。逆に、オブジェクトを JSON 文字列に変換する toJson も必要になる場面があります。

課題 3:キャッシュキーの生成が難しい

依存関係のキャッシュを効率的に使うには、ファイルの内容に基づいたハッシュ値をキャッシュキーに含める必要があります。hashFiles 関数を使えば簡単に実現できますが、使い方を知らないと手動でハッシュを計算しようとして複雑になってしまいます。

課題 4:条件分岐の書き方が複雑

複数の条件を組み合わせたり、文字列の一部を判定したりする際、どの関数を使えばよいか分からないことがあります。containsstartsWithendsWith などの関数を知っていれば簡潔に書けますが、知らないと冗長なスクリプトを書いてしまいがちです。

mermaidflowchart LR
  start["ワークフロー記述"]
  problem1["どのコンテキスト?"]
  problem2["JSON の扱い方?"]
  problem3["ハッシュ計算?"]
  problem4["条件分岐が複雑"]

  start --> problem1
  start --> problem2
  start --> problem3
  start --> problem4

これらの課題を解決するには、GitHub Actions の式とコンテキストの体系的な理解が必要です。

解決策

コンテキストの活用方法

GitHub Actions のコンテキストは、実行環境のさまざまな情報にアクセスするための仕組みです。ここでは、主要なコンテキストの使い方を具体的に見ていきましょう。

github コンテキスト

github コンテキストは、イベント、リポジトリ、コミットに関する情報を提供します。最も頻繁に使うコンテキストと言えるでしょう。

yaml# github コンテキストの基本的な使い方
name: GitHub Context Example

on: [push, pull_request]

jobs:
  context_example:
    runs-on: ubuntu-latest
    steps:
      - name: Display event information
        run: |
          echo "Event name: ${{ github.event_name }}"
          echo "Repository: ${{ github.repository }}"
          echo "Branch: ${{ github.ref }}"
          echo "Commit SHA: ${{ github.sha }}"

このステップでは、トリガーされたイベント名、リポジトリ名、ブランチ名、コミット SHA を表示しています。これらの情報は、条件分岐やタグ付けなどに活用できます。

yaml# ブランチ名に応じた条件分岐
- name: Deploy to production
  if: ${{ github.ref == 'refs/heads/main' }}
  run: echo "Deploying to production"

- name: Deploy to staging
  if: ${{ startsWith(github.ref, 'refs/heads/develop') }}
  run: echo "Deploying to staging"

github.ref は完全なリファレンス名(refs​/​heads​/​main など)を返すため、比較時には注意が必要です。startsWith 関数を使うと、プレフィックスマッチングが簡単に行えます。

steps コンテキスト

steps コンテキストは、前のステップの出力や結果を参照するために使います。ステップ間でデータを受け渡す際に非常に便利です。

yaml# steps コンテキストの使い方
- name: Generate version
  id: version
  run: echo "version=1.2.3" >> $GITHUB_OUTPUT

- name: Use version
  run: echo "Version is ${{ steps.version.outputs.version }}"

ここでは、id: version で識別されたステップが version という出力を生成し、次のステップで steps.version.outputs.version として参照しています。

yaml# ステップの実行結果を判定
- name: Run tests
  id: test
  continue-on-error: true
  run: npm test

- name: Handle test failure
  if: ${{ steps.test.outcome == 'failure' }}
  run: echo "Tests failed, but continuing"

outcome プロパティは、ステップが成功したか失敗したかを success または failure として返します。continue-on-error: true と組み合わせることで、失敗後の処理を柔軟に制御できます。

env コンテキスト

env コンテキストは、環境変数にアクセスするために使います。ワークフロー、ジョブ、ステップの各レベルで定義できます。

yaml# env コンテキストの使い方
env:
  GLOBAL_VAR: global

jobs:
  env_example:
    runs-on: ubuntu-latest
    env:
      JOB_VAR: job_level
    steps:
      - name: Display environment variables
        env:
          STEP_VAR: step_level
        run: |
          echo "Global: ${{ env.GLOBAL_VAR }}"
          echo "Job: ${{ env.JOB_VAR }}"
          echo "Step: ${{ env.STEP_VAR }}"

このように、スコープの異なる環境変数を階層的に定義できます。同名の変数がある場合、より狭いスコープが優先されます。

runner コンテキスト

runner コンテキストは、ジョブを実行しているランナーの情報を提供します。OS に応じた処理の分岐などに使えます。

yaml# runner コンテキストの使い方
- name: OS-specific command
  run: |
    echo "OS: ${{ runner.os }}"
    echo "Temp directory: ${{ runner.temp }}"
    echo "Tool cache: ${{ runner.tool_cache }}"

- name: Install dependencies (Ubuntu)
  if: ${{ runner.os == 'Linux' }}
  run: sudo apt-get install -y some-package

- name: Install dependencies (macOS)
  if: ${{ runner.os == 'macOS' }}
  run: brew install some-package

runner.osLinuxmacOSWindows のいずれかを返すため、OS 固有の処理を簡単に分岐できます。

JSON 操作関数:fromJson と toJson

GitHub Actions では、JSON データの変換が頻繁に必要になります。fromJsontoJson は、その変換を担う重要な関数です。

fromJson 関数

fromJson は、JSON 文字列をオブジェクトに変換します。主に、外部から取得した JSON データや、ステップの出力を構造化データとして扱う際に使います。

yaml# fromJson の基本的な使い方
jobs:
  json_example:
    runs-on: ubuntu-latest
    steps:
      - name: Parse JSON string
        id: parse
        run: |
          json='{"name":"MyApp","version":"1.0.0","tags":["stable","latest"]}'
          echo "data=$json" >> $GITHUB_OUTPUT

      - name: Access parsed data
        run: |
          echo "Name: ${{ fromJson(steps.parse.outputs.data).name }}"
          echo "Version: ${{ fromJson(steps.parse.outputs.data).version }}"

ここでは、JSON 文字列を fromJson で変換し、ドット記法でプロパティにアクセスしています。

yaml# マトリックス戦略での活用
jobs:
  matrix_from_json:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - name: Set matrix
        id: set-matrix
        run: |
          matrix='{"os":["ubuntu-latest","macos-latest"],"node":["16","18","20"]}'
          echo "matrix=$matrix" >> $GITHUB_OUTPUT

  test:
    needs: matrix_from_json
    runs-on: ${{ matrix.os }}
    strategy:
      matrix: ${{ fromJson(needs.matrix_from_json.outputs.matrix) }}
    steps:
      - name: Test
        run: echo "Testing on ${{ matrix.os }} with Node ${{ matrix.node }}"

動的にマトリックス戦略を生成できるため、外部ファイルや API から設定を読み込む際に非常に便利です。

toJson 関数

toJson は、オブジェクトを JSON 文字列に変換します。デバッグやログ出力、外部サービスへのデータ送信などに使います。

yaml# toJson の基本的な使い方
- name: Display GitHub event
  run: echo '${{ toJson(github.event) }}'

- name: Display matrix values
  run: echo '${{ toJson(matrix) }}'

toJson を使うと、構造化データを見やすく出力できます。特に、github.event の内容を確認する際に重宝します。

yaml# 条件分岐での活用
- name: Check pull request labels
  if: ${{ contains(toJson(github.event.pull_request.labels.*.name), 'deploy') }}
  run: echo "Deploy label found"

ここでは、プルリクエストのラベル配列を JSON 文字列に変換し、contains 関数で特定のラベルが含まれているか判定しています。

ハッシュ計算:hashFiles 関数

hashFiles 関数は、指定したパターンに一致するファイルの内容から SHA-256 ハッシュを計算します。キャッシュキーの生成に最適です。

yaml# hashFiles の基本的な使い方
- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

このように、package-lock.json の内容が変わるとハッシュ値が変わり、新しいキャッシュが作成されます。内容が同じであれば同じハッシュ値が返されるため、効率的なキャッシュ管理が可能です。

yaml# 複数ファイルのハッシュ計算
- name: Cache with multiple files
  uses: actions/cache@v3
  with:
    path: |
      ~/.cargo
      target
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}

複数のファイルパターンをカンマ区切りで指定することもできます。この場合、すべてのファイルの内容を組み合わせてハッシュが計算されます。

yaml# グロブパターンの活用
- name: Cache Python dependencies
  uses: actions/cache@v3
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements/**/*.txt') }}

**​/​ を使うことで、ディレクトリ階層を再帰的に検索できます。requirements ディレクトリ配下のすべての .txt ファイルが対象になります。

文字列判定関数:contains、startsWith、endsWith

文字列や配列の判定には、専用の関数を使うと簡潔に書けます。

yaml# contains の使い方
- name: Check branch
  if: ${{ contains(github.ref, 'feature') }}
  run: echo "This is a feature branch"

- name: Check commit message
  if: ${{ contains(github.event.head_commit.message, '[skip ci]') }}
  run: echo "CI skip requested"

contains は、第 1 引数が第 2 引数を含むかどうかを判定します。文字列だけでなく、配列に対しても使えます。

yaml# startsWith と endsWith の使い方
- name: Deploy on tag
  if: ${{ startsWith(github.ref, 'refs/tags/v') }}
  run: echo "Deploying version tag"

- name: Check file extension
  if: ${{ endsWith(github.event.head_commit.modified[0], '.md') }}
  run: echo "Markdown file modified"

startsWith は先頭一致、endsWith は末尾一致を判定します。バージョンタグの判定やファイル拡張子のチェックに便利です。

フォーマット関数:format と join

文字列の生成には、formatjoin が役立ちます。

yaml# format の使い方
- name: Format message
  run: |
    message="${{ format('Deploying {0} to {1} environment', github.sha, 'production') }}"
    echo "$message"

- name: Format with multiple placeholders
  run: |
    echo "${{ format('Build {0} on {1} completed at {2}', github.run_number, runner.os, github.event.head_commit.timestamp) }}"

format は、プレースホルダー {0}{1}{2} などに引数を埋め込みます。可読性の高いメッセージ生成に便利です。

yaml# join の使い方
- name: Join array
  run: |
    tags="${{ join(fromJson('["v1.0.0","latest","stable"]'), ', ') }}"
    echo "Tags: $tags"

- name: Join matrix values
  run: |
    echo "Testing: ${{ join(matrix.*, '-') }}"

join は、配列の要素を指定した区切り文字で結合します。タグのリストやマトリックス値の表示に活用できます。

ステップ制御関数:success、failure、always、cancelled

ステップの実行条件を制御する関数も重要です。

yaml# ステップ制御関数の使い方
- name: Run tests
  id: test
  run: npm test

- name: On success
  if: ${{ success() }}
  run: echo "All previous steps succeeded"

- name: On failure
  if: ${{ failure() }}
  run: echo "Some step failed"

- name: Cleanup
  if: ${{ always() }}
  run: echo "This always runs"

- name: On cancelled
  if: ${{ cancelled() }}
  run: echo "Workflow was cancelled"

これらの関数を使うことで、エラーハンドリングやクリーンアップ処理を柔軟に制御できます。

具体例

具体例 1:動的マトリックス戦略の構築

外部ファイルから設定を読み込み、動的にマトリックス戦略を構築する例を見てみましょう。

json// .github/test-config.json
{
  "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
  "node": ["16", "18", "20"],
  "exclude": [{ "os": "windows-latest", "node": "16" }]
}

この設定ファイルを読み込んで、マトリックステストを実行するワークフローを作成します。

yaml# 動的マトリックス戦略のワークフロー
name: Dynamic Matrix Test

on: [push, pull_request]

jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Read test configuration
        id: set-matrix
        run: |
          config=$(cat .github/test-config.json)
          echo "matrix=$config" >> $GITHUB_OUTPUT

最初のジョブでは、設定ファイルを読み込み、出力として保存しています。cat コマンドでファイル内容を取得し、$GITHUB_OUTPUT に書き込むことで、次のジョブで利用できるようにしています。

yamltest:
  needs: setup
  runs-on: ${{ matrix.os }}
  strategy:
    matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
  steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node }}

    - name: Display test environment
      run: |
        echo "OS: ${{ matrix.os }}"
        echo "Node: ${{ matrix.node }}"
        echo "Runner: ${{ runner.os }}"

fromJson で設定を変換し、マトリックス戦略として展開しています。これにより、設定ファイルを編集するだけでテスト環境を柔軟に変更できます。

yaml- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-${{ matrix.node }}-
      ${{ runner.os }}-node-

- name: Install dependencies
  run: yarn install --frozen-lockfile

- name: Run tests
  run: yarn test

キャッシュキーには、OS、Node バージョン、package-lock.json のハッシュを組み合わせています。これにより、環境ごとに適切なキャッシュが使われます。

具体例 2:プルリクエストのラベルに基づいた自動デプロイ

プルリクエストに特定のラベルが付いている場合のみデプロイを実行する例です。

yaml# ラベルベースの自動デプロイワークフロー
name: Auto Deploy

on:
  pull_request:
    types: [labeled, synchronize]

jobs:
  check-label:
    runs-on: ubuntu-latest
    outputs:
      should-deploy: ${{ steps.check.outputs.deploy }}
      environment: ${{ steps.check.outputs.env }}
    steps:
      - name: Check labels
        id: check
        run: |
          labels='${{ toJson(github.event.pull_request.labels.*.name) }}'
          echo "Labels: $labels"

          if echo "$labels" | grep -q "deploy:production"; then
            echo "deploy=true" >> $GITHUB_OUTPUT
            echo "env=production" >> $GITHUB_OUTPUT
          elif echo "$labels" | grep -q "deploy:staging"; then
            echo "deploy=true" >> $GITHUB_OUTPUT
            echo "env=staging" >> $GITHUB_OUTPUT
          else
            echo "deploy=false" >> $GITHUB_OUTPUT
            echo "env=none" >> $GITHUB_OUTPUT
          fi

ラベル情報を toJson で JSON 文字列に変換し、grep で特定のラベルを検索しています。結果を出力として保存し、次のジョブで利用します。

yamldeploy:
  needs: check-label
  if: ${{ needs.check-label.outputs.should-deploy == 'true' }}
  runs-on: ubuntu-latest
  environment:
    name: ${{ needs.check-label.outputs.environment }}
  steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Display deployment info
      run: |
        echo "Deploying to: ${{ needs.check-label.outputs.environment }}"
        echo "Branch: ${{ github.head_ref }}"
        echo "Commit: ${{ github.event.pull_request.head.sha }}"

    - name: Deploy to environment
      run: |
        echo "Deploying application..."
        # デプロイコマンドを実行

前のジョブの出力を参照し、デプロイの実行可否と環境を判定しています。if 条件により、ラベルが付いている場合のみジョブが実行されます。

具体例 3:複数ファイルのハッシュを使ったキャッシュ戦略

モノレポ構成で、複数のプロジェクトが異なる依存関係を持つ場合のキャッシュ戦略です。

yaml# モノレポのキャッシュ戦略
name: Monorepo Build

on: [push]

jobs:
  build-frontend:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Cache frontend dependencies
        uses: actions/cache@v3
        with:
          path: frontend/node_modules
          key: frontend-${{ runner.os }}-${{ hashFiles('frontend/package-lock.json', 'frontend/yarn.lock') }}
          restore-keys: |
            frontend-${{ runner.os }}-

      - name: Install frontend dependencies
        working-directory: frontend
        run: yarn install --frozen-lockfile

      - name: Build frontend
        working-directory: frontend
        run: yarn build

frontend ディレクトリの依存関係ファイルのみをハッシュ計算の対象にすることで、無駄なキャッシュ再生成を防いでいます。

yamlbuild-backend:
  runs-on: ubuntu-latest
  steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Cache backend dependencies
      uses: actions/cache@v3
      with:
        path: |
          backend/node_modules
          backend/.yarn/cache
        key: backend-${{ runner.os }}-${{ hashFiles('backend/package-lock.json', 'backend/.yarnrc.yml') }}
        restore-keys: |
          backend-${{ runner.os }}-

    - name: Install backend dependencies
      working-directory: backend
      run: yarn install --immutable

    - name: Build backend
      working-directory: backend
      run: yarn build

バックエンドも同様に、独自の依存関係ファイルでキャッシュキーを生成しています。複数のパスをキャッシュ対象に含めることもできます。

yamlintegration-test:
  needs: [build-frontend, build-backend]
  runs-on: ubuntu-latest
  steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Cache all dependencies
      uses: actions/cache@v3
      with:
        path: |
          frontend/node_modules
          backend/node_modules
        key: all-deps-${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/.yarnrc.yml') }}

    - name: Run integration tests
      run: yarn test:integration

統合テストでは、すべてのプロジェクトの依存関係をまとめてキャッシュしています。**​/​ パターンで、すべてのディレクトリから該当ファイルを検索できます。

具体例 4:条件付きステップ実行とエラーハンドリング

複雑な条件分岐とエラーハンドリングを組み合わせた例です。

yaml# 条件付きステップとエラーハンドリング
name: Advanced Workflow

on: [push, pull_request]

jobs:
  test-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Check if tests should run
        id: should-test
        run: |
          if [[ "${{ github.event_name }}" == "pull_request" ]] || [[ "${{ contains(github.event.head_commit.message, '[test]') }}" == "true" ]]; then
            echo "run=true" >> $GITHUB_OUTPUT
          else
            echo "run=false" >> $GITHUB_OUTPUT
          fi

プルリクエストの場合、またはコミットメッセージに [test] が含まれる場合にテストを実行する判定をしています。

yaml- name: Run unit tests
  id: unit-test
  if: ${{ steps.should-test.outputs.run == 'true' }}
  continue-on-error: true
  run: yarn test:unit

- name: Run integration tests
  id: integration-test
  if: ${{ steps.should-test.outputs.run == 'true' && steps.unit-test.outcome == 'success' }}
  continue-on-error: true
  run: yarn test:integration

ユニットテストが成功した場合のみ、統合テストを実行しています。continue-on-error により、失敗してもワークフローは継続します。

yaml- name: Report test results
  if: ${{ always() && steps.should-test.outputs.run == 'true' }}
  run: |
    unit_result="${{ steps.unit-test.outcome }}"
    integration_result="${{ steps.integration-test.outcome }}"

    echo "Unit tests: $unit_result"
    echo "Integration tests: $integration_result"

    if [[ "$unit_result" == "failure" ]] || [[ "$integration_result" == "failure" ]]; then
      echo "::error::Some tests failed"
      exit 1
    fi

テスト結果をまとめて報告し、いずれかが失敗していればワークフロー全体を失敗させています。always() により、前のステップが失敗しても必ず実行されます。

yaml- name: Deploy on success
  if: ${{ success() && github.ref == 'refs/heads/main' }}
  run: |
    echo "All tests passed, deploying..."
    # デプロイコマンドを実行

- name: Cleanup on failure
  if: ${{ failure() }}
  run: |
    echo "Workflow failed, cleaning up..."
    # クリーンアップコマンドを実行

- name: Always cleanup
  if: ${{ always() }}
  run: |
    echo "Performing final cleanup..."
    # 最終クリーンアップコマンドを実行

成功時のデプロイ、失敗時のクリーンアップ、常に実行される最終処理を、それぞれの条件関数で制御しています。

具体例 5:イベントペイロードの活用

github.event から詳細な情報を取得し、柔軟な処理を実現する例です。

yaml# イベントペイロードの活用
name: Event Payload Example

on:
  pull_request:
    types: [opened, synchronize, reopened]
  issue_comment:
    types: [created]

jobs:
  handle-event:
    runs-on: ubuntu-latest
    steps:
      - name: Display full event payload
        run: echo '${{ toJson(github.event) }}'

      - name: Handle pull request event
        if: ${{ github.event_name == 'pull_request' }}
        run: |
          echo "PR Number: ${{ github.event.pull_request.number }}"
          echo "PR Title: ${{ github.event.pull_request.title }}"
          echo "PR Author: ${{ github.event.pull_request.user.login }}"
          echo "Base Branch: ${{ github.event.pull_request.base.ref }}"
          echo "Head Branch: ${{ github.event.pull_request.head.ref }}"

プルリクエストイベントでは、番号、タイトル、作成者、ブランチ名などの詳細情報にアクセスできます。

yaml- name: Check changed files
  if: ${{ github.event_name == 'pull_request' }}
  run: |
    files='${{ toJson(github.event.pull_request.changed_files) }}'
    echo "Changed files count: $files"

    # ファイルの差分を取得してチェック
    git fetch origin ${{ github.event.pull_request.base.ref }}
    changed_files=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD)

    if echo "$changed_files" | grep -q "^src/"; then
      echo "Source files changed, running tests"
    fi

変更されたファイルの情報を元に、必要なテストやビルドを判断できます。

yaml- name: Handle issue comment event
  if: ${{ github.event_name == 'issue_comment' }}
  run: |
    echo "Comment Author: ${{ github.event.comment.user.login }}"
    echo "Comment Body: ${{ github.event.comment.body }}"
    echo "Issue Number: ${{ github.event.issue.number }}"

    # コメント内容に基づいた処理
    comment="${{ github.event.comment.body }}"
    if [[ "$comment" == "/deploy"* ]]; then
      echo "Deploy command detected"
      # デプロイ処理を実行
    fi

コメントイベントでは、コメント内容や Issue 番号にアクセスし、チャットオプス的な操作が可能です。

yaml- name: Check user permissions
  if: ${{ github.event_name == 'issue_comment' }}
  run: |
    author="${{ github.event.comment.user.login }}"
    author_association="${{ github.event.comment.author_association }}"

    echo "Author: $author"
    echo "Association: $author_association"

    if [[ "$author_association" == "OWNER" ]] || [[ "$author_association" == "MEMBER" ]]; then
      echo "User has required permissions"
    else
      echo "User does not have required permissions"
      exit 1
    fi

コメント作成者の権限を確認し、適切な権限を持つユーザーのみが操作できるように制御しています。

まとめ

GitHub Actions のコンテキストと式は、ワークフローの表現力を大きく高める強力な機能です。本記事では、以下の内容を解説しました。

  • 主要なコンテキストgithubenvjobstepsrunnersecretsinputsmatrix の使い方と活用シーン
  • JSON 操作関数fromJson でオブジェクトに変換、toJson で JSON 文字列に変換する方法
  • ハッシュ計算hashFiles でファイルの内容からハッシュを生成し、効率的なキャッシュ管理を実現
  • 文字列判定関数containsstartsWithendsWith で柔軟な条件分岐を記述
  • フォーマット関数formatjoin で読みやすいメッセージを生成
  • ステップ制御関数success()failure()always()cancelled() でエラーハンドリングとクリーンアップを制御

これらの機能を組み合わせることで、動的なマトリックス戦略、条件付きデプロイ、複雑なエラーハンドリングなど、高度なワークフローを実現できます。

早見表を手元に置きながら、ぜひ実際のプロジェクトで活用してみてください。GitHub Actions の柔軟性を最大限に引き出し、より効率的な CI/CD パイプラインを構築できるでしょう。

関連リンク