🦭

"claspよりも手軽に"GASプロジェクトをローカルの開発環境で管理することができるasideの使い方

2023/11/07に公開

asideとは

claspと同じくGASプロジェクトをローカルの開発環境で管理することができます。
https://github.com/google/aside

  • GASのスクリプトをローカルで書くことができるため、クラウド上のGASエディタにスクリプトを記述しなくて良い
  • Gitにコードをpushできるため、コードを管理しやすい

という上記のclaspのメリットに加えて、以下のような設定が最初からされており便利です。

  • ESLint,Prettierの設定されている
  • Jestによるテスト環境が整っている

claspとは

https://zenn.dev/nenenemo/articles/dcc3fade96d809

asideの注意事項

使用する中でasideの注意事項は以下の点かなと思いました。

  • 2023年3月にリリースされたので、claspに比べるとまだ参考文献が少ない
  • claspではjsで記述できましたが、asideではtsで記述しないとデプロイの際にエラーになる
  • claspでは連携するサービスを選択することができましたが、asideでは選択することができず現在連携できるのはスプレッドシートのみ
  • 型をanyにするとエラーになるのできちんと型を定義するかnode_modules/@types/google-apps-script/google-apps-script-events.d.tsに使用する型を定義する必要がある

Google Apps ScriptのAPIの有効化

まず、下記のリンクにアクセスしてください。
https://script.google.com/home/usersettings

オフになっていると思うのでクリックしてオンにしてください。

画面を戻り、オンになっていればGoogle Apps ScriptのAPIの有効化ができています。

有効化しなかった場合、Error: ENOENT: no such file or directory, lstat 'dist/.clasp.json' というエラーが出て実行できません。

Google Apps Scriptプロジェクトの初期化

npx @google/aside init

コマンドを実行すると以下の質問が出てきます。
Script ID (optional):既存のGoogle Apps ScriptプロジェクトのスクリプトIDを入力できます。もし既に開発中のプロジェクトがあって、それにasideを使って作業したい場合、そのプロジェクトのスクリプトIDをここに入力します。スクリプトIDは、プロジェクトのURLからも見つけることができます。このフィールドはオプショナルですので、新しいプロジェクトを作成する場合は何も入力せずに次へ進めます。

Script ID for production environment (optional): このフィールドは、本番環境用のGoogle Apps ScriptプロジェクトのスクリプトIDを指定するためのものです。開発環境と本番環境を分けたい場合に、別のスクリプトIDをここに入力します。これにより、開発中の変更が直接本番環境に影響を与えることなく、テストや開発を進めることができます。このフィールドもオプショナルですので、本番環境と開発環境を分けない場合は何も入力せずに進めることができます。

✔ Project Title: … test # プロジェクトの名前、後で変更できますのでtestとしました
✔ Generate package.json? … No / Yes # Yesを選択
✔ Adding scripts...
✔ Saving package.json...
✔ Installing dependencies...
✔ Installing src template...
✔ Installing test template...
✔ Script ID (optional): … 
✔ Script ID for production environment (optional): … 

初期化が問題なく終了すると、以下のような表示が出てきます。
アクセスすると上はスプレッドシートのリンク、下はApps Scriptのリンクになっています。

timeZoneの修正

appsscript.json"timeZone"を修正します。

