カスタム GitHub アクションを作成する

完了

GitHub Actions は、独自の使い慣れた便利なリポジトリにあるすべての要素をコードからクラウドに移行する際に役立つ強力な機能です。 ここでは、さまざまな種類の GitHub アクションと、カスタム GitHub アクションを作成するためのメタデータ、構文、ワークフロー コマンドについて説明します。

GitHub アクションの種類

3 つの種類 (Docker、JavaScript、複合実行ステップ アクション) の GitHub Actions の図: 。

アクションは、開発ワークフローのカスタマイズに使用できる個々のタスクです。 独自のアクションは、リポジトリと対話するカスタム コードを記述してカスタム タスクを実行するか、GitHub コミュニティで共有されているアクションを使用することで作成できます。 さまざまなアクション間を移動すると、 Docker コンテナー アクション、 JavaScript アクション、 複合実行ステップ アクションの 3 種類のアクションがあることがわかります。 それぞれのアクションの種類について詳しく見ていきましょう。

Docker コンテナーのアクション

Docker コンテナーでは、GitHub Actions のコードにより環境がパッケージ化されます。 つまり、すべての依存関係がそのコンテナー内にあるため、このアクションは一貫性のある信頼性の高い環境で実行されます。 アクションを特定の環境構成で実行する必要がある場合は、オペレーティング システムとツールをカスタマイズできるため、Docker コンテナーを使用することをお勧めします。 ジョブでコンテナーを構築し、取得する必要があるため、Docker コンテナーのアクションは JavaScript のアクションよりも遅くなることが多いという欠点があります。

Docker コンテナーのアクションを構築するには、環境変数と Docker コンテナーのファイルシステムの使用方法に関する基本的な知識が必要です。 次に示すような、いつくかの簡単な手順を実行することで、Docker コンテナーのアクションを構築することができます。

  1. Dockerfile を作成し、Docker イメージをアセンブルするコマンドを定義します。
  2. action.yml メタデータ ファイルを作成し、アクションの入力と出力を定義します。 ファイルで、runs: using: の値を docker に、runs: image: の値を Dockerfile に設定します。
  3. entrypoint.sh ファイルを作成し、Docker イメージについて説明します。
  4. アクションをコミットし、action.ymlentrypoint.shDockerfileREADME.md などのファイルを使用して GitHub にプッシュします。

JavaScript のアクション

JavaScript のアクションは、ランナーのマシンで直接実行できます。また、アクションの実行に使用する環境からアクション コードを分離することができます。 このため、アクション コードは単純化され、Docker コンテナー内のアクションよりも迅速に実行できます。

パッケージ化された JavaScript のアクションを作成して使用するための前提条件として、npm を含む Node.js をダウンロードする必要があります。 オプションの手順ですが、GitHub Actions Toolkit Node.js を使用することをお勧めします。これは Node.js パッケージのコレクションであり、より一貫性のある JavaScript のアクションをすばやく構築することができます。

JavaScript アクションを構築する手順は最小限の簡単なものです。

  1. action.yml メタデータ ファイルを作成してアクションの入力と出力を定義し、この JavaScript アクションの実行を開始する方法をアクション ランナーに知らせます。
  2. index.js ファイルを作成し、Toolkit パッケージ、ルーティング、およびアクションの他の機能に関するコンテキスト情報を含めます。
  3. アクションをコミットし、action.ymlindex.jsnode_modulespackage.jsonpackage-lock.jsonREADME.md などのファイルを使用して GitHub にプッシュします。

複合実行ステップのアクション

複合実行ステップのアクションでは、シェル スクリプトを使用してアクションを再利用できます。 同じアクション内で、複数のシェル言語を混在させることもできます。 複数のタスクを自動化するためのシェル スクリプトが多数ある場合は、それらを簡単にアクションに変換し、異なるワークフローで再利用できます。 JavaScript を使用したり、Docker コンテナーでコードをラップしたりするよりも、シェル スクリプトを記述する方が簡単な場合があります。

パッケージ化された複合アクション

