mcpField
M
make-github-actions-workflow

make-github-actions-workflow

github.com/dotnetクラウド・DevOps14.8k46 回インストール今日更新
リポジトリ

make-github-actions-workflow について

リポジトリの規約に沿った GitHub Actions ワークフローを作成するスキルです。CI やリポジトリ自動化に向け、イベント、権限、安全なスクリプト、条件、エラー処理、検証を案内します。

主な機能

  1. 01ワークフローのトリガーイベント選択
  2. 02明示的で最小限の権限設定
  3. 03実行条件と冪等性チェックの追加
  4. 04複雑な処理に `actions/github-script@v8` を使用
  5. 05API エラーとページネーションの処理
  6. 06ワークフローの安全性と動作の検証

活用シーン

  1. 01CI 検証ワークフローの作成
  2. 02プルリクエスト管理の自動化
  3. 03Issue ラベル付けや通知の追加
  4. 04ワークフローの権限と安全性の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dotnet/efcore --skill make-github-actions-workflow

インストール後、Claude Code で/make-github-actions-workflowを入力して読み込まれたか確認します。

詳細

GitHub Actions ワークフローの作成

このリポジトリの規約やパターンに従った GitHub Actions ワークフローを作成して設定します。ワークフローを使うと、CI 検証、PR 管理、Issue のラベル付け、通知などのタスクを自動化できます。

リポジトリの規約

このリポジトリでは、すべてのワークフローで特定のパターンを使用しています。新しいワークフローを作成する際は、次の規約に従ってください。

ファイルの場所と命名
  • すべてのワークフローは .github/workflows/ に配置します
  • kebab-case の名前を使用します:label-and-milestone-issues.yml、validate-pr-target-branch.yml
  • ワークフローの目的を説明するコメントブロックから始めます
ランナー
  • 汎用的なジョブには ubuntu-latest を使用します
  • 特定の OS バージョンが必要な場合(copilot のセットアップ手順など)は ubuntu-24.04 を使用します
権限
  • 必ず明示的に権限を宣言します。デフォルトの権限には依存しないでください
  • 最小限の権限を使用します。ワークフローに必要な権限のみをリクエストしてください
  • 一般的なパターン:
    • 読み取り専用:permissions: {}
    • PR コメント:pull-requests: write
    • Issue 管理:issues: write
    • コードの読み取り:contents: read
  • 外部コントリビューターからの PR に書き込みアクセスが必要なワークフローでは、pull_request の代わりに pull_request_target を使用します
    • セキュリティに関する警告: pull_request_target ワークフローは、ベースリポジトリのコンテキストとその権限で実行されます。これらのワークフローでは、PR ブランチのコードをチェックアウトしたり実行したりしないでください。代わりに、イベントペイロードや GitHub API(actions/github-script、github.rest.* など)を使って、PR を安全に調査し操作してください。
スクリプト作成
  • 複雑なロジックには、シェルスクリプトではなく actions/github-script@v8 を使用します
  • async/await を使って JavaScript を記述します。github オブジェクト(Octokit)と context を利用できます
  • REST API 呼び出しには github.rest.* を、GraphQL クエリには github.graphql() を使用します
  • context.payload.pull_request、context.repo.owner、context.repo.repo を使って PR や Issue のデータにアクセスします
  • デバッグには console.log() を使用し、エラーには core.setFailed() を使用します
エラー処理
  • API 呼び出しを try/catch ブロックで囲みます
  • 最初のエラーで失敗させるのではなく、エラーを収集して最後に報告します
  • スキップした操作は、その理由とともにログに記録します

ワークフロー

ステップ 1:要件を把握する

ワークフローを記述する前に、次の点を明確にします。

  • どのイベントをトリガーにしますか?(push、pull_request、check_suite、schedule など)
  • どの権限が必要ですか?
  • 実行を制限する条件は何ですか?(作成者、ブランチ、ラベルなど)
  • どの API 呼び出しが必要ですか?
  • レート制限や冪等性に関する考慮事項はありますか?
ステップ 2:トリガーイベントを選択する
ユースケースイベント備考
PR の作成または更新pull_requestPR への読み取り専用アクセス
書き込みアクセスが必要な PRpull_request_targetコメント、ラベル付け、クローズが可能
PR のマージpull_request_target: [closed]github.event.pull_request.merged == true を確認します
CI チェックの完了check_suite: [completed]自身の実行をスキップするには app.slug != 'github-actions' でフィルタリングします
コードのプッシュpushブランチやパスでフィルタリングします
手動トリガーworkflow_dispatchパラメーターには inputs: を追加します
スケジュール実行schedulecron 構文を使用します
ステップ 3:ワークフローを記述する

次のテンプレートに従って YAML ファイルを作成します。

# Description of what this workflow does and why.

name: Descriptive Workflow Name

on:
  <trigger_event>:
    types: [<event_types>]

