claspでGoogle Apps Scriptをローカル開発・デプロイ検証してみた

こんにちは、SCSKの齋藤です。
本記事では、Google Apps Script(GAS)のコードをGitで管理しつつ、`clasp`というCLIツールを使ってローカル開発・デプロイ検証をしてみた話を紹介します。

はじめに

GASはブラウザ上のスクリプトエディタでそのまま編集・実行できる手軽さが魅力ですが、検証を進めるうちに困りごとも出てきました。エディタ上で直接編集していると変更履歴が追いづらく、複数のスプレッドシートに同じようなスクリプトを配布したい場合にコピペで運用するのも辛くなってきます。普段Gitでコード管理しているエンジニアとしては、GASのコードもGitで管理して、ローカルのエディタで書きたいと感じていました。

そこで見つけたのが、Googleが公式に提供しているclasp(Command Line Apps Script Projects)というCLIツールです。ローカルのファイルとGASプロジェクトを同期でき、gitと組み合わせれば普段の開発フローに近い形でGASを管理できそうだと思い、検証環境で試してみることにしました。

ただ、実際に使ってみると「複数の環境(開発用・検証用・本番用)にどうやって同じコードを配布するか」「マージ前に手元だけで動作確認したい場合はどうするか」といった、CI/CDに寄せた運用を考える必要が出てきました。GitHub Actionsで自動デプロイを組む一方、マージ前にローカルから直接pushして確認したい場面もあり、この使い分けで何度かハマったので、その過程を紹介します。

この記事では、claspを使ったリポジトリ構成、環境別デプロイの仕組み、そしてマージ前にローカルで動作確認する際に気をつけたポイントをまとめます。

claspとは

clasp(Command Line Apps Script Projects)は、Googleが公式に提供しているGoogle Apps Script用のCLIツールです。npm経由でインストールでき、ローカルのファイルシステムにあるJavaScript/TypeScriptファイルと、クラウド上のGASプロジェクトとの間でコードを同期(push/pull)できます。

claspを使う一番のメリットは、GASのコードを普段のソフトウェア開発と同じようにGitで管理できるようになることです。ブラウザのスクリプトエディタでは難しかったプルリクエストによるレビューや、変更履歴の追跡、複数人での並行開発がしやすくなります。また、ローカルのエディタ(VS Codeなど)の補完やLintの恩恵を受けられるのも嬉しいポイントです。

claspはOAuthでGoogleアカウントにログインして認可を行い、その認可情報を使ってApps Script APIを通じてプロジェクトのソースコードを操作します。そのため利用するには、Googleアカウント側でApps Script APIを有効にしておく必要があります。

コマンドも直感的で、clasp createで新規プロジェクト作成、clasp pushでローカルの変更をクラウドに反映、clasp pullでクラウド側の最新コードをローカルに取得、clasp openでブラウザのスクリプトエディタを開く、といった操作が一通り揃っています。ライブラリプロジェクトと、スプレッドシートに紐づくコンテナバインドスクリプトの両方に対応しているため、共通ロジックをライブラリ化して複数のスプレッドシートから参照する、という構成にも使えます。

やってみる

リポジトリ構成:共通ライブラリとシート紐付けスクリプトを1つにまとめる

検証環境では、複数のスプレッドシートで同じようなバリデーションロジックを使いたかったため、共通処理をまとめた「ライブラリ」プロジェクトと、各スプレッドシートに紐づく「コンテナバインドスクリプト」を分けて、1つのGitリポジトリで管理する構成にしてみました。


gas-project/
├── library/            # 共通ロジック(ライブラリとしてデプロイ)
│   └── validation.js
├── sheet/               # 各スプレッドシートに紐づくスクリプト
│   └── main.gs
└── .clasp.template.json # 環境ごとに差し込むテンプレート

コンテナバインドスクリプト側からライブラリを参照することで、バリデーションロジックの修正がライブラリ1箇所で完結し、各スプレッドシート側は薄いラッパーとして保てるようにしています。

環境別デプロイ:envsubstでscriptIdを差し込む

claspは.clasp.jsonというファイルでpush/pull対象のGASプロジェクト(scriptId)を指定します。開発用・検証用・本番用で別々のGASプロジェクトを使いたかったため、scriptIdを直書きせず、テンプレートファイルと環境変数を使って動的に生成する方式にしてみました。


