GitHub Actions ワークフロー入門:基礎から実践まで

Shunku

はじめに

GitHub Actionsは、GitHubに組み込まれた強力な自動化プラットフォームです。リポジトリ内で直接ソフトウェア開発ワークフローを自動化できます。コードのビルドとテストからアプリケーションのデプロイまで、あらゆる作業を自動化できます。

この記事では、効果的なワークフローを作成するために必要な基本概念を解説します。

コアコンセプト

flowchart TB
    subgraph Workflow["Workflow (workflow.yml)"]
        subgraph Job1["Job: build"]
            S1["Step 1: Checkout"]
            S2["Step 2: Setup Node"]
            S3["Step 3: Install deps"]
            S4["Step 4: Run tests"]
        end
        subgraph Job2["Job: deploy"]
            S5["Step 1: Checkout"]
            S6["Step 2: Deploy"]
        end
    end

    Event["Event (push, PR, schedule)"] --> Workflow
    Job1 --> Job2

    style Event fill:#f59e0b,color:#fff
    style Workflow fill:#3b82f6,color:#fff
    style Job1 fill:#8b5cf6,color:#fff
    style Job2 fill:#22c55e,color:#fff

階層構造の概要

コンポーネント 説明
Workflow YAMLファイルで定義された自動化プロセス
Event ワークフローを開始するトリガー
Job 同じランナー上で実行されるステップの集合
Step ジョブ内の個々のタスク
Action 再利用可能なコードユニット
Runner ワークフローを実行するサーバー

YAML構文の基礎

ワークフローはYAMLで記述します。主要な構文ルールは以下の通りです:

# キーと値のペア
name: My Workflow

# ネスト構造はインデント(スペース2つ)を使用
jobs:
  build:
    runs-on: ubuntu-latest

# リストはハイフンを使用
steps:
  - name: First step
  - name: Second step

# 複数行の文字列
run: |
  echo "Line 1"
  echo "Line 2"

# 1行の文字列
run: echo "Single line"

ワークフローファイルの構造

ワークフローファイルは .github/workflows/ ディレクトリに配置します:

# .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: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

イベントトリガー

プッシュとプルリクエストイベント

on:
  push:
    branches:
      - main
      - 'release/**'
    paths:
      - 'src/**'
      - '!src/**/*.md'
    tags:
      - 'v*'

  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

スケジュールトリガー

on:
  schedule:
    # 毎日UTC 00:00に実行
    - cron: '0 0 * * *'
    # 毎週月曜日UTC 9:00に実行
    - cron: '0 9 * * 1'

手動トリガー

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'デプロイ環境'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production

      debug:
        description: 'デバッグモードを有効化'
        required: false
        type: boolean
        default: false

トリガーの比較

トリガー ユースケース
push 指定ブランチへのすべてのコミットで実行
pull_request PRのオープンや更新時に実行
schedule 定期タスク(ナイトリービルド、クリーンアップ)
workflow_dispatch オプション入力付きの手動実行
workflow_call 別のワークフローから呼び出し
repository_dispatch API経由の外部イベントでトリガー

ジョブとステップ

ジョブの設定

jobs:
  build:
    name: Build Application
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build

  test:
    name: Run Tests
    runs-on: ubuntu-latest
    needs: build  # buildジョブの完了を待つ

    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

ステップ:アクション vs コマンド

steps:
  # 事前ビルドされたアクションを使用
  - name: Checkout repository
    uses: actions/checkout@v4
    with:
      fetch-depth: 0

  # シェルコマンドを実行
  - name: Build project
    run: |
      npm ci
      npm run build
    working-directory: ./frontend

  # 特定のシェルを使用
  - name: PowerShell script
    shell: pwsh
    run: Get-Process

ジョブの依存関係