permissions:
  <resource>: <read|write>

jobs:
  <job-name>:
    if: <guard_condition>  # Optional: skip when not needed
    runs-on: ubuntu-latest
    steps:
      - name: Descriptive step name
        uses: actions/github-script@v8
        with:
          script: |
            // Your logic here
ステップ 4:ガード条件を実装する

不要な実行を避けるため、条件を追加します。

  • イベントペイロードを確認するジョブレベルの if:(例:github.event.check_suite.app.slug != 'github-actions')
  • PR の作成者やドラフト状態などを確認する、スクリプト内での早期 return
  • 冪等性チェック(例:アクションの重複を防ぐタグとして、非表示の HTML コメントを使用する)

opened、edited、reopened に反応する pull_request_target ポリシーワークフローの場合:

  • edited では、context.payload.changes?.base が存在しない場合に処理を終了します。タイトルや本文の編集によって、ターゲットブランチのポリシーを再適用してはいけません。
  • PR の作成者だけでなく、context.actor の権限を確認します。メンテナーが外部からの PR を編集または再オープンすることがあり、その操作にはメンテナーの権限を適用する必要があります。
  • opened では、アクターと作成者は同じなので、権限を一度だけ照会し、その結果をポリシーとラベル付けの判断に再利用します。
  • アクターまたは作成者のいずれかがボットの場合は、対象外にします。
  • main など、許可するブランチを 1 つだけ指定するのではなく、禁止するブランチのパターン(例:release/*)を直接指定します。
  • 権限の照会に失敗した場合は、破壊的な操作をせずに処理を終了します。アクセス権が不明であることは、コントリビューターが外部のユーザーである証拠にはなりません。
ステップ 5:検証する

ワークフローを作成したら、以下を確認します。

  • 権限は最小限で、明示的に宣言されています
  • 複雑なロジックには actions/github-script@v8 を使用しています
  • ガード条件によって不要な実行を防いでいます
  • API 呼び出しでは必要に応じてページネーションに対応しています(per_page: 100 を使用)
  • エラー処理で失敗を暗黙に無視していません
  • シークレットやトークンをハードコードしていません
  • ワークフローによって無限ループが発生しません(例:自分自身をトリガーするワークフロー)

このリポジトリの既存のワークフロー

参考として、以下のワークフローを確認してください。

ワークフロートリガー目的
validate-pr-target-branch.ymlpull_request_target: [opened, edited, reopened]リリースブランチをターゲットとする外部 PR をクローズし、コミュニティラベルを追加します
label-and-milestone-issues.ymlpull_request_target: [closed]修正用 PR がマージされたときに、課題にラベルとマイルストーンを設定します
copilot-setup-steps.ymlworkflow_dispatch、push、pull_requestCopilot の開発環境をセットアップします
inter-branch-merge-flow.ymlrelease/** への pusharcade を介したブランチ間マージをトリガーします

よく使われるパターン

PR にコメントする
await github.rest.issues.createComment({
  owner: context.repo.owner,
  repo: context.repo.repo,
  issue_number: prNumber,
  body: 'Comment text'
});
ユーザーの権限を確認する
const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({
  owner: context.repo.owner,
  repo: context.repo.repo,
  username: context.actor
});
const hasWriteAccess = ['admin', 'write'].includes(permissions.permission);
ボットが所有するコメントを冪等に更新する

非表示のマーカーは、ワークフローのコメントを識別するためのものですが、所有者を示すものではありません。コントリビューターやほかのアプリも、自分のコメントに同じマーカーを付けられるためです。マーカーと正確な github-actions[bot] ログイン名の両方で照合し、そのコメントを更新するか、新しいコメントを作成します。一般的な user.type === 'Bot' チェックでは、ワークフローの所有者を特定できません。ワークフローで固定されているアクションの SHA を維持し、pull_request_target ジョブではプルリクエストのフォークからコードを実行しないでください。

const marker = '';
const comments = await github.paginate(github.rest.issues.listComments, {
  owner: context.repo.owner,
  repo: context.repo.repo,
  issue_number: prNumber,
  per_page: 100
});

const body = `${marker}\nComment text`;
const existing = comments.find(comment =>
  comment.user?.login === 'github-actions[bot]' && comment.body?.includes(marker));

if (existing) {
  await github.rest.issues.updateComment({
    owner: context.repo.owner,
    repo: context.repo.repo,
    comment_id: existing.id,
    body
  });
} else {
  await github.rest.issues.createComment({
    owner: context.repo.owner,
    repo: context.repo.repo,
    issue_number: prNumber,
    body
  });
}
特定のコミットにおけるリポジトリファイルを読み込む
const { data: fileData } = await github.rest.repos.getContent({
  owner, repo,
  path: 'eng/Versions.props',
  ref: commitSha
});
const content = Buffer.from(fileData.content, 'base64').toString('utf-8');

参考資料

コメント