GAS のGoogle製CLIツール clasp

Google Apps Scriptというと以前はWebのエディター上でしかコードを書けなかった。
手に馴染んだエディタが使えないし、バージョン管理はしにくかった。

Googleから[clasp](https://github.com/google/clasp)が登場し開発環境は大幅に改善された。

- 利用バージョン： clasp v1.1.5

## インストール
`npm` コマンドでインストールできる。

```bash
npm i @google/clasp -g
```
`npm i clasp` でインストールすると以前は別モノがインストールされたが、今は `An alias for @google/clasp`と書かれており単に`clasp` のみでも良さそう。

## ログイン
Webエディタ側から取るにも、Webエディタ側にアップするにもユーザ認証が必要ということで、まずはログインする必要がある。

ログインする前には Google Apps Script API を有効にしておく必要もある。
https://script.google.com/home/usersettings にアクセスして、「オン」になっていることを確認する。
「オフ」になっていれば「オン」にする。

![Google Apps Script API](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32533/f3c4b058-30b7-eb00-0503-49393974241a.png)

APIを有効にしたら `clasp login` コマンドでログインできる。
実行すると次の様にメッセージが表示され、同時にブラウザが立ち上がる。

```console
$ clasp login
🔑  Authorize clasp by visiting this url:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%...(長いので略)
```

ブラウザで開いたページでは次の許可を求めてくる[^1]。
[^1]: ブラウザのないサーバ等で実行した場合には表示されるURLをコピーしてローカルマシンのブラウザで表示すれば良いと思われる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/32533/602f5e3a-eb3d-5c5d-fe5e-219f9fdc33a4.png)

許可するとログイン完了。次のメッセージが表示される。

```
Saved the credentials to ~/.clasprc.json. You may close the page.
```
ログイン情報は`~/.clasprc.json`に書き込まれるようだ。

## ログアウト
次のコマンドでログアウトして、再度利用するには再ログインが必要とドキュメントには書いているが、実行してもログアウトが不十分な感じ。
再ログインが出来なかった。

```sh
clasp logout
```

## 新規スクリプトの作成
`gapps`コマンドではすでに存在するスクリプトから取得する必要があったが、`clasp`では新規に作ることもできる。
`clasp create`コマンドで *sample* というスクリプトを作ってみる。

```console
$ clasp create sample
Created new script: https://script.google.com/d/1y4QuWA-C8UhyRi7sl1kVTuauhJGQ9U0EzISiQPfixxxxxxxxxxxxxxxx/edit
Cloned 1 file.
└─ appsscript.json
```

示されたURLにアクセスすると、見慣れたWebのスクリプトエディタが開き確かにできている。自分でURLをコピペしなくても、次のコマンドで開くことができる。

```bash
clasp open
```

Webエディタの方には空関数myFunctionが書かれた`Code.gs`ファイルが作られている。
一方、ローカルのディレクトリには次の2つのファイルが新たに作成される。

- .clasp.json
- appsscript.json

ファイルの中はそれぞれ次の通り。

```json:.clasp.json
{"scriptId":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
```

```json:appsscript.json
{
  "timeZone": "America/New_York",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER"
}
```

### Google Apps Script APIの有効化
これまで、Google Apps Script APIを使ったことがなければ、`clasp create`等のコマンド実行で次の様にエラーが発生する。

```console
$ clasp create sample
Error: Permission denied. Enable the Apps Script API:
https://script.google.com/home/usersettings
```
ログインの時にした許可は何だったんだろうと思いながら、指示通り `https://script.google.com/home/usersettings` にアクセスしてみると次のページが表示される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/32533/ce9adf4b-0895-50cf-44d5-9bfeb094f462.png)

Google Apps Script API が「オフ」となっている。これを「オン」にすれば良い。
クリックして「オン」にする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/32533/15a17c06-e9dd-e178-18b3-d02fb3221be9.png)

その後はコマンドが実行できるようになる。

## スクリプトのpull

さて、`clasp create`しただけではWebエディタ側に作成された*Code.gs*ファイルもローカルに取ってこれていない状態なので、これを `pull`してみる。

`clasp pull`コマンドを実行する。

```console
$ clasp pull
Cloned 2 files.
└─ Code.js
└─ appsscript.json
```

メッセージによれば、2つのファイルをpullしたようだ。
*appsscript.json*ファイルは `clasp create`した時点であったので、*Code.js* が増えたことになる。
Webエディタで作成されていた *Code.gs*の拡張子が*.js*に書き換えられて取れている。

## スクリプトのpush

`Code.js`を次のように書いてpushしてみてる。

```javascript:Code.js
function myFunction() {
  Logger.log('Hello World');
}
```

`clasp push`コマンドでpushできる。
ただ、このコマンド、カレントディレクトリにある全てファイルをpushしようとするらしい。
GASのコードをローカルで編集する動機としては、gitでバージョン管理をしたり、babelでトランスパイルしたいというものがあると思う。
そうすると、ディレクトリ内には *.git*ディレクトリや*.gitignore*、*node_modules*ディレクトリがあると思う。それらは GASのコードとして有効ではないのでエラーとなるようだ。
push対象のファイルからこれらを除外するために *.claspignore*がある。
これに次の様に書いておけば、カレントディレクトリの **.js*ファイルと、*appsscript.json* がpushの対象となる。