パッケージ化された複合アクションでは、複数の手順を再利用可能なユニットにバンドルします。 これらのアクションはリポジトリで定義され、ワークフローの中で異なるリポジトリをまたいで参照できます。 複合アクションをパッケージ化すると、ワークフローが簡略化され、重複を削減でき、保守性が向上します。

パッケージ化された複合アクションを作成する場合、各手順は単一の action.yml ファイル内で定義されます。 このファイルでは、入力や出力と、実行するコマンドまたはアクションのシーケンスを指定します。 パッケージ化された複合アクションは、繰り返しのタスクを自動化したり、複数のシェル コマンドを 1 つの再利用可能なアクションに組み合わせたりする場合に特に便利です。

複合アクションを作成する

1. 複合アクションのディレクトリを設定する

複合アクションは、リポジトリ内の独自のディレクトリに配置する必要があります。

ディレクトリ構造の例:

.github/actions/my-composite-action/
├── action.yml
└── scripts/
    └── my-script.sh

2. action.yml ファイルを定義する

my-composite-action ディレクトリ内に、action.yml ファイルを作成します。

name: "My Composite Action"
description: "A reusable composite action that checks out code and sets up Node.js"

inputs:
  node-version:
    description: "The Node.js version to use"
    required: true

runs:
  using: "composite"
  steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}

注:"composite" フィールドを使用すると、このアクションが複合アクションであることが示されます。

3. ワークフローで複合アクションを使用する

複合アクションが作成されると、それを GitHub Actions ワークフローで参照できます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Use my composite action
        uses: ./.github/actions/my-composite-action
        with:
          node-version: '18'

複合アクションが 他のリポジトリから共有されている場合、参照は次のようになります。

uses: owner/repository/.github/actions/my-composite-action@v1

ワークフローで使用されている複合アクションのスクリーンショット。

複合アクションに出力を追加する

複合アクションでは、ワークフローがステップ間またはジョブ間でデータを渡すために使用できる出力を定義できます。 出力は、結果や計算された値をアクション間で共有する場合に特に便利です。

次の例では、複合アクションの中で出力を定義し使用する方法を示しています。

action.yml 内で出力を定義する

action.yml ファイルが、script-result という名前の出力を指定します。 この出力は、手順 resultrun-script 出力から値を取得します。 手順 run-script では、Bash コマンドを実行して出力値を設定します。

outputs:
  script-result:
    description: "Result from the script"
    value: ${{ steps.run-script.outputs.result }}

runs:
  using: "composite"
  steps:
    - id: run-script
      run: echo "result=Success" >> $GITHUB_OUTPUT
      shell: bash

複合アクションで出力を定義しているスクリーンショット。

ワークフローで出力を使用する

複合アクションが作成されると、その出力にワークフローでアクセスできるようになります。 次に例を示します。

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run composite action
        id: my-action
        uses: ./.github/actions/my-composite-action

      - name: Display result
        run: echo "Script Result: ${{ steps.my-action.outputs.script-result }}"

この例では:

  • 複合アクションは、キーワード uses を使用して呼び出されます。
  • script-result 構文を使用して出力 steps.<step-id>.outputs.<output-name> にアクセスします。
  • ワークフロー ログに結果を表示します。

複合アクション内で出力を定義して、再利用可能でありモジュール型のワークフローを作成します。 このアプローチは、データの共有を簡素化し、保守性を向上します。

複合アクションのベスト プラクティス

ベスト プラクティス 説明
バージョン管理の使用 安定バージョン 1 を参照するには、v1 タグを使用します。
アクションをモジュール型に保つ 複合アクション内の関連するステップをグループ化します。
ドキュメントの入力と出力 action.yml 内に入力と出力の説明を追加します。
公開前にテストする テスト リポジトリ内で、複合アクションを検証します。

ワークフロー内の複合アクション

複合アクションは、複数の手順を再利用可能なユニットにバンドルすることで、ワークフローを簡素化できる強力な手法です。 これらのアクションでは、単一の action.yml ファイル内に一連のコマンドまたは操作を定義できるため、ワークフロー間でのロジックの保守と再利用が容易になります。

