GitHub Actions 基本:ワークフロー、ジョブ、ステップ

1. 概要

GitHub Actions は GitHub に統合された CI/CD ツールで、専用の CI サーバーなしに、ビルド、テスト、デプロイを自動化できます。このガイドでは、3 つの主要な概念(ワークフロー、ジョブ、ステップ)について説明し、Maven を使用した Spring Boot プロジェクトの具体的な例を提供します。

このガイドを読み終わったら、コードをプッシュするたびにテストを自動実行するワークフローファイルを作成でき、ジョブが並列または順序通りに実行される方法を理解し、ワークフローが失敗したときのデバッグ方法を知ることができます。

2. ワークフロー(Workflow)とは?

ワークフロー(Workflow)は、リポジトリの .github/workflows/ ディレクトリにある YAML ファイルです。各ワークフローは、いつ実行するか(トリガー)と何を実行するか(ジョブ)を定義します。

# .github/workflows/ci.yml
name: CI Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
      - name: Build with Maven
        run: mvn -B package

説明:

  • ファイルの先頭の name は、GitHub の Actions タブに表示される名前です。
  • on はトリガーを宣言します。ここでは、push または pull_request が main ブランチに対して実行されたときにワークフローが実行されます。
  • jobs.build は、build という名前の単一のジョブで、ubuntu-latest の仮想マシン上で実行されます。

