GitHub Actionsを自分で書かなくなった日
GitHub ActionsのYAMLを書くのが嫌いだった。インデントを間違えて動かない、ドキュメントを読んでもオプションが多すぎる、動作確認のためにpushしてCI待ちを繰り返す。
YAMLとの格闘
GitHub Actionsの設定はYAML。プログラミング言語ではないけど、書き方を間違えるとエラーになる。しかもエラーメッセージがわかりにくい。
「steps」の下に「run」を書くのか「uses」を書くのか。「with」のパラメータ名は何か。毎回ドキュメントとにらめっこしていた。
特にしんどいのが、ワークフローの構文エラーがpush後にしかわからない点だった。ローカルではactというツールで検証できるけど、Docker環境の差異でローカルでは通るのに本番では落ちる、という場面に何度も遭遇した。YAMLのインデントが1段ズレているだけでジョブ全体が沈黙する。エラーの原因を突き止めるまでにpushを5〜6回繰り返すこともあった。
AIに投げたら一発で動いた
Claude Codeに「Go のプロジェクトのCI を作って。lint、test、buildを実行して、mainブランチへのpush時にデプロイ」と指示した。
出てきたYAMLが、一発で動いた。自分で書いたら2時間はかかっていたものが、AIなら5分。しかも、キャッシュの設定やマトリクスビルドまで含まれていた。
具体的にどうやっているか
AIでGitHub Actionsのワークフローを生成するとき、自分がやっている手順を書いておく。
ステップ1:要件を箇条書きにする。最初にやるのは、ワークフローで何をしたいかの整理。「PR時にlintとtestを走らせる」「mainマージ時にCloud Runへデプロイする」「毎日深夜にバッチジョブを実行する」など、やりたいことを箇条書きにする。この段階でYAMLの書き方は一切考えない。
ステップ2:AIにプロジェクト構成を伝える。言語、フレームワーク、デプロイ先、使っているツール。これを伝えないとAIは汎用的なテンプレートしか出せない。たとえば「GoでGCP Cloud Runにデプロイしている。Dockerfileはリポジトリルートにある。golangci-lintでlintしている」と伝える。具体的であるほど、出てくるYAMLの精度が上がる。
ステップ3:生成されたYAMLを読む。ここが大事で、AIが生成したものをそのまま使わない。actions/checkout@v4のバージョンが古くないか、キャッシュキーの設計は妥当か、permissionsが最小権限になっているか。生成後に必ず目を通す。
ステップ4:段階的に動作確認する。最初からフルのワークフローを動かすのではなく、まずlintだけ、次にtest追加、最後にdeploy追加、という形で段階的にpushして確認する。一度に全部入れると、どこで壊れたかわからなくなる。
この手順を踏むと、AIが出したYAMLがそのまま使えなかった場合でも、修正箇所がすぐわかる。
CI/CDパイプラインを丸ごと自動構築した話
実際にあった事例を紹介する。新しいGoのマイクロサービスを立ち上げたとき、CI/CDパイプライン全体をAIで構築した。
必要だったのは以下の構成。
- PRオープン時:lint(golangci-lint)、unit test、integration test
- mainマージ時:Dockerイメージのビルド、GCR(Google Container Registry)へのpush、Cloud Runへのデプロイ
- タグ作成時:本番環境へのデプロイ
Claude Codeにこの要件とプロジェクト構成を伝えたら、3つのワークフローファイル(ci.yml、deploy-staging.yml、deploy-production.yml)を生成してくれた。
驚いたのは、Workload Identity Federationを使ったGCPの認証設定まで含まれていた点。サービスアカウントキーをシークレットに保存する古いやり方ではなく、OIDCトークンを使う方式を提案してきた。自分で調べたら半日はかかるような設定だった。
ただし、Cloud Runのサービス名やリージョンの指定は環境固有の値なので、ここは自分で埋める必要があった。AIは「ここを埋めてください」とプレースホルダーを残してくれたので、迷うことはなかった。
AIが得意なパターン
GitHub Actionsの生成でAIが特に得意なのは、定型パターンの組み合わせ。
言語別のセットアップ。Go、Node.js、Python、Rust。それぞれの標準的なCI構成をAIは知っている。バージョン指定、依存関係のキャッシュ、テスト実行まで含めたテンプレートを即座に出してくれる。
複合ワークフロー。lint + test + build + deploy の組み合わせ。ステップ間の依存関係(needsの設定)も正しく書いてくれる。
マトリクスビルド。複数バージョンや複数OSでのテスト。matrix strategyの書き方は覚えにくいけど、AIに任せれば一発。
Reusable Workflows。複数リポジトリで共通のCI構成を使いたい場合、workflow_callを使ったReusable Workflowsの構成もAIは得意。呼び出し側と定義側の両方のYAMLを整合性を保って生成してくれる。自分で書くと、inputs/outputsの受け渡しで型を間違えたり、secretsの受け渡し方法でハマったりするけど、AIならその辺りを正しく書いてくれる。
Composite Actions。小さな処理をアクションとして切り出すパターンも得意。action.ymlの書き方は独特で、runs.using: compositeのなかでshellを明示する必要があるなど、細かいルールが多い。こういう「覚えても忘れる系」の構文はAI向きだと感じる。
注意点:シークレットとパーミッション
AIに全部任せて安心、とはいかない。特にセキュリティ周り。
シークレットの扱い。AIが生成したYAMLにシークレット名が含まれていることがある。実際のシークレット値ではないけど、シークレット名からインフラ構成が推測される可能性がある。
パーミッション。permissions の設定はAIが適切に書いてくれないことがある。最小権限の原則に従っているか、人間が確認する必要がある。
サードパーティアクションのバージョン固定。AIがuses: actions/checkout@v4のようにメジャーバージョンだけで指定することがある。セキュリティを考えると、コミットSHAで固定するのが望ましい。自分はAIが生成したあとに@v4を@SHA値に置き換える作業をしている。Dependabotでアクションの更新を監視する設定もセットで入れておくといい。
トラブルシューティングで助かった場面
AIが役立つのは、ワークフローの新規作成だけではない。CIが壊れたときのトラブルシューティングでもかなり助かっている。
事例1:キャッシュが効かなくなった。ある日突然CIが遅くなった。調べるとキャッシュのヒット率が0%になっていた。原因は、package-lock.jsonのパスがリポジトリのリファクタリングで変わっていたのに、キャッシュキーのhashFilesのパスが古いままだったこと。AIにワークフローのYAMLとエラーログを渡したら、「キャッシュキーのパスが実際のファイルパスと一致していない」と即座に指摘してくれた。
事例2:並列ジョブ間のアーティファクト受け渡し。buildジョブの成果物をdeployジョブで使いたいが、actions/upload-artifactとactions/download-artifactの設定でハマった。v3からv4への破壊的変更があり、ドキュメントを読んでも動かない。AIにエラーログを貼って聞いたら、v4ではupload-artifactとdownload-artifactでアーティファクト名のデフォルト挙動が変わっていることを教えてくれた。
事例3:GITHUB_TOKENの権限不足。PRにコメントを書くステップがResource not accessible by integrationで落ちていた。AIに聞いたら、permissionsにpull-requests: writeが足りないことをすぐ指摘してくれた。さらに、フォークからのPRではGITHUB_TOKENの権限が制限されることも教えてくれて、pull_request_targetトリガーの使い分けまで説明してくれた。
こういったトラブルは、エラーメッセージだけでは原因がわかりにくい。AIにYAMLとエラーログを一緒に渡すと、パターンマッチで原因を特定してくれることが多い。
既存ワークフローの改善にも使える
新規作成だけでなく、既存のワークフローの改善にも使える。
「このワークフローの実行時間を短くして」と投げると、キャッシュの追加、並列実行の提案、不要なステップの指摘をしてくれる。
実際にCI時間が12分から7分に短縮できたケースがあった。キャッシュキーの設定が甘かったのをAIが指摘してくれた。
他にも、テストの並列化で効果が出た例がある。Goのテストを-count=1で直列実行していたのを、パッケージ単位で分割してマトリクスビルドにしたら、テスト時間が8分から3分に縮まった。分割の仕方もAIが提案してくれた。go list ./...の出力をmatrixのinputに使う方法は、自分では思いつかなかったと思う。
AIが苦手な部分もある
万能ではない。AIに任せて失敗した場面も正直に書いておく。
環境固有の設定。自社のネットワーク構成やVPN経由のアクセスが必要なデプロイ先など、パブリックなドキュメントに載っていない設定はAIにはわからない。self-hosted runnerの設定や、社内プロキシの設定はどうしても自分で書く必要がある。
複雑な条件分岐。if条件が入れ子になるような複雑なワークフローは、AIが生成したものが意図通りに動かないことがある。たとえば「PRのラベルにskip-deployがついていたらデプロイをスキップ、ただしforce-deployラベルがついていたら強制デプロイ」のような条件は、AIが出したif式のgithubコンテキストの参照が微妙に間違っていた。
ワークフロー間の連携。workflow_runトリガーで別のワークフローの完了をフックにする構成は、AIが生成したものがうまく動かなかった経験がある。トリガー元のブランチフィルタとの組み合わせが複雑で、何度かやりとりして修正した。
こういう場面では、AIに丸投げではなく「たたき台を出してもらって、自分で調整する」というスタンスが重要になる。
YAMLは書けなくていい
これは言い過ぎかもしれないけど、GitHub ActionsのYAMLを暗記する必要はなくなったと感じる。構造を理解していれば、詳細はAIに書かせればいい。
大事なのは「何をCI/CDでやりたいか」を明確にすること。目的が明確なら、AIは正確な実装を出してくれる。
逆に言えば、CI/CDの概念自体を理解していないとAIの出力を検証できない。「ジョブとステップの違い」「アーティファクトの受け渡し」「環境変数とシークレットの使い分け」「トリガーの種類と挙動」。こういった基本概念は知っておく必要がある。道具としてのYAMLの書き方はAIに任せていいけど、CI/CDパイプラインの設計力は人間側に残る。
結局、AIが変えたのは「YAMLを書く時間」であって、「CI/CDを設計する時間」ではない。設計ができる人がAIを使うと生産性が跳ね上がる。設計をスキップしてAIに丸投げすると、動くけど意図が不明瞭なワークフローができあがる。
関連記事
他の記事
ブラウザ横スクロールアクションゲーム開発記|TypeScript×Canvasで作るネオンランナー
HTML5 CanvasとTypeScriptで横スクロールアクションゲーム「ネオンランナー」を自作した。物理エンジン、衝突判定、操作性の工夫を解説する。
ブラウザで遊べるテトリス風パズルをTypeScriptで作った話
HTML5 CanvasとTypeScriptでテトリス風ブロックパズルを実装した。エンジンとUIを分離するSnapshotパターンや、ネオン演出のこだわりを解説する。
ゲーム実況のサムネイル作りで学んだデザインの基本
非デザイナーがゲーム配信のサムネイルを自作し続けて気づいた、視認性・配色・構図の基本ルール。試行錯誤の記録。
配信のコメント欄が動いた瞬間の話。ゼロからイチの体験
ゲーム配信でコメントがゼロの日々を超えて、初めてリアルタイムでコメントが来た瞬間の話。ゼロからイチの体験がモチベーションを変えた。