複合アクションの利点:

  • 再利用性 - アクションを 1 回定義すれば、複数のワークフローで使用できます。
  • 保全性 - 単一のアクションにロジックを一元化することで、重複を減らします。
  • モジュール性 - 複数のシェル コマンドまたはその他の操作を 1 つのユニットにまとめます。

GitHub Actions ランナー上で、CLI を設定するアクションを開発する

多くの CI/CD ワークフローには、クラウド サービスの操作、インフラストラクチャの管理、スクリプトの実行のために、特定のバージョンの CLI ツール が必要です。 GitHub でホストされるランナーには多くのツールが事前インストールされていますが、特にワークフローで必要なものが古いまたはサポート外のバージョンの場合は、正確にそのバージョンが含まれていないことがあります。 必要な CLI バージョンをすべてのワークフローにインストールする代わりに、再利用可能な GitHub アクションを作成すると以下を実現できます。

  • ジョブ間で、必要な CLI バージョンが一貫性してインストールされることを保証します。
  • インストール ロジックを一元化してワークフローを簡素化します。
  • キャッシュを最適化して、ワークフローの実行を高速化します。

CLI セットアップ アクションを開発する方法

CLI セットアップ アクションは、GitHub ランナー上で CLI をインストールして構成する、JavaScript ベースのアクションです。

アクションを作成する手順:

手順 1: アクション ディレクトリを設定する

CLI セットアップ アクションのディレクトリを手動で作成するには、次の手順に従います。

  1. リポジトリに移動する

JavaScript アクションを表示しているルート リポジトリ構造のスクリーンショット。

  1. アクションの新しいディレクトリを作成する
    my-cli-action フォルダー内に .github/actions という名前の新しいディレクトリを作成します。 これにより、アクションは整理され、カスタム アクション構造に対する GitHub の推奨に従うようになります。

  2. 新しいディレクトリに移動する
    新しく作成したディレクトリに移動して、アクション用ファイルの追加を開始します。

  3. ディレクトリ構造を確認する
    ディレクトリを作成した後、リポジトリの構造は次のようになります。

your-repository/
├── .github/
│   ├── actions/
│   │   ├── my-cli-action/

'.github/actions' 内の JavaScript アクションのディレクトリ構造のスクリーンショット。

これで、CLI セットアップ アクションのために、action.yml ファイルと他の必要なファイルの作成に進む準備ができました。

手順 2: action.yml メタデータ ファイルを定義する

アクションを記述する action.yml ファイルを作成します。

name: "Setup MyCLI"
description: "Installs MyCLI and adds it to the PATH"
author: "Your Name"

inputs:
  version:
    description: "The CLI version to install"
    required: false
    default: "latest"

runs:
  using: "node16"
  main: "index.js"

using: node16 を使用する理由: このアクションは、Node.js 16 を使用して JavaScript コードを実行します。

JavaScript GitHub アクション用の YAML メタデータ ファイルのスクリーンショット。

手順 3: CLI をインストールする JavaScript スクリプトを作成する

同じディレクトリに、index.js という名前のファイルを作成し、次のコードを追加します。

const core = require('@actions/core');
const { execSync } = require('child_process');

async function run() {
  try {
    const version = core.getInput('version') || 'latest';
    
    console.log(`Installing MyCLI version: ${version}...`);

    execSync(`curl -fsSL https://cli.example.com/install.sh | sh`, { stdio: 'inherit' });

    console.log("MyCLI installed successfully.");
  } catch (error) {
    core.setFailed(`Installation failed: ${error.message}`);
  }
}

run();

上記の JavaScript コードでは、core.getInput() を使用して、入力として指定された CLI バージョンを取得します。 その後、curl コマンドを実行して CLI をダウンロードおよびインストールします。 インストール プロセスが失敗した場合、アクションは core.setFailed() を使用して、ワークフローを失敗としてマークします。

GitHub アクション内の index.js 用 JavaScript コードのスクリーンショット。

手順 4: アクションをローカルでテストする