{
  "scriptId": "${SCRIPT_ID}",
  "rootDir": "./library"
}

CI上でこのテンプレートに対してenvsubstをかけ、環境ごとのSCRIPT_IDを差し込んだ.clasp.jsonを生成してからclasp pushする、という流れです。


export SCRIPT_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
envsubst < .clasp.template.json > .clasp.json
clasp push --force

この方式にしたことで、.clasp.json自体はGit管理対象から外しつつ、テンプレートだけをリポジトリに残せるようになりました。GitHub Actions側ではブランチ名に応じて環境変数を切り替え、開発ブランチへのpushは開発環境のscriptIdへ、本番ブランチへのpushは本番環境のscriptIdへ、という形でワークフローを組んでいます。

マージ前にローカルだけで動作確認する

CI/CDが組めていても、レビュー前の実装がちゃんと動くか、マージする前に手元で確認したいことがあります。そこで、CIと同じ手順をローカルで手動再現してみました。


nvm install 20 && nvm use 20
npm install -g @google/clasp
clasp login --no-localhost

ここでいくつかハマりポイントがありました(詳細は後述)。ログインが済んだら、CIと同様にテンプレートへ環境変数を差し込んで、開発用の環境だけに向けてpushします。


export SCRIPT_ID="<検証用GASプロジェクトのID>"
envsubst < .clasp.template.json > .clasp.json
clasp push --force

この状態で実際にスプレッドシートを開いて動作確認し、問題なければコミットしてPRを作成する、という流れにしています。ローカルでの検証はあくまで開発用の環境に対してのみ行い、検証用・本番用のプロジェクトには触れないようにする、という点は徹底しています。

clasp pullで「今デプロイされている実体」を確認する

動作確認中に「ボタンを押したらスクリプト関数が見つからないと言われる」といった、コードは合っているはずなのに動かないケースに遭遇することがあります。こういうときは、clasp pullでクラウド側の実際のコードをローカルに取得し、意図した内容が本当にデプロイされているかを確認するのが有効でした。


clasp pull
git diff

git diffで差分が出なければ、コードそのものは正しくデプロイされていることになるので、原因はコード以外(ブラウザ側のキャッシュなど)にありそうだと切り分けられます。実際に今回の検証でもこの手順で「コードは正しい」ことを確認でき、原因の切り分けに役立ちました。

工夫したところ・ハマったところ

Apps Script APIを有効化していないとログインでハマる

clasp loginは問題なく通っても、実際にclasp pushを叩くと権限エラーになることがありました。原因は、Googleアカウントの設定画面でApps Script APIが有効化されていなかったことでした。Google Workspaceの管理画面ではなく、個人のGoogleアカウント設定(script.google.com の設定ページ)でオン/オフを切り替えるタイプの設定なので、見落としやすいポイントだと思います。

Jestでのユニットテストとclasp pushでの実機確認を組み合わせる

GASのコードはブラウザ内のグローバルオブジェクト(SpreadsheetAppUrlFetchAppなど)に依存しているため、ローカルでそのままテストを実行することはできません。そこで、これらのグローバルオブジェクトをモックにしたJestのユニットテストをまず用意し、ロジック単体の正しさはローカルで素早く検証できるようにしました。そのうえで、実際にスプレッドシート上で動かす必要がある部分(トリガーの発火やUIの挙動など)は、clasp pushで開発用環境に反映してから手動で確認する、という二段構えのテスト戦略にしています。すべてを実機確認に頼らずに済むようになり、開発のサイクルが少し早くなったように感じました。

まとめ

  • claspを使うことで、GASのコードもGitで管理し、普段のエディタで開発できるようになりました
  • .clasp.template.json + envsubstで環境ごとのscriptIdを差し込む方式にすることで、.clasp.jsonをGit管理対象から外しつつ複数環境に対応できました
  • マージ前にローカルで動作確認したい場合は、CIと同じ手順を手動で再現するのがシンプルでよさそうです
  • clasp pullは「今実際にデプロイされているコード」を確認できるため、コードの問題か環境側の問題かを切り分ける際に便利でした
×
タイトルとURLをコピーしました