```:.claspignore
**/**
!*.js
!appsscript.json
```

で、`clasp push`を実行すると、次の様に2ファイルがpushされ、書き換えた*Code.js*もWebエディタ側に反映されている。

```console
$ clasp push
└─ Code.js
└─ appsscript.json
Pushed 2 files.
```

このpush、`gapps push`コマンド同様、ローカルのファイル構成で完全に上書きしてしまう。つまり、**Webエディタ側のみにあるファイルは削除してしまう**ので注意が必要だ。

### ディレクトリ構成

そこそこの量のコードを書くと、ファイルやディレクトリを分割したくなると思う。
例えば、*src*ディレクトリにコードを配置する場合、*.claspignore*を次の様に書いてやると、*src*以下の**.js*ファイルがpush対象となる。

```:.claspignore
**/**
!src/*.js
!appsscript.json
```

ローカルに次のファイルがある状態で、pushすると

```ｂａｓｈ
./
├── appsscript.json
└── src
    └── Code.js
```

上記の *Code.js*は *src/Code.gs*という名前となる。
（GASのファイル名って`/`使っていいんだ！と軽く驚いた。）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/32533/56919033-e4e5-08e5-22b0-3a52772026a5.png)

これをpullしてもちゃんと *./src*以下に*Code.js*が配置されるし、Webエディタ側で *src/index.gs*というファイルを作成して、pullしても、*./src*以下に*index.js*ファイルができる。

### *.clasp.json* ファイルの`rootDir`
*.claspignore*ファイルで、push対象を絞り込んでも良いが、*.clasp.json* ファイルに`rootDir`を指定しておくのも便利。

次のように`rootDir`を追加すると、pullもpushもこの *./sources*以下で行われるようになる。

```json:.clasp.json
{"scriptId":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
 "rootDir": "sources"}
```

こんな感じ。

```bash
sources/
├── appsscript.json
└── src
    └── Code.js
```

webpack等でビルドする場合、ビルド成果物の出力先ディレクトリを指定しておくと良いと思う。

## バージョン管理
GASではスクリプトにバージョンを付けて管理できるが、それも `clasp`コマンドでできるようになっている。

`clasp version`でバージョンを作成できる。
次の様に実行する。

```console
$ clasp version '最初のバージョン'
Created version 1.
```
すると、次のようにできている。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/32533/c6075c23-ad89-f710-250f-58ccacf6b36d.png)

バージョンを確認するには`clasp versions`を実行する。

```console
$ clasp versions
~ 1 Version ~
1 - 最初のバージョン
```

## 既存のスクリプトからのクローン
これまで新規スクリプトを作成する流れで書いてきたが、もちろん既存のスクリプトの管理を`clasp`を使って始めることもできる。

`clasp create`の代わりに`clasp clone`を利用すると既存のGASスクリプトのコードを*appsscript.json*を含めローカルにクローンすることができ、同時に *.clasp.json*も作成される。

```console
$ clasp clone xxxSCRIPT-IDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Cloned 2 files.
└─ code.js
└─ appsscript.json
```

*src*フォルダなど、ローカルのカレントディレクトリ以外にコードを配置したい場合は、次の手順でpullし直せばよい。

1. 最初にっクローンしたファイルを削除する
2. *.clasp.json*に `rootDir`設定を追加する
3. `clasp pull`を実行

### ドキュメントに紐付いたスクリプトも管理可能

`clasp clone`で特筆すべきなのは、GASとして独立しているスクリプトをクローンできるのはもちろん、スプレッドシートなどのスクリプトエディタで作成した**ドキュメントに紐付いているスクリプトもクローンできること**である。
`gapps`コマンドではできないことだったので、これだけでも導入の価値があると思う。

`clasp create`のところで説明しなかったが、**新規にスクリプトを作成する場合もスプレッドシート等に紐づくスクリプトとして作成できる**。
その場合にはスクリプト名に加えて、親となるドキュメントのIDを指定する。

```console
$ clasp create MyScript xxxxxGOOGLEーDOCS-IDxxxxxxxxxxx
Created new script: https://script.google.com/d/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/edit
Cloned 1 file.
└─ appsscript.json
```

## Typescript
v1.5からはなんとTypescriptをサポートした。

[詳しくはこちら](https://qiita.com/HeRo/items/f2ce057c6b1456e896ad)
## その他
GASのスクリプトはWebアプリとして公開できるたりするのだが、その操作もできるようだ。
ただ、自分としてはあまり使っていない機能なので、使うようになったら書こうと思う。

## まとめ
- `gapps`（node-google-apps-script)はディスコン。今後は `clasp`を使おう。
- 使い始めるまでのGoogle上の設定も `clasp`のほうが簡単。
- 新規のスクリプトの作成もCLIでできちゃう
- ドキュメントに紐づくスクリプトもようやくローカル開発しやすくなった。

## 参考資料
- ドキュメント：[Command Line Interface using <code>clasp</code>  \|  Apps Script  \|  Google Developers](https://developers.google.com/apps-script/guides/clasp)
- Gitリポジトリ：[google/clasp: Develop Apps Script projects locally\.](https://github.com/google/clasp)
- 新しいGASのマネジメントコンソール： [Apps Script](https://script.google.com/home/my)