flowchart LR
    subgraph Parallel["並列実行"]
        lint["lint"]
        test["test"]
    end

    build["build"] --> Parallel
    Parallel --> deploy["deploy"]

    style build fill:#3b82f6,color:#fff
    style Parallel fill:#8b5cf6,color:#fff
    style deploy fill:#22c55e,color:#fff
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  lint:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Linting..."

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

  deploy:
    needs: [lint, test]  # 両方の完了を待つ
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

式とコンテキスト

コンテキストの使用

steps:
  - name: Show context information
    run: |
      echo "Repository: ${{ github.repository }}"
      echo "Branch: ${{ github.ref_name }}"
      echo "Actor: ${{ github.actor }}"
      echo "Event: ${{ github.event_name }}"
      echo "SHA: ${{ github.sha }}"

主要なコンテキスト

コンテキスト 説明
github ワークフロー実行情報
env 環境変数
vars リポジトリ/組織変数
secrets 暗号化されたシークレット
job 現在のジョブ情報
steps ステップの出力とステータス
runner ランナー情報
matrix 現在のジョブのマトリックス値

条件付き実行

steps:
  - name: mainブランチのみ
    if: github.ref == 'refs/heads/main'
    run: echo "On main branch"

  - name: プルリクエストのみ
    if: github.event_name == 'pull_request'
    run: echo "This is a PR"

  - name: 前のステップが失敗しても実行
    if: always()
    run: echo "This always runs"

  - name: 失敗時のみ実行
    if: failure()
    run: echo "Previous step failed"

  - name: フォークではスキップ
    if: github.repository == 'owner/repo'
    run: echo "Not a fork"

環境変数

変数の定義

env:
  # ワークフローレベル
  NODE_ENV: production

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # ジョブレベル
      CI: true

    steps:
      - name: Build
        env:
          # ステップレベル
          API_URL: https://api.example.com
        run: |
          echo "NODE_ENV: $NODE_ENV"
          echo "CI: $CI"
          echo "API_URL: $API_URL"

シークレットの使用

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}
    run: ./deploy.sh

  - name: Login to Docker Hub
    uses: docker/login-action@v3
    with:
      username: ${{ secrets.DOCKER_USERNAME }}
      password: ${{ secrets.DOCKER_PASSWORD }}

実践例:完全なCIワークフロー

name: CI

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

env:
  NODE_VERSION: '20'

jobs:
  lint:
    name: Lint Code
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - run: npm ci
      - run: npm run lint

  test:
    name: Run Tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - run: npm ci
      - run: npm test -- --coverage

      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

ベストプラクティス

1. アクションのバージョンを固定する

# 良い例:特定のバージョンまたはSHAを使用
- uses: actions/checkout@v4
- uses: actions/setup-node@v4.0.2
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608

# 避けるべき:latestやブランチの使用
- uses: actions/checkout@main  # これはやめましょう

2. キャッシュを使用する

- name: Cache node modules
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

3. シークレットの露出を最小化

# 良い例:環境変数として渡す
- name: Deploy
  env:
    TOKEN: ${{ secrets.DEPLOY_TOKEN }}
  run: ./deploy.sh

# 避けるべき:コマンド内にインライン(ログに漏れる可能性)
- run: ./deploy.sh ${{ secrets.DEPLOY_TOKEN }}  # これはやめましょう

4. タイムアウトを設定する

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15  # 暴走ジョブを防止

まとめ

概念 ポイント
Workflow .github/workflows/内のYAMLファイル
トリガー push, pull_request, schedule, workflow_dispatch
ジョブ デフォルトで並列実行、needsで依存関係を指定
ステップ アクションにはuses、コマンドにはrun
コンテキスト ${{ github.* }}, ${{ secrets.* }}など
条件 if式で実行を制御

これらの基礎を身につければ、コードをプッシュしたりプルリクエストを開いたりするたびに、アプリケーションを自動的にビルド、テスト、デプロイするワークフローを作成できます。

参考資料

  • Manning - GitHub Actions in Action, Chapter 3
  • O'Reilly - Learning GitHub Actions, Chapters 1-4
  • GitHub Docs - Workflow Syntax