ワークフローでアクションを使用する前に、それを GitHub でホストされているランナーでテストします。
リポジトリにワークフロー ファイル (.github/workflows/test.yml) を作成します。

name: Test MyCLI Setup

on:
  push:
    branches:
      - main
      - feature/*

1. ワークフローのトリガー
ワークフローは、メイン ブランチか、feature/* パターンに一致するブランチにプッシュされるときにトリガーされます。 これは、リポジトリの分岐戦略に合わせて調整できます。

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

2. リポジトリをクローンする
actions/checkout@v4 アクションは、リポジトリをランナーに複製するために使用されます。 これにより、ワークフローによるリポジトリのファイルへのアクセスを保証しています。

      - name: Install MyCLI
        uses: ./.github/actions/my-cli-action
        with:
          version: '1.2.3'

3. カスタム アクションを実行する
uses: ./.github/actions/my-cli-action 行は、カスタム アクションをローカルで参照します。 アクション ディレクトリと action.yml ファイルが正しく設定されていることを確認します。 バージョン入力では、インストールする CLI バージョン (この場合はバージョン 1.2.3) を指定します。

      - name: Verify CLI Installation
        run: |
          echo "Checking MyCLI version..."
          mycli --version

4. CLI のインストールを検証する
この手順では、シェル コマンドを実行して、CLI が正常にインストールされたことを検証します。 mycli --version を実行して、インストールされている CLI のバージョンを確認します。

JavaScript GitHub アクションのテスト結果のスクリーンショット。

ローカルでテストする

このワークフローをローカルでテストするには、act CLI ツールを使用します。

act -j test

これにより、ローカル コンピューター上で GitHub Actions 環境がシミュレートされ、変更をプッシュする前にワークフローをデバッグおよび検証できます。

最適化のヒント: キャッシュ

ワークフローのパフォーマンスを向上させるには、 actions/cache アクションを使用して CLI インストール ディレクトリをキャッシュします。

      - name: Cache MyCLI
        uses: actions/cache@v4
        with:
          path: ~/.mycli
          key: mycli-${{ runner.os }}-${{ inputs.version }}

これにより、後続の実行ではキャッシュされた CLI インストールが再利用されるので、セットアップ時間が短縮されます。

CLI セットアップ アクションのベスト プラクティス

ベスト プラクティス 説明
バージョン管理の使用 inputs.version 経由で CLI バージョンを指定することを、ユーザーに許可します。
エラーを適切に処理する エラー時に終了するには、core.setFailed() を使用します。
CLI インストールをキャッシュする actions/cache を使用してワークフローのパフォーマンスを最適化します。
ドキュメントを提供する README.md 内で使用と入力を説明します。

JavaScript アクションのトラブルシューティング

JavaScript ベースの GitHub Actions を操作する際には、ワークフローの実行中に予期しない動作、エラー、または障害が発生する場合があります。 このユニットでは、JavaScript アクションの問題を特定して解決するのに役立つ、手法とツールを提供します。

一般的なトラブルシューティングのシナリオ

問題 考えられる原因 推奨される修正
スタック トレースでアクションが失敗する index.js の構文またはランタイム エラー console.log() を使用してログする
入力が undefined 入力名が正しくないか、入力が見つからない action.yml と入力の受け渡し方法を確認します
環境変数が設定されていない core.exportVariable または process.env が正しく使用されていません 変数を設定するコードをレビューします
ファイルが見つかりません 相対パスがありません ファイルへの __dirname パスまたは完全パスを使用します
キャッシュが復元されていない key または path 値が正しくない キャッシュの構成とキーを確認します

デバッグ用のログを使用します

core.infocore.debugconsole.log を含むログ メッセージ

const core = require('@actions/core');

core.info("This is an info message");
core.debug("This is a debug message");
console.log("This is a raw console log");

✅ デバッグ ログには core.debug を使用します。これらは、ACTIONS_STEP_DEBUG が true に設定されている場合にのみ表示されます。

デバッグログを有効化する

次のシークレットを設定すると、ステップ レベルのデバッグ ログを有効にできます。

ACTIONS_STEP_DEBUG=true

ランナー診断ログを有効にするには、次のように設定します。

ACTIONS_RUNNER_DEBUG=true

デバッグ用のシークレットを設定する

  1. GitHub リポジトリに移動します。
  2. [設定]>[シークレットと変数]>[アクション] の順に移動します。
  3. 次の名前と値を持つ新しいシークレットを追加します。
    • ACTIONS_STEP_DEBUG: true
    • ACTIONS_RUNNER_DEBUG: true

ワークフロー ログを検査する

ワークフローが失敗した場合は、[アクション] タブで失敗したジョブをクリックし、各ステップを展開し次を実行します。

  • 詳細なログを表示する
  • 標準出力 (stdout) を確認する
  • スクリプトの終了コードを確認する
  • 未処理の例外を特定する

🔍 ログ出力の例

Error: Cannot find module '@actions/core'
Require stack:
- /home/runner/work/_actions/my-org/my-action/index.js

✅ npm インストール @actions/core を Fix: Run し、node_modules をコミットします (または、ncc を使用してアクションをバンドルします)。

アクションをローカルでテストする

GitHub Actions をローカルで実行するための CLI ツールである、act を使用します。 例:

act -j test

🛠 ローカルでテストするときは、GitHub 環境を適切にシミュレートする必要があります。

エラーを適切に処理する

例外をキャッチし、役立つメッセージを表示して失敗します:

try {
  // your logic
} catch (error) {
  core.setFailed(`Action failed with error: ${error.message}`);
}

🔁 これにより、GitHub はエラー時にワークフローを停止し、読み取りやすいログを提供できるようになります。

JavaScript アクションをデバッグするためのベスト プラクティス

練習 説明
core.debug() を使用する デバッグが有効になっていない限り、詳細ログを非表示にします。
action.yml を検証する 入力と出力が適切に定義されていることを確認します。
コードのバンドル @vercel/ncc を使用して JavaScript を 1 つのファイルにコンパイルします。 これにより、依存関係が減少し、必要なすべてのモジュールが確実に含まれるので、存在しないファイルが原因で発生するランタイム エラーが回避されます。
act を使用してテストする より高速な反復のために、ローカルで実行をシミュレートします。
try/catch を使用する ワークフローが警告なしで失敗するのを防ぎます。

Docker コンテナーアクションのトラブルシューティング

Docker コンテナー アクションは強力であり、GitHub Actions ワークフローで複雑なツールと環境をカプセル化できます。 ただし、これらのアクションのデバッグは、ランタイム環境が分離されているために、JavaScript アクションのものよりも困難になることがあります。 このユニットでは、Docker ベースのアクションにおける問題の特定、診断、および解決について説明します。

Docker コンテナー アクションでの一般的な問題

問題 原因 推奨される修正
アクションの開始に失敗する ENTRYPOINT または CMD が間違って構成されています Dockerfile で ENTRYPOINT が正しく使用されていることを確認します
依存関係に不足がある 依存関係がインストールされていないか、正しく構成されていません すべてのパッケージがイメージにインストールされていることを確認します
入力が受信されない INPUT_ 環境変数がアクセスされていません process.env.INPUT_<INPUT_NAME> (または同等のシェル) を使用します
ファイルが見つかりません コンテナー内のファイル パスが間違っている 絶対パスを使用するか、ディレクトリ構造を検証します
アクセス許可が拒否されました ファイルまたはスクリプトに実行アクセス許可がない Dockerfile 内に RUN chmod +x <script> を追加します
ネットワーク関連のエラー 外部サービスにアクセスできない ネットワーク設定と再試行ロジックを検証します

Docker アクションのライフサイクルを理解する

トラブルシューティングを行う前に、Docker コンテナー アクションがどのように実行されるのかを理解してのは有用です。

1. ワークフロー トリガー

GitHub Actions のワークフローは、構成されたイベント (pushpull_request、手動 workflow_dispatchなど) に応答して開始されます。

2. ランナーのセットアップ

GitHub は、ワークフローを実行するために、新しい仮想マシン (ランナー) をプロビジョニングします。 ランナーは、アクションの定義をダウンロードして依存関係を解決することで、環境を準備します。

3. アクションの解決

アクションが runs.using: docker ファイル内で action.yml を指定している場合、GitHub はそれを Docker ベースのアクションとして認識します。

4. イメージのビルドまたはプル

GitHub は、アクションの Dockerfile で定義された Docker イメージをビルドするか、指定されている場合は事前ビルド済みのイメージをプルします。 このイメージは、アクション コードが実行される環境を定義します。

5. コンテナーの実行

ランナーは Docker コンテナーを起動し、ワークスペースをマウントし、ワークフローで定義されたシークレットや入力を含む環境変数を挿入します。

6. エントリポイントの実行

GitHub は、コンテナー内の Dockerfile から entrypoint コマンドを実行します。 これは、カスタム アクション ロジック (通常はスクリプトまたはアプリケーション) が実行される場所です。

7. 結果の処理

コンテナー アクションによって設定された出力は、いずれもランナーによってキャプチャされ、ワークフロー内の後続のステップに渡されます。 完了すると、コンテナーはシャットダウンされ、ランナーは破棄されます。

注: Docker コンテナー アクションは、クリーンで分離された環境で実行されます。 ファイル システムの状態、インストールされているツール、環境変数は、すべて Dockerfile 内で定義されている必要があります。

デバッグの手法

1. ログを追加する

エントリポイント スクリプトの中で、echo、printf、またはログ ステートメントを使用します。

echo "Starting Docker action..."
echo "Input VALUE: $INPUT_VALUE"

すべてのクリティカルな入力と手順をログに記録して、障害が発生した場所を診断します。

2. ローカルでビルドしてテストする

自分のマシンで Docker を使用して、コンテナーの動作をシミュレートします。

docker build -t my-action .
docker run -e INPUT_NAME=value my-action

環境変数が GitHub セットを模倣していることを確認します。

3. act CLI を使用して GitHub ワークフローをシミュレートする

GitHub ワークフローをローカルで実行するために、act をインストールします。

act -j test-job

GitHub にプッシュせずに、ワークフローで Docker アクションをテストするのに最適です。

4. Dockerfile の構成を検証する

ENTRYPOINT または CMD を定義する必要があります。 スクリプトをイメージにコピーし、実行アクセス許可を付与します。

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

5. GitHub ログを調べる

失敗したワークフロー実行をクリックし、各ステップを展開して、次の内容を確認します。

  • Docker のビルド ログ
  • コンテナーからの標準出力と標準エラー
  • 終了コードとスタック トレースの 🔍 ログでは、パッケージの不足、構文の問題、またはアクセス許可エラーが確認されることがよくあります。

例: エントリ ポイント エラー

Error: container_linux.go:380: starting container process caused "exec: \"/entrypoint.sh\": permission denied"

✅ Dockerfile で、Fix: Add RUN chmod +x /entrypoint.sh を実行します。

環境変数マッピング

GitHub 入力 Docker 環境変数
with: name: test INPUT_NAME=test
GITHUB_WORKSPACE /github/workspace にマップ済み
GITHUB_EVENT_NAME ワークフローをトリガーしたイベント
echo "Input was $INPUT_NAME"
echo "Working dir: $GITHUB_WORKSPACE"

トラブルシューティング シークレットを使用する

リポジトリまたは組織に次のシークレットを追加して、追加のログを有効にします。

秘密 説明
ACTIONS_STEP_DEBUG デバッグ ログを有効にします
ACTIONS_RUNNER_DEBUG ランナーの診断を有効にします

Docker アクションのデバッグに関するベスト プラクティス

ベスト プラクティス 理由
豊富にログを使用する 障害ポイントのトレースに役立ちます
常に chmod +x を設定する シェル スクリプトでのアクセス許可エラーを回避します
スクリプト内で入力を検証する 不足している入力または形式が正しくない入力を早期にキャッチできます
コンテナーの依存関係を最小化する 小さいイメージはデバッグが簡単になります
docker run または act を使用してローカルでテストする 繰り返しを迅速にし、即時のフィードバックが得られ得ます