appsscript.json
{
  "timeZone": "Asia/Tokyo",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

デプロイ

開発環境用の.clasp-dev.jsonと本番環境用の.clasp-prod.jsonがありますが、環境に応じて指定してデプロイを行ってください。.clasp.jsonには指定したファイルの内容がコピーされます。

# 開発環境にデプロイ
npm run deploy

# 本番環境にデプロイ
npm run deploy:prod

Manifest file has been updated. Do you want to push and overwrite?

主に本番環境にデプロイを行った場合に下記のように聞かれる場合があります。

Manifest file has been updated. Do you want to push and overwrite? (y/N)

Yesを選択すると、ローカルでの変更がリモートにプッシュされ、リモートのマニフェストファイル(またはその他の関連ファイル)がローカルのバージョンで上書きされます。

上記はスクリプトの違いによって発生しています。

-fオプションは、forceを意味しており、確認なしで強制的にプロジェクトをプッシュすることができます。

今回、本番環境("deploy:prod")では-fオプションが付いていないため、変更がマニフェストファイルに影響を与える場合、ユーザーにプッシュを続行するかどうかの確認を求められます。

package.json
    "deploy": "npm run lint && npm run test && npm run build && ncp .clasp-dev.json .clasp.json && clasp push -f",
    "deploy:prod": "npm run lint && npm run test && npm run build && ncp .clasp-prod.json .clasp.json && clasp push",

デプロイ実施時にエラーが出る場合

下記内容のjsonが表示されると思います。

{
  "responseType": "json",
  "retryConfig": {
    "currentRetryAttempt": 0,
    "retry": 3,
    "httpMethodsToRetry": ["Array"],
    "noResponseRetries": 2,
    "statusCodesToRetry": ["Array"]
  },
  "code": 403,
  "errors": [
    {
      "message": "Drive ACL permission denied, wanted WRITE, got versioned_id {\n  id: \"<scriptId>\"\n  version: 5\n}\nfield {\n  field: CAN_EDIT\n  bool_value: false\n}\nfield {\n  field: IS_OWNER\n  bool_value: false\n}\n",
      "domain": "global",
      "reason": "forbidden"
    }
  ]
}

内容は
wanted WRITE, got versioned_id:書き込み権限(WRITE)を求めているが、与えられたIDはその権限を持っていない。
CAN_EDIT: bool_value: false:編集権限(CAN_EDIT)がfalse、つまり編集不可。
IS_OWNER: bool_value: false:所有者権限(IS_OWNER)もfalse、つまり所有者ではない。

つまり、リソースに対する適切な権限が設定されていないために発生しています。

この場合、そもそもコンソールにデプロイのボタンもないかと思います。

プロジェクトの設定で閲覧中のプロジェクトに対する権限が制限されており、読み取り専用の設定や表示されない設定があります。の表示も出ていると思います。

権限を見直してみてください。

プロジェクトのタイプとアクセス権限の設定

appsscript.jsonを修正します。

appsscript.json
{
  "timeZone": "America/New_York",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "ANYONE_ANONYMOUS"
  }
}

テスト用のdoGet関数を追加

src/index.ts
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const doGet = (e: GoogleAppsScript.Events.DoGet) => {
  const response = JSON.stringify({ hello: 'world' });
  return ContentService.createTextOutput(response).setMimeType(
    ContentService.MimeType.JSON
  );
};

package.jsonを修正し、初めてのデプロイ

package.json"deploy""deploy:prod"の内容を修正します。
DEV_DEPLOYMENT_IDPROD_DEPLOYMENT_IDは後で.envで定義するので今は気にしなくて良いです。

package.json
"deploy": "npm run lint && npm run test && npm run build && ncp .clasp-dev.json .clasp.json && clasp push -f && source .env && clasp deploy $DEV_DEPLOYMENT_ID",
"deploy:prod": "npm run lint && npm run test && npm run build && ncp .clasp-prod.json .clasp.json && clasp push && source .env && clasp deploy $PROD_DEPLOYMENT_ID"

初回デプロイの.envファイルの作成

以下の内容で作成してください。

.env
PROD_DEPLOYMENT_ID=""
DEV_DEPLOYMENT_ID=""

.envにライセンス文言が追加されないように、license-config.jsonを編集します。

license-config.json
{
  "ignore": [
    ".claspignore",
    ".editorconfig",
    ".eslintignore",
    ".gitignore",
    ".prettierignore",
    "*.txt",
    ".github",
    "CONTRIBUTING",
    "build",
    ".env", // 追記
    "dist"
  ],
  "license": "license-header.txt",
  "licenseFormats": {
    "js|ts|mjs": {
      "prepend": "/**",
      "append": " */",
      "eachLine": {
        "prepend": " * "
      }
    },
    "html|md": {
      "prepend": "<!--",
      "append": "-->"
    },
    "sh|^pre-commit": {
      "eachLine": {
        "prepend": "# "
      }
    }
  },
  "trailingWhitespace": "TRIM"
}

