はじめに
業務でテスト計画書をスプレッドシートに埋める作業を、Claude Code に丸投げできるようにしました。
動かしてみたら、GAS(Google Apps Script)の捉え方がガラッと変わったんですね。
サーバー処理の言語というより、もうちょっと別の何かだった、という話です。
0. この記事で得られること
この記事で持ち帰れるのは次の 3 つです。
- Claude Code から curl で叩いてスプシを自動生成する全体像
- 固定フォーマットじゃないスプシを扱うときの考え方(テンプレ+差分書き換え+行調節)
- すぐ動かせる最小サンプル(数行の GAS Web App+curl)
1. 何を作ったか
QA まわりの仕事で、新しい機能をリリースするたびにテスト計画書をスプレッドシート(以下スプシと書きます)にまとめる作業があります。
テンプレを毎回コピーして開き、画面の確認項目、入力パターン、組合せの表を手で埋める。
地味に時間が溶けるやつです。
これを create-qa-plan というスキルにまとめました。
Claude Code に JIRA チケットの URL と PR を渡すと、中身を読み取って JSON を組み立てる。
それをエンドポイントに POST して、スプシの URL が返ってくる、という流れです。
現状はあえてローカル+手動運用にしています。
JIRA から完全自動でトリガーされるわけではなく、自分が手元の Claude Code に投げて初めて動く。
理由は単純で、テスト計画は中身を人間がレビューしてから保存したいからです。
将来的に JIRA トリガーでフル自動化することはできるけど、いまは「人間が起動する」ところは残しています。
2. Before / After
何が変わったかは、表 1 つで十分です。
| Before(手動) | After(Claude Code 経由) | |
|---|---|---|
| 起点 | テンプレスプシをコピーして開く | コマンドを 1 行投げる |
| 中身を埋める | ケース表とパターン表を手書き | JSON を組み立てて POST |
| 所要時間 | 30 分〜1 時間 | 数分 |
| 自分の作業 | 全部 | 出てきたスプシをレビュー |
体感としては「埋める作業」が「レビューする作業」に変わった、というのが大きいです。手が止まる場所が変わると、考える時間に回せます。
3. アーキテクチャと設計
数分でスプシが返ってくる裏で、実は 4 つの部品が動いています。
3-1. 全体の流れ
Claude Code が JSON を組み立てて curl で n8n に投げる。
n8n が認証を被せて GAS を叩く。
GAS がテンプレートをコピーしてデータを書き込み、URL を返す。
Claude Code はその URL をユーザーに見せるだけです。
3-2. n8n を挟んだ理由
Claude Code 側に Google の認証情報を持たせたくないので、間に n8n(ノーコードで API ワークフローを組めるツール)を挟んでいます。
n8n に OAuth2 credential を 1 つ預けておけば、Claude Code は素の curl を投げるだけで済みます。
n8n を認証ゲートウェイとして使っている、という言い方が近いです。
3-3. GAS をフロントエンド言語として捉える
作ってみて気づいたのは、GAS で書いていたコードが「データを更新する処理」ではなく「画面を組み立てる処理」だった、ということです。
スプシと GAS の関係を、Web フロントエンドに置き換えるとこうなります。
| Web フロントエンド | スプシ × GAS |
|---|---|
| HTML(構造) | セル・行・列 |
| CSS(見た目) | 書式・罫線・色・プルダウン |
| JavaScript(DOM 操作) |
setValue / setBackground / setDataValidation ... |
こう並べると、GAS でやっているのは DB 更新じゃなくて DOM 操作に近い、と分かります。
スプシは表データの置き場ではなく、ユーザーが実際に触る画面そのもの。
GAS はその画面を描く言語。
この視点に立った瞬間、「行が動的に伸びる」という悩みが「動的に UI を組み立てる」という設計の話に置き換わりました。
4. 構築プロセスのつまずき
「GAS でスプシを描く」と決めたものの、最初に詰まったのが「テンプレが完全固定じゃない」という点でした。
4-1. テンプレが"完全固定じゃない"とはどういうことか
テスト計画書は、入力パラメータの数で行が伸び、組合せの数で列が伸び、パターン表ブロックの数まで増減します。
普通の「テンプレに値を埋める」では立ち行きません。
固定セルへの代入ではなく、テンプレを元に動的に UI を組み立てる、という頭の切り替えが必要でした。
実際に詰まったのは大きく 2 つです。
つまずき 1:テンプレの想定数を超えるデータが来た
テンプレはあらかじめ「行 4 つ × ブロック 1 個」みたいな見本の構造を持っています。
ただ実データは、入力パラメータの数で行が増え、パターン表ブロックも 2〜3 個並ぶことがある。
テンプレが想定した数を超えた瞬間に、続くブロックの位置がズレたり、強引に行を増やすと テンプレが持っていたプルダウン(実行結果列)まで一緒に飛ぶ という事故が起きました。
| つまずき | テンプレが想定した行数・ブロック数とデータが合わない。行を増やそうとしてシートを書き換えると、テンプレが用意していた入力規則のプルダウンまで一緒に消えていた。 |
| 対応 | 行は「テンプレ行数 vs 必要行数」の差分の符号で挿入と削除を切り替え、増えた行には書式だけコピーして引き継ぐ。ブロックは P1 を copyTo で複製して値だけ差し替える。書き込みの前にプルダウンを退避しておき、後で戻す。 |
| 学び | テンプレを動かすときは「形をコピーして中身だけ流し込む」を貫く。データと UI 部品(プルダウン)は別物として扱い、データを書き換えるときに UI 部品を巻き込まない。 |
つまずき 2:Claude Code に Google 認証を持たせたくなかった
| つまずき | GAS Web App を「自分のみ」公開にすると、未認証の curl ではログイン画面の HTML が返ってきて呼べない。かといって、Claude Code 側に OAuth トークンを持たせるのは、ローカル運用でも気持ち悪い。 |
| 対応 | 間に n8n を挟んで、Google の OAuth2 credential は n8n に 1 つだけ預ける。Claude Code は素の JSON を curl で n8n に投げるだけ。n8n が認証ゲートウェイとして GAS を叩く形にした。 |
| 学び | Claude Code 側に持たせる必要のない秘密は、外に追い出すと運用が楽になる。同じ発想は他の Google API(Gmail/Calendar)の自動化にも転用できる。 |
5. 再利用できる成果物
ここまでの設計は create-qa-plan 限定の話に見えますが、スプシ × GAS で何か作るときに広く効きます。
| 成果物 | 転用先の例(行数・要素数が事前に決まらないもの中心) |
|---|---|
| GAS コードの設計(テンプレ+差分書き換え+行調節+UI 部品保持) | 行数が事前に決まらない帳票・一覧表全般(請求書の明細行、可変項目のアンケート結果、メンバー名簿など) |
| ブロック単位の複製 | 同じ書式の塊が複数並ぶ文書(顧客別の集計セクションが N 個並ぶ報告書など) |
| n8n を認証ゲートウェイにする構成 | Claude Code 側に Google 認証を持たせず、他の Google API(Gmail/Calendar など)を叩く自動化 |
| Claude Code スキルの構造(プロンプト+JSON 組み立て+エンドポイント POST) | 同じ枠で別のスプシ自動化スキルを増やしていける |
特に GAS コードの設計は、テンプレを別フォーマットに差し替えるだけで別ドメインにそのまま持っていけます。
6. すぐ試せる最初の一歩
n8n を挟むのは後回しで、まず素の GAS Web App だけで動かすところから始めます。
6-1. 最小の GAS Web App
POST で JSON を受け取って、新しいスプシを 1 枚作って A1 に書き込むだけのコードです。
function doPost(e) {
var data = JSON.parse(e.postData.contents);
var ss = SpreadsheetApp.create('test_' + new Date().getTime());
ss.getActiveSheet().getRange('A1').setValue(data.message || 'hello');
return ContentService
.createTextOutput(JSON.stringify({ url: ss.getUrl() }))
.setMimeType(ContentService.MimeType.JSON);
}
6-2. デプロイの最小手順
-
script.google.comで新規プロジェクトを作って、上のコードを貼る - 「デプロイ」→「新しいデプロイ」→ 種類「ウェブアプリ」
- 実行ユーザー:自分/アクセスできるユーザー:全員(curl で素のリクエストを通すため。「自分のみ」だと未認証の curl では Google のログイン画面 HTML が返ってきます。本番運用では n8n 等で認証を被せるか、Workspace ドメイン内に絞る形を検討してください)
- 表示された URL をコピー
6-3. curl で叩く
curl -sL -X POST \
-H "Content-Type: application/json" \
-d '{"message":"hi"}' \
'<デプロイ URL>'
レスポンスにスプシ URL が返ってくれば成功です。ここまで動けば、あとはテンプレのコピー、差分書き換え、行調節、と積み上げていくだけ。
おわりに
スプシを「表データの置き場」じゃなくて「ユーザーが触る画面」として見ると、GAS でやれることの幅が一気に広がります。
自分も最初は GAS をサーバー処理の言語だと思っていたんですが、触ってみたら案外フロントエンド寄りでした。