注意: ファイルは正しいパス .github/workflows/*.yml に配置する必要があります。ディレクトリが異なると、GitHub がワークフローを認識できません。

3. ジョブ(Job):独立した実行単位

1 つのワークフローには複数のジョブを含めることができます。各ジョブは独立した runner(仮想マシン)で実行され、デフォルトではジョブは 並列実行 されます。ただし、needs を宣言した場合は例外です。

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn -B test

  deploy:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - run: echo "Deploying application..."

説明:

  • test と deploy は 2 つの独立したジョブで、各ジョブはクリーンな runner 環境を持ち、ファイルシステムを共有しません。
  • needs: test により、deploy は test が正常に完了するのを待ってから実行されます。これは順序付き関係を作成します。
  • needs がない場合、GitHub Actions は test と deploy を同時に実行します。

3.1. ジョブ間でのデータ共有

各ジョブが独立した runner を持つため、ジョブ間でファイルを転送するには artifacts を使用する必要があります。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn -B package
      - uses: actions/upload-artifact@v4
        with:
          name: app-jar
          path: target/*.jar

  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app-jar

説明:

  • upload-artifact は、ジョブ build からの .jar ファイルを GitHub の一時ストレージにアップロードします。
  • ジョブ deploy の download-artifact は、新しい runner にそのファイルをダウンロードし直します。
  • これはジョブ間でデータを転送する唯一の方法です(通常の環境変数は使用できません)。

4. ステップ(Step):最小の操作単位

ステップはジョブ内の特定の操作で、上から下へ順序通りに実行されます。ステップには 2 つの主な種類があります:uses を使用する(事前に作成された action を呼び出す)か、run を使用する(shell コマンドを実行する)です。

steps:
  - name: Checkout code
    uses: actions/checkout@v4

  - name: Cache Maven dependencies
    uses: actions/cache@v4
    with:
      path: ~/.m2/repository
      key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}

  - name: Run tests
    run: mvn -B test

  - name: Print result
    run: echo "Test step finished with status ${{ job.status }}"

説明:

  • ステップ Checkout code は、事前に作成された action actions/checkout を使用して、ソースコードを runner にチェックアウトします。
  • ステップ Cache Maven dependencies は、~/.m2/repository ディレクトリをキャッシュし、以降のビルドを高速化します。依存関係を再度ダウンロードする必要がないためです。
  • キャッシュの key は pom.xml のハッシュに基づいています。pom.xml が変更されると、古いキャッシュは破棄され、新しいキャッシュが作成されます。
  • 最後のステップは、run を使用して通常の shell コマンドを実行し、${{ job.status }} などの context を参照できます。

5. 環境変数とシークレット

通常、機密設定(API キー、トークン)をワークフローに渡す必要がありますが、YAML ファイルにハードコードしたくない場合があります。

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      SPRING_PROFILES_ACTIVE: prod
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to server
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
        run: |
          echo "Deploying with profile $SPRING_PROFILES_ACTIVE"
          curl -H "Authorization: Bearer $DEPLOY_TOKEN" https://api.example.com/deploy

説明:

  • ジョブレベルの env は、そのジョブ内のすべてのステップに適用されます(SPRING_PROFILES_ACTIVE)。
  • ステップレベルの env は、そのステップにのみ適用されます(DEPLOY_TOKEN)。
  • secrets.DEPLOY_TOKEN はリポジトリの Settings → Secrets and variables → Actions から取得され、ログに実際の値が表示されることはありません。

注意: echo $DEPLOY_TOKEN でシークレット値をログに直接出力しないでください。GitHub は自動的にマスキングしますが、シークレットを出力しないことが最善です。

6. マトリックス(Matrix):複数のバージョンを同時に実行

複数の Java バージョンまたは OS でテストする必要がある場合、matrix を使用するとジョブの繰り返し記述を避けられます。

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java: [17, 21]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
      - run: mvn -B test

説明:

  • strategy.matrix.java は値のリスト [17, 21] を宣言します。
  • GitHub Actions は自動的に 2 つの並列ジョブ を作成し、各ジョブは対応する Java バージョンで実行されます。
  • この方法により、YAML の繰り返し記述を節約でき、複数の環境でコードが正常に実行されることを確認する必要がある場合に適しています。

7. シンプルなテストでワークフローを検証

ワークフローは JUnit で直接テストされませんが、ワークフロー内の mvn test ステップがプロジェクトの正しいテストスイートを実行していることを確認する必要があります。以下は、CI が実行する OrderService の簡単なテスト例です:

class OrderServiceTest {

    private final OrderService orderService = new OrderService();

    @Test
    void shouldCalculateTotalPriceCorrectly() {
        Order order = new Order("ORD-001", List.of(
                new OrderItem("Keyboard", 2, BigDecimal.valueOf(50)),
                new OrderItem("Mouse", 1, BigDecimal.valueOf(20))
        ));

        BigDecimal total = orderService.calculateTotal(order);

        assertThat(total).isEqualByComparingTo(BigDecimal.valueOf(120));
    }
}

説明:

  • このテストは src/test/java にあり、ワークフローのステップで mvn -B test によって自動実行されます。
  • テストが失敗した場合、ステップ Run tests はエラーを報告し(終了コードが 0 以外)、ジョブは停止し、依存するジョブ(needs)は実行されません。
  • これが CI が有用な理由です。エラーのあるコードは main にマージされる前にブロックされます。

GitHub Actions UI(Actions タブ)で実行する結果:

✓ Checkout code
✓ Set up JDK 21
✓ Build with Maven
✓ Run tests (shouldCalculateTotalPriceCorrectly PASSED)

8. 一般的なエラー

  • YAML のインデント エラー:GitHub Actions は YAML を使用しており、インデントが 1 スペース間違うとジョブまたはステップが認識されず、通常「Invalid workflow file」エラーが報告されます。
  • runs-on の忘却:各ジョブは必ず runs-on を持つ必要があります。欠落するとワークフローが解析時に失敗します。
  • ジョブ間での環境変数の使用:env と出力変数は通常、ジョブ間で自動的に転送されません。outputs または artifact を使用する必要があります。
  • 依存関係が変更されてもキャッシュ キーが変わらない:キャッシュ key が一般的すぎる場合(例えば maven-cache のみ)、古い依存関係を含む古いキャッシュを誤って使用する可能性があります。
  • すべてのプッシュで重いワークフローを実行:paths または branches を制限しない場合、小さなコミット(README の編集など)でも完全なパイプラインのビルド + テストがトリガーされ、Actions 実行分数を浪費します(無料の制限があります)。

注意: プロジェクトがシンプルなビルドのみを必要とし、多くの環境がない場合、matrix や artifact を使用する必要はありません。不要な複雑さを追加するとワークフローの保守が困難になります。

9. まとめ

ワークフローはパイプライン全体を定義する YAML ファイルで、ジョブは独立した runner で実行される独立した実行ブロックであり、ステップはジョブ内の特定の操作です。この 3 つのレイヤーを理解することで、CI/CD パイプラインを明確に整理できます。どのジョブが並列実行され、どのジョブが needs で相互に待機し、データ共有が必要な場合は artifact を使用するかを理解できます。

初めの段階では、ワークフローをシンプルに保ちましょう(1 つのジョブ、いくつかの基本的なステップ:チェックアウト、Java セットアップ、テスト)。プロジェクトが大きくなったら、matrix、cache を追加し、build/test/deploy を別々のジョブに分割して、管理やデバッグを容易にしてください。

github-actionsci-cddevopsjavaautomation