追記しない場合は、.envに記述された環境変数を使用する場合に先頭に以下の文章が記述され、.envを読み込むことができずエラーになります。

/**
 * Copyright 2023 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Gitの操作から除外するために.gitignoreにも、.envを追記します。

node_modules
dist/
build/
.DS_Store
.clasp*.json
*.tgz
.env # 追記

初回のデプロイ

デプロイを行ってください。

npm run deploy

デプロイが成功すると以下のように表示されます。
黒塗りの部分はデプロイIDになります。@1.はバージョン1ということです。

今回はコマンドラインを使用してGASにgetリクエストを送ってみます。

curl -L "https://script.google.com/macros/s/<デプロイID(黒塗りの部分)>/exec"

以下のように表示されると思います。

{"hello":"world"}

.envを編集する

このままだとデプロイを行うたびに新しいデプロイIDが発行されてしまいます。
防ぐために.envを編集してください。

.env
PROD_DEPLOYMENT_ID=""
DEV_DEPLOYMENT_ID="-i <デプロイID(黒塗りの部分)>"

-iでデプロイIDを指定することによって、今後npm run deployでデプロイした際に新しいデプロイIDが発行を防ぐことができます。

確認してみます。

index.tsの内容を変更してください。今回は{ hello: 'hoge' }に変更しています。

src/index.ts
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const doGet = (e: GoogleAppsScript.Events.DoGet) => {
  console.log(e.parameter);
  const response = JSON.stringify({ hello: 'hoge' });
  return ContentService.createTextOutput(response).setMimeType(
    ContentService.MimeType.JSON
  );
};

index.tsの内容を変更後、デプロイしてください。

npm run deploy

デプロイIDが先ほどと変わっていないか、確認してください。

created dist in 1.3s
└─ dist/appsscript.json
└─ dist/index.js
Pushed 2 files.
Created version 4.
- <デプロイID>@2.

getリクエストのレスポンス内容も変更されているか確認します。
今回はコマンドラインでも確認していますが、クラウド上のGASエディタで確認しても同じです。

curl -L "https://script.google.com/macros/s/<デプロイID(黒塗りの部分)>/exec"

以下のように表示されると、デプロイIDは変わらずスクリプトの内容が変更されていることが確認できます。

{"hello":"hoge"}

クローンした場合

対象のブランチに移動した後、依存関係をインストールします。

npm install

初期化します。

npx @google/aside init
✔ Project Title: …  # プロジェクトの名前を入力してください 後から変更できます
✔ Generate package.json? … No / Yes # Yesを選択してください
✔ Adding scripts...
✔ Saving package.json...
✔ Installing dependencies...

.eslintrc.json already exists
? Overwrite › No / Yes # NOを選択してください
license-config.json already exists
? Overwrite › No / Yes # NOを選択してください
license-header.txt already exists
? Overwrite › No / Yes # NOを選択してください
tsconfig.json already exists
? Overwrite › No / Yes # NOを選択してください

✔ Script ID (optional): … #開発環境のスクリプトIDを入力してください
✔ Script ID for production environment (optional): … #本番環境のスクリプトIDを入力してください

クローンしたので、プロジェクト設定ファイルがない状態だと思います。下記を実行してください。

npm run deploy

下記3点が作成されます。
.clasp.json
.clasp-dev.json
.clasp-prod.json

下記コマンドでソースが開くので問題がないか確認してください。

npm run open

デプロイ&コマンドソースを開くを同時に実行

npm run deploy && npm run open

Permission denied to enable service [drive]

GASのプロジェクトをGCPに紐づけてログを確認している場合に下記が表示され、スクリプトが実行されない場合があります。
Permission denied to enable service [drive]と表示される場合は対象のドライブにGCPのアクセス権がない場合にログに表示されます。

GASのプロジェクトをGCPに紐づけてログを確認する方法はこちらです。
https://zenn.dev/nenenemo/articles/db5f4d3930276c

参考にさせていただきました

https://umihi.co/posts/20230804-google-aside-hello-world-with-api-url-in-1min/

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion