資料 - ワークフローとアクション
1. はじめに
GitHub Actionsは、リポジトリ内でCI/CDパイプラインを構築できる強力な自動化プラットフォームです。本記事では、GitHub Actionsの公式ドキュメントをもとに、実務で必要となる全ての機能を体系的に解説します。
2. 目次
- はじめに
- 目次
- ワークフローの基本構造
- イベントトリガーの仕組み
- 変数とコンテキスト
- 式評価とステータスチェック
- ワークフローコマンド
- 依存関係のキャッシング
- 再利用可能なワークフロー
- 環境とデプロイメント保護
- カスタムアクションの作成
- 実践的なパターン
- トラブルシューティング
- まとめ
3. ワークフローの基本構造
3.1 YAMLファイルの配置
ワークフローファイルは .github/workflows/ ディレクトリに配置します。ファイル拡張子は .yml または .yaml です。
3.2 基本的な構成要素
name: "CI パイプライン"
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
NODE_VERSION: '20'
DATABASE_URL: ${{ secrets.DATABASE_URL }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "リポジトリのチェックアウト"
uses: actions/checkout@v5
- name: "Node.js のセットアップ"
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: "依存関係のインストール"
run: npm ci
- name: "テストの実行"
run: npm test
3.3 ワークフロー実行の流れ
3.4 主要なキーワード
| キーワード | 説明 | 必須 |
|---|---|---|
name |
ワークフロー名 | 任意 |
on |
トリガーイベント | 必須 |
jobs |
実行するジョブの定義 | 必須 |
runs-on |
ランナーの種類 | 必須 |
steps |
ジョブ内の処理ステップ | 必須 |
env |
環境変数 | 任意 |
permissions |
トークンの権限設定 | 任意 |
concurrency |
並行実行制御 | 任意 |
4. イベントトリガーの仕組み
4.1 主要なイベント一覧
GitHub Actionsは30種類以上のイベントに対応していますが、実務でよく使用するものを紹介します。
4.2 push イベント
コミットがプッシュされたときにトリガーされます。
on:
push:
branches:
- main
- 'releases/**'
paths:
- '**.js'
- '!docs/**'
tags:
- v1.*
フィルタリングオプション:
-
branches/branches-ignore: ブランチ名でフィルタ -
paths/paths-ignore: ファイルパスでフィルタ -
tags/tags-ignore: タグ名でフィルタ
4.3 pull_request イベント
プルリクエストに関連するアクションでトリガーされます。
on:
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- main
paths:
- 'src/**'
アクティビティタイプ:
-
opened: プルリクエスト作成時 -
synchronize: プルリクエストへのプッシュ時 -
reopened: プルリクエスト再オープン時 -
closed: プルリクエストクローズ時 -
labeled/unlabeled: ラベル変更時 -
assigned/unassigned: アサイン変更時 -
review_requested: レビュー依頼時
4.4 schedule イベント
cron式を使用して定期実行します。
on:
schedule:
# 毎日午前9時(UTC)に実行
- cron: '0 9 * * *'
# 月曜日と木曜日の午前5時30分(UTC)に実行
- cron: '30 5 * * 1,4'
cron式の構文:
┌─────────── 分 (0 - 59)
│ ┌───────── 時 (0 - 23)
│ │ ┌─────── 日 (1 - 31)
│ │ │ ┌───── 月 (1 - 12)
│ │ │ │ ┌─── 曜日 (0 - 6, 日曜=0)
│ │ │ │ │
* * * * *
4.5 workflow_dispatch イベント
手動でワークフローを実行する場合に使用します。
on:
workflow_dispatch:
inputs:
environment:
description: 'デプロイ先の環境'
required: true
type: choice
options:
- development
- staging
- production
logLevel:
description: 'ログレベル'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
dryRun:
description: 'ドライラン実行'
required: false
type: boolean
default: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: "デプロイ実行"
run: |
echo "環境: ${{ inputs.environment }}"
echo "ログレベル: ${{ inputs.logLevel }}"
echo "ドライラン: ${{ inputs.dryRun }}"
4.6 workflow_run イベント
他のワークフロー完了時にトリガーされます。
on:
workflow_run:
workflows: ["ビルドワークフロー"]
types:
- completed
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: "成功時のデプロイ"
run: echo "デプロイを開始します"
4.7 イベントのフィルタリングパターン
4.7.1 グロブパターンの使用
on:
push:
branches:
# feature/で始まる全てのブランチ
- 'feature/**'
# releases/10 のような形式
- 'releases/[0-9]+'
# v1.0.0 のようなタグ
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
4.7.2 否定パターン
on:
push:
branches:
- 'releases/**'
# releases/**-alpha を除外
- '!releases/**-alpha'
5. 変数とコンテキスト
5.1 デフォルト環境変数
GitHub Actionsが自動的に設定する環境変数です。
jobs:
show-info:
runs-on: ubuntu-latest
steps:
- name: "環境変数の表示"
run: |
echo "リポジトリ: $GITHUB_REPOSITORY"
echo "ブランチ: $GITHUB_REF_NAME"
echo "SHA: $GITHUB_SHA"
echo "アクター: $GITHUB_ACTOR"
echo "ワークフロー名: $GITHUB_WORKFLOW"
echo "実行番号: $GITHUB_RUN_NUMBER"
主要な環境変数:
| 変数名 | 説明 | 例 |
|---|---|---|
GITHUB_REPOSITORY |
リポジトリの所有者と名前 | yamada-taro/my-app |
GITHUB_REF |
ブランチまたはタグの完全な ref | refs/heads/main |
GITHUB_REF_NAME |
ブランチまたはタグ名 | main |
GITHUB_SHA |
コミット SHA | ffac537e6cbbf934b08745a378932722df287a53 |
GITHUB_ACTOR |
ワークフローを開始したユーザー名 | yamada-taro |
GITHUB_WORKSPACE |
ワークスペースディレクトリのパス | /home/runner/work/my-app/my-app |
RUNNER_OS |
ランナーのOS |
Linux, Windows, macOS
|
5.2 コンテキストの使用
コンテキストは ${{ }} 構文でアクセスします。
5.2.1 github コンテキスト
jobs:
context-demo:
runs-on: ubuntu-latest
steps:
- name: "GitHub コンテキストの使用"
run: |
echo "イベント名: ${{ github.event_name }}"
echo "リポジトリ: ${{ github.repository }}"
echo "ブランチ: ${{ github.ref_name }}"
echo "アクター: ${{ github.actor }}"
echo "ジョブID: ${{ github.job }}"
5.2.2 env コンテキスト
env:
GLOBAL_VAR: "グローバル変数"
jobs:
env-demo:
runs-on: ubuntu-latest
env:
JOB_VAR: "ジョブレベル変数"
steps:
- name: "環境変数の使用"
env:
STEP_VAR: "ステップレベル変数"
run: |
echo "グローバル: ${{ env.GLOBAL_VAR }}"
echo "ジョブ: ${{ env.JOB_VAR }}"
echo "ステップ: ${{ env.STEP_VAR }}"
優先順位: ステップ > ジョブ > ワークフロー
5.2.3 secrets コンテキスト
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: "APIキーの使用"
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: |
echo "APIキーは自動的にマスクされます"
echo $API_KEY
5.2.4 steps コンテキスト
jobs:
multi-step:
runs-on: ubuntu-latest
steps:
- name: "バージョン番号の生成"
id: version
run: echo "number=1.0.${{ github.run_number }}" >> $GITHUB_OUTPUT
- name: "ビルド結果の出力"
id: build
run: |
echo "status=success" >> $GITHUB_OUTPUT
echo "artifact=app-v1.0.tar.gz" >> $GITHUB_OUTPUT
- name: "前ステップの出力を使用"
run: |
echo "バージョン: ${{ steps.version.outputs.number }}"
echo "ビルド状況: ${{ steps.build.outputs.status }}"
echo "アーティファクト: ${{ steps.build.outputs.artifact }}"
5.2.5 needs コンテキスト
jobs:
build:
runs-on: ubuntu-latest
outputs:
build_id: ${{ steps.build.outputs.id }}
artifact_name: ${{ steps.build.outputs.name }}
steps:
- id: build
run: |
echo "id=${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "name=app-build-${{ github.run_number }}.zip" >> $GITHUB_OUTPUT
test:
needs: build
runs-on: ubuntu-latest
steps:
- name: "ビルド情報の使用"
run: |
echo "ビルドID: ${{ needs.build.outputs.build_id }}"
echo "アーティファクト: ${{ needs.build.outputs.artifact_name }}"
5.2.6 matrix コンテキスト
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
include:
- os: ubuntu-latest
node: 22
experimental: true
steps:
- name: "マトリックス情報の表示"
run: |
echo "OS: ${{ matrix.os }}"
echo "Node.js: ${{ matrix.node }}"
echo "実験的: ${{ matrix.experimental }}"
5.3 設定変数(vars コンテキスト)
リポジトリ、組織、環境レベルで設定した変数にアクセスします。
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: "設定変数の使用"
run: |
echo "環境: ${{ vars.ENVIRONMENT_NAME }}"
echo "APIエンドポイント: ${{ vars.API_ENDPOINT }}"
echo "リージョン: ${{ vars.AWS_REGION }}"
5.4 コンテキストの利用可能範囲
6. 式評価とステータスチェック
6.1 基本的な演算子
jobs:
conditional:
runs-on: ubuntu-latest
steps:
- name: "等価比較"
if: github.ref == 'refs/heads/main'
run: echo "mainブランチです"
- name: "不等価比較"
if: github.event_name != 'schedule'
run: echo "スケジュール実行ではありません"
- name: "AND条件"
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: echo "mainブランチへのpushです"
- name: "OR条件"
if: github.event_name == 'push' || github.event_name == 'pull_request'
run: echo "pushまたはpull_requestです"
6.2 組み込み関数
6.2.1 contains 関数
jobs:
check-labels:
runs-on: ubuntu-latest
if: contains(github.event.issue.labels.*.name, 'bug')
steps:
- name: "バグラベル付きのIssue"
run: echo "このIssueにはbugラベルが付いています"
6.2.2 startsWith / endsWith 関数
jobs:
branch-check:
runs-on: ubuntu-latest
steps:
- name: "featureブランチのチェック"
if: startsWith(github.ref, 'refs/heads/feature/')
run: echo "featureブランチです"
- name: "JSファイルのチェック"
if: endsWith(github.event.head_commit.modified[0], '.js')
run: echo "JavaScriptファイルが変更されました"
6.2.3 format 関数
jobs:
format-demo:
runs-on: ubuntu-latest
steps:
- name: "フォーマット済みメッセージ"
run: |
MESSAGE=$(echo '${{ format("ビルド {0} が {1} で完了しました", github.run_number, github.ref_name) }}')
echo $MESSAGE
6.2.4 hashFiles 関数
jobs:
cache-dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: "依存関係のキャッシュ"
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
6.2.5 toJSON / fromJSON 関数
jobs:
json-demo:
runs-on: ubuntu-latest
steps:
- name: "JSONへの変換"
run: echo '${{ toJSON(github) }}' > github-context.json
- name: "JSONからの変換"
env:
MATRIX_JSON: '{"include":[{"os":"ubuntu-latest","node":20},{"os":"windows-latest","node":18}]}'
run: echo '${{ fromJSON(env.MATRIX_JSON) }}'
6.3 ステータスチェック関数
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "テスト実行"
id: test
run: npm test
continue-on-error: true
- name: "成功時の処理"
if: success()
run: echo "全てのステップが成功しました"
- name: "失敗時の処理"
if: failure()
run: echo "いずれかのステップが失敗しました"
- name: "必ず実行される処理"
if: always()
run: echo "結果に関わらず実行されます"
- name: "キャンセル時の処理"
if: cancelled()
run: echo "ワークフローがキャンセルされました"
複合条件の例:
steps:
- name: "テスト失敗かつmainブランチ"
if: failure() && github.ref == 'refs/heads/main'
run: echo "mainブランチでテストが失敗しました"
- name: "成功またはスキップ"
if: success() || skipped()
run: echo "成功またはスキップされました"
6.4 三項演算子の代替パターン
GitHub Actionsには三項演算子がありませんが、&& と || を組み合わせて実現できます。
env:
ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: "環境の表示"
run: echo "デプロイ先: ${{ env.ENVIRONMENT }}"
7. ワークフローコマンド
ワークフローコマンドは、ランナーとの通信を行うための特殊な構文です。
7.1 メッセージの出力
7.1.1 デバッグメッセージ
jobs:
debug-example:
runs-on: ubuntu-latest
steps:
- name: "デバッグメッセージの出力"
run: |
echo "::debug::これはデバッグメッセージです"
echo "::debug::変数の値: ${{ github.sha }}"
デバッグメッセージを表示するには、リポジトリシークレット ACTIONS_STEP_DEBUG を true に設定します。
7.1.2 通知メッセージ
steps:
- name: "通知の作成"
run: |
echo "::notice::ビルドが正常に完了しました"
echo "::notice file=app.js,line=10::この行に注意してください"
7.1.3 警告メッセージ
steps:
- name: "警告の作成"
run: |
echo "::warning::非推奨の機能が使用されています"
echo "::warning file=config.yml,line=5,col=10,title=非推奨::古い設定形式です"
7.1.4 エラーメッセージ
steps:
- name: "エラーの作成"
run: |
echo "::error::ビルドに失敗しました"
echo "::error file=app.js,line=42,col=15,title=構文エラー::予期しないトークンです"
exit 1
7.2 ログのグループ化
steps:
- name: "グループ化されたログ"
run: |
echo "::group::依存関係のインストール"
npm install
echo "::endgroup::"
echo "::group::テストの実行"
npm test
echo "::endgroup::"
echo "::group::ビルドの実行"
npm run build
echo "::endgroup::"
7.3 値のマスキング
jobs:
mask-demo:
runs-on: ubuntu-latest
steps:
- name: "シークレットのマスク"
run: |
TOKEN="ghp_secret_token_12345"
echo "::add-mask::$TOKEN"
echo "トークン: $TOKEN"
- name: "環境変数のマスク"
env:
PASSWORD: "my_secret_password"
run: |
echo "::add-mask::$PASSWORD"
echo "パスワードは表示されません: $PASSWORD"
7.4 環境変数の設定
jobs:
env-file:
runs-on: ubuntu-latest
steps:
- name: "環境変数の設定"
run: |
echo "BUILD_TIME=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV
- name: "環境変数の使用"
run: |
echo "ビルド時刻: $BUILD_TIME"
echo "ビルド番号: $BUILD_NUMBER"
複数行の値:
steps:
- name: "複数行の環境変数"
run: |
{
echo 'JSON_RESPONSE<<EOF'
curl https://api.example.com/data
echo EOF
} >> $GITHUB_ENV
- name: "値の使用"
run: echo "$JSON_RESPONSE"
7.5 出力パラメータの設定
jobs:
generate:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.number }}
artifact: ${{ steps.build.outputs.name }}
steps:
- name: "バージョン番号の生成"
id: version
run: echo "number=1.0.${{ github.run_number }}" >> $GITHUB_OUTPUT
- name: "アーティファクト名の生成"
id: build
run: echo "name=app-${{ github.sha }}.tar.gz" >> $GITHUB_OUTPUT
deploy:
needs: generate
runs-on: ubuntu-latest
steps:
- name: "出力の使用"
run: |
echo "バージョン: ${{ needs.generate.outputs.version }}"
echo "アーティファクト: ${{ needs.generate.outputs.artifact }}"
7.6 ジョブサマリーの追加
jobs:
summary-demo:
runs-on: ubuntu-latest
steps:
- name: "サマリーの作成"
run: |
echo "## テスト結果 :rocket:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **成功**: 42件" >> $GITHUB_STEP_SUMMARY
echo "- **失敗**: 3件" >> $GITHUB_STEP_SUMMARY
echo "- **スキップ**: 5件" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 失敗したテスト" >> $GITHUB_STEP_SUMMARY
echo "1. test_user_authentication" >> $GITHUB_STEP_SUMMARY
echo "2. test_api_response" >> $GITHUB_STEP_SUMMARY
echo "3. test_database_connection" >> $GITHUB_STEP_SUMMARY
7.7 システムPATHの追加
steps:
- name: "カスタムパスの追加"
run: |
echo "$HOME/.local/bin" >> $GITHUB_PATH
echo "/opt/custom-tools/bin" >> $GITHUB_PATH
- name: "追加したパスの確認"
run: echo $PATH
8. 依存関係のキャッシング
8.1 キャッシュの基本
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: "Node.js キャッシュ"
id: cache
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: "キャッシュヒット時のメッセージ"
if: steps.cache.outputs.cache-hit == 'true'
run: echo "キャッシュが見つかりました"
- name: "依存関係のインストール"
if: steps.cache.outputs.cache-hit != 'true'
run: npm ci
8.2 キャッシュの仕組み
8.3 複数パスのキャッシュ
- name: "複数ディレクトリのキャッシュ"
uses: actions/cache@v4
with:
path: |
~/.npm
~/.cache
node_modules
.next/cache
key: ${{ runner.os }}-multi-${{ hashFiles('**/package-lock.json') }}
8.4 言語別のキャッシュ例
8.4.1 Node.js
- name: "Node.js セットアップとキャッシュ"
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
8.4.2 Python
- name: "Python セットアップとキャッシュ"
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- run: pip install -r requirements.txt
8.4.3 Java (Gradle)
- name: "Java セットアップとキャッシュ"
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- run: ./gradlew build
8.4.4 Ruby
- name: "Ruby セットアップとキャッシュ"
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- run: bundle exec rake test
8.5 キャッシュの制限事項
- 保存期間: 7日間アクセスがないキャッシュは自動削除
- サイズ制限: リポジトリあたり10GB(デフォルト)
- 最大キャッシュ数: 制限なし(サイズ制限内)
- キャッシュキー: 512文字まで
8.6 キャッシュの削除順序
9. 再利用可能なワークフロー
9.1 基本的な再利用可能ワークフロー
呼び出されるワークフロー (.github/workflows/reusable-test.yml):
name: "再利用可能なテストワークフロー"
on:
workflow_call:
inputs:
node-version:
description: 'Node.js のバージョン'
required: true
type: string
test-command:
description: 'テストコマンド'
required: false
type: string
default: 'npm test'
outputs:
test-result:
description: 'テスト結果'
value: ${{ jobs.test.outputs.result }}
secrets:
npm-token:
description: 'NPM トークン'
required: false
jobs:
test:
runs-on: ubuntu-latest
outputs:
result: ${{ steps.test.outputs.status }}
steps:
- uses: actions/checkout@v5
- name: "Node.js セットアップ"
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: "依存関係のインストール"
env:
NPM_TOKEN: ${{ secrets.npm-token }}
run: npm ci
- name: "テスト実行"
id: test
run: |
${{ inputs.test-command }}
echo "status=success" >> $GITHUB_OUTPUT
呼び出し側のワークフロー (.github/workflows/main.yml):
name: "メインワークフロー"
on:
push:
branches: [main]
jobs:
test-node-18:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '18'
test-command: 'npm test'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
test-node-20:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
test-command: 'npm run test:coverage'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
report:
needs: [test-node-18, test-node-20]
runs-on: ubuntu-latest
steps:
- name: "テスト結果の表示"
run: |
echo "Node 18: ${{ needs.test-node-18.outputs.test-result }}"
echo "Node 20: ${{ needs.test-node-20.outputs.test-result }}"
9.2 シークレットの継承
jobs:
call-workflow:
uses: ./.github/workflows/deploy.yml
secrets: inherit
9.3 マトリックス戦略との組み合わせ
jobs:
test:
strategy:
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
uses: ./.github/workflows/test.yml
with:
node-version: ${{ matrix.node }}
os: ${{ matrix.os }}
9.4 ネストされた再利用可能ワークフロー
最大10レベルまでネスト可能です。
9.5 YAML アンカーとエイリアス
YAMLのアンカー機能を使って、設定の重複を避けることができます。
jobs:
test: &base_job
runs-on: ubuntu-latest
timeout-minutes: 30
env:
NODE_VERSION: '20'
steps:
- uses: actions/checkout@v5
- name: "Node.js セットアップ"
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm test
# 同じ設定を再利用
integration-test: *base_job
環境変数での使用:
env: &shared_env
NODE_ENV: production
API_URL: https://api.example.com
jobs:
build:
runs-on: ubuntu-latest
env: *shared_env
steps:
- run: npm run build
deploy:
runs-on: ubuntu-latest
env: *shared_env
steps:
- run: npm run deploy
10. 環境とデプロイメント保護
10.1 環境の定義
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- name: "ステージング環境へのデプロイ"
run: |
echo "デプロイ先: ${{ vars.DEPLOY_URL }}"
echo "APIキー: ${{ secrets.API_KEY }}"
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://www.example.com
steps:
- name: "本番環境へのデプロイ"
run: echo "本番デプロイを実行"
10.2 デプロイメント保護ルール
10.2.1 必須レビュアー
リポジトリ設定で、環境ごとに最大6名のレビュアーを設定できます。
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # レビュアー承認が必要
steps:
- name: "デプロイ実行"
run: echo "承認後にデプロイされます"
10.2.2 待機タイマー
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 待機時間が設定されている
steps:
- name: "デプロイ実行"
run: echo "待機時間経過後にデプロイされます"
待機時間は1分~43,200分(30日)の範囲で設定可能です。
10.2.3 デプロイメントブランチとタグ
環境設定で、特定のブランチやタグからのみデプロイを許可できます。
# production 環境は main ブランチからのみデプロイ可能
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: "デプロイ"
run: echo "main ブランチからのデプロイ"
10.3 環境変数とシークレット
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: "環境固有の設定を使用"
env:
# 環境変数
REGION: ${{ vars.AWS_REGION }}
CLUSTER: ${{ vars.ECS_CLUSTER }}
# 環境シークレット
ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY_ID }}
SECRET_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
echo "リージョン: $REGION"
echo "クラスター: $CLUSTER"
aws ecs update-service ...
10.4 デプロイメントのフロー
11. カスタムアクションの作成
11.1 アクションの種類
GitHub Actionsでは3種類のカスタムアクションを作成できます。
- JavaScriptアクション: Node.js で実装
- Dockerコンテナアクション: Dockerコンテナで実行
- コンポジットアクション: 複数のステップを組み合わせ
11.2 JavaScriptアクション
action.yml:
name: '挨拶アクション'
description: '名前を受け取って挨拶を返します'
author: '山田太郎'
inputs:
who-to-greet:
description: '挨拶する相手の名前'
required: true
default: '世界'
greeting-style:
description: '挨拶のスタイル'
required: false
default: 'formal'
outputs:
greeting-message:
description: '生成された挨拶メッセージ'
timestamp:
description: '実行時のタイムスタンプ'
runs:
using: 'node20'
main: 'index.js'
pre: 'setup.js'
post: 'cleanup.js'
branding:
icon: 'message-circle'
color: 'blue'
index.js:
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const whoToGreet = core.getInput('who-to-greet');
const greetingStyle = core.getInput('greeting-style');
const timestamp = new Date().toISOString();
let greeting;
if (greetingStyle === 'formal') {
greeting = `こんにちは、${whoToGreet}様`;
} else {
greeting = `やあ、${whoToGreet}!`;
}
console.log(`挨拶を生成しました: ${greeting}`);
core.setOutput('greeting-message', greeting);
core.setOutput('timestamp', timestamp);
// デバッグ情報
core.debug(`実行時刻: ${timestamp}`);
core.info(`リポジトリ: ${github.context.repo.owner}/${github.context.repo.repo}`);
} catch (error) {
core.setFailed(error.message);
}
}
run();
使用例:
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: "挨拶の実行"
id: greet
uses: ./
with:
who-to-greet: '田中花子'
greeting-style: 'casual'
- name: "出力の表示"
run: |
echo "メッセージ: ${{ steps.greet.outputs.greeting-message }}"
echo "時刻: ${{ steps.greet.outputs.timestamp }}"
11.3 Dockerコンテナアクション
action.yml:
name: 'Dockerコンテナアクション'
description: 'Dockerコンテナで実行されるアクション'
author: '山田太郎'
inputs:
command:
description: '実行するコマンド'
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.command }}
env:
CUSTOM_VAR: 'value'
Dockerfile:
FROM alpine:3.18
RUN apk add --no-cache bash curl jq
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh:
#!/bin/bash
set -e
COMMAND=$1
echo "実行コマンド: $COMMAND"
echo "環境変数: $CUSTOM_VAR"
eval "$COMMAND"
echo "コマンド実行完了"
11.4 コンポジットアクション
action.yml:
name: 'Node.js セットアップとテスト'
description: 'Node.js のセットアップ、依存関係のインストール、テスト実行を行います'
author: '山田太郎'
inputs:
node-version:
description: 'Node.js のバージョン'
required: false
default: '20'
working-directory:
description: '作業ディレクトリ'
required: false
default: '.'
cache:
description: 'キャッシュを有効にするか'
required: false
default: 'true'
outputs:
test-result:
description: 'テスト結果'
value: ${{ steps.test.outputs.result }}
runs:
using: 'composite'
steps:
- name: "Node.js セットアップ"
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: ${{ inputs.cache == 'true' && 'npm' || '' }}
- name: "依存関係のインストール"
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
echo "::group::npm install"
npm ci
echo "::endgroup::"
- name: "Lint実行"
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
echo "::group::ESLint"
npm run lint
echo "::endgroup::"
continue-on-error: true
- name: "テスト実行"
id: test
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
echo "::group::Tests"
npm test
echo "result=success" >> $GITHUB_OUTPUT
echo "::endgroup::"
- name: "カバレッジレポート"
if: always()
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
if [ -d "coverage" ]; then
echo "## テストカバレッジ" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "カバレッジレポートが生成されました" >> $GITHUB_STEP_SUMMARY
fi
使用例:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: "テスト実行"
uses: ./
with:
node-version: '20'
working-directory: './backend'
cache: 'true'
11.5 アクションのメタデータ詳細
11.5.1 inputs の詳細設定
inputs:
deployment-environment:
description: 'デプロイ先の環境'
required: true
type: choice
options:
- development
- staging
- production
version:
description: 'バージョン番号'
required: false
default: 'latest'
dry-run:
description: 'ドライランモード'
required: false
default: 'false'
api-key:
description: 'APIキー'
required: true
deprecationMessage: 'このパラメータは非推奨です。代わりに secrets を使用してください'
11.5.2 ブランディング設定
branding:
icon: 'check-circle'
color: 'green'
利用可能なアイコン: Feather icons v4.28.0
利用可能なカラー: white, black, yellow, blue, green, orange, red, purple, gray-dark
12. 実践的なパターン
12.1 マトリックス戦略
12.1.1 基本的なマトリックス
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
# 3 OS × 3 Node = 9 ジョブ
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test
12.1.2 マトリックスの拡張(include)
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
include:
# 特定の組み合わせに設定を追加
- os: ubuntu-latest
node: 22
experimental: true
# 新しい組み合わせを追加
- os: macos-latest
node: 20
experimental: false
12.1.3 マトリックスの除外(exclude)
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
exclude:
# Windows + Node 18 を除外
- os: windows-latest
node: 18
# macOS + Node 22 を除外
- os: macos-latest
node: 22
12.1.4 マトリックスの動的生成
jobs:
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
MATRIX='{"include":[
{"os":"ubuntu-latest","node":18},
{"os":"ubuntu-latest","node":20},
{"os":"windows-latest","node":20}
]}'
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
test:
needs: setup
runs-on: ${{ matrix.os }}
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
steps:
- run: echo "OS: ${{ matrix.os }}, Node: ${{ matrix.node }}"
12.2 並行実行制御(concurrency)
12.2.1 ブランチ単位での制御
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: "デプロイ実行"
run: echo "同じブランチの実行は1つのみ"
12.2.2 環境単位での制御
jobs:
deploy-production:
runs-on: ubuntu-latest
concurrency:
group: production-deployment
cancel-in-progress: false
steps:
- name: "本番デプロイ"
run: echo "本番環境への同時デプロイを防止"
12.2.3 条件付きキャンセル
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !contains(github.ref, 'release/') }}
12.3 条件付き実行の高度な使用
12.3.1 プルリクエストのマージ判定
jobs:
on-merge:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: "マージ後の処理"
run: echo "プルリクエストがマージされました"
12.3.2 ラベルによる実行制御
jobs:
deploy-if-labeled:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.labels.*.name, 'deploy')
steps:
- name: "デプロイ実行"
run: echo "deployラベルが付いています"
12.3.3 複数条件の組み合わせ
jobs:
complex-condition:
runs-on: ubuntu-latest
if: |
github.event_name == 'push' &&
github.ref == 'refs/heads/main' &&
!contains(github.event.head_commit.message, '[skip ci]')
steps:
- name: "条件を満たした場合の処理"
run: echo "全ての条件を満たしています"
12.4 ジョブ間のデータ受け渡し
12.4.1 outputs を使った受け渡し
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.number }}
sha-short: ${{ steps.sha.outputs.short }}
should-deploy: ${{ steps.check.outputs.deploy }}
steps:
- uses: actions/checkout@v5
- id: version
run: echo "number=$(cat package.json | jq -r .version)" >> $GITHUB_OUTPUT
- id: sha
run: echo "short=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
- id: check
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "deploy=true" >> $GITHUB_OUTPUT
else
echo "deploy=false" >> $GITHUB_OUTPUT
fi
build:
needs: prepare
runs-on: ubuntu-latest
steps:
- name: "ビルド情報の表示"
run: |
echo "バージョン: ${{ needs.prepare.outputs.version }}"
echo "コミットSHA: ${{ needs.prepare.outputs.sha-short }}"
deploy:
needs: [prepare, build]
if: needs.prepare.outputs.should-deploy == 'true'
runs-on: ubuntu-latest
steps:
- name: "デプロイ実行"
run: echo "バージョン ${{ needs.prepare.outputs.version }} をデプロイ"
12.4.2 artifacts を使った受け渡し
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: "ビルド実行"
run: |
npm run build
tar -czf build.tar.gz dist/
- name: "ビルド成果物のアップロード"
uses: actions/upload-artifact@v4
with:
name: build-artifact
path: build.tar.gz
retention-days: 5
test:
needs: build
runs-on: ubuntu-latest
steps:
- name: "ビルド成果物のダウンロード"
uses: actions/download-artifact@v4
with:
name: build-artifact
- name: "テスト実行"
run: |
tar -xzf build.tar.gz
npm test
deploy:
needs: [build, test]
runs-on: ubuntu-latest
steps:
- name: "ビルド成果物のダウンロード"
uses: actions/download-artifact@v4
with:
name: build-artifact
- name: "デプロイ実行"
run: |
tar -xzf build.tar.gz
aws s3 sync dist/ s3://my-bucket/
12.5 エラーハンドリング
12.5.1 continue-on-error の使用
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "重要なテスト"
run: npm test
- name: "オプショナルなLint"
run: npm run lint
continue-on-error: true
- name: "カバレッジチェック"
run: npm run coverage
continue-on-error: true
- name: "必ず実行される処理"
if: always()
run: echo "結果に関わらず実行"
12.5.2 マトリックスでのエラーハンドリング
strategy:
matrix:
node: [18, 20, 22]
include:
- node: 22
experimental: true
fail-fast: false
steps:
- name: "テスト実行"
run: npm test
continue-on-error: ${{ matrix.experimental == true }}
12.6 セキュリティのベストプラクティス
12.6.1 最小権限の原則
permissions:
contents: read
pull-requests: write
issues: write
jobs:
comment:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: "プルリクエストへのコメント"
uses: actions/github-script@v8
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'テストが完了しました'
})
12.6.2 シークレットの安全な使用
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: "シークレットの使用"
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
# シークレットは自動的にマスクされる
curl -H "Authorization: Bearer $API_KEY" https://api.example.com
- name: "シークレットを含むファイルの作成"
run: |
echo "${{ secrets.SSH_PRIVATE_KEY }}" > private_key
chmod 600 private_key
# 使用後は削除
rm private_key
shell: bash
12.6.3 pull_request_target の安全な使用
# 危険: フォークからの任意のコードを実行
on: pull_request_target
jobs:
dangerous:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5 # フォークのコードをチェックアウト
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: npm install # 任意のコードが実行される可能性
- run: npm test
# 安全: 信頼できるコードのみ実行
on: pull_request_target
jobs:
safe:
runs-on: ubuntu-latest
steps:
# デフォルトブランチのコードを使用
- uses: actions/checkout@v5
# フォークからの入力は検証する
- name: "プルリクエスト情報の取得"
uses: actions/github-script@v8
with:
script: |
const pr = context.payload.pull_request;
console.log(`PR #${pr.number}: ${pr.title}`);
12.7 パフォーマンス最適化
12.7.1 並列実行の活用
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: npm test
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: npm run build
# 全てのジョブが成功した場合のみ実行
deploy:
needs: [lint, test, build]
runs-on: ubuntu-latest
steps:
- run: echo "全てのチェックが完了しました"
12.7.2 キャッシュの効果的な使用
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# 複数のキャッシュを組み合わせ
- name: "Node.js キャッシュ"
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- name: "Next.js キャッシュ"
uses: actions/cache@v4
with:
path: |
.next/cache
node_modules/.cache
key: ${{ runner.os }}-next-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-next-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-next-
- run: npm ci
- run: npm run build
13. トラブルシューティング
13.1 よくある問題と解決方法
13.1.1 ワークフローがトリガーされない
原因と対策:
-
YAMLの構文エラー
# 間違い on: push branches: [main] # 正しい on: push: branches: [main] -
ファイル配置の誤り
-
.github/workflows/ディレクトリに配置されているか確認 - ファイル拡張子が
.ymlまたは.yamlであることを確認
-
-
イベントフィルタが一致しない
# mainブランチのみトリガー on: push: branches: - main
13.1.2 キャッシュが効かない
# キャッシュキーにハッシュ値を含める
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
13.1.3 ジョブがタイムアウトする
jobs:
long-running:
runs-on: ubuntu-latest
timeout-minutes: 60 # デフォルトは360分
steps:
- name: "長時間かかる処理"
run: ./long-script.sh
13.1.4 環境変数が参照できない
# 環境変数の設定
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: "環境変数の設定"
run: echo "MY_VAR=value" >> $GITHUB_ENV
- name: "環境変数の使用"
run: echo $MY_VAR # 次のステップで利用可能
13.2 デバッグ方法
13.2.1 デバッグログの有効化
リポジトリシークレット ACTIONS_STEP_DEBUG を true に設定すると、詳細なログが出力されます。
steps:
- name: "デバッグ情報の出力"
run: |
echo "::debug::デバッグメッセージ"
echo "現在のディレクトリ: $(pwd)"
echo "ファイル一覧:"
ls -la
13.2.2 ランナーへのSSH接続
開発時のデバッグには、tmate を使ったSSH接続が便利です。
steps:
- name: "SSH セッションの開始"
uses: mxschmitt/action-tmate@v3
if: failure() # 失敗時のみ
14. まとめ
GitHub Actionsは、CI/CDパイプラインの構築に必要な全ての機能を提供する強力なプラットフォームです。本記事では、公式ドキュメントに基づいて以下の内容を解説しました。
14.1 主要な機能
- ワークフロー構文: YAML形式での柔軟な定義
- 豊富なイベント: 30種類以上のトリガーイベント
- 変数とコンテキスト: 動的な値の参照と受け渡し
- 式評価: 条件分岐とデータ変換
- キャッシング: 依存関係の高速化
- 再利用可能ワークフロー: コードの重複削減
- 環境管理: デプロイメント保護とシークレット管理
- カスタムアクション: 独自の自動化処理
14.2 実装のポイント
- 段階的な導入: シンプルなワークフローから開始し、必要に応じて機能を追加
- キャッシュの活用: ビルド時間の短縮
- 並列実行: テストやビルドの高速化
- セキュリティ: 最小権限の原則とシークレット管理
- 再利用性: 共通処理の抽出とテンプレート化
14.3 制限事項の理解
- ワークフローファイルサイズ: 推奨される適切なサイズ
- 同時実行制限: プランに応じた並列実行数
- 保存期間: ログとアーティファクトの保存期間
- キャッシュサイズ: リポジトリあたりのキャッシュ容量
GitHub Actionsを活用することで、コードの品質向上、デプロイの自動化、開発効率の改善を実現できます。本記事の内容を参考に、プロジェクトに最適なCI/CDパイプラインを構築してください。