GAE/Go (+dep) を gcloud コマンドを使わずに CI でデプロイ

GAE (Google App Engine) のアプリをデプロイする際は通常 `gcloud app deploy` コマンドを使います

## dep を使うと `gcloud deploy` できない？

しかし、GAE/Go の組み合わせにおいて、[dep](https://github.com/golang/dep) を使っていると次のようなエラーでデプロイできず困りました。

```
Updating service [default]...failed.
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed:
2018/01/28 01:49:22 go-app-builder: Failed parsing input: package "path/to/project/vendor/google.golang.org/appengine/urlfetch" cannot import internal package "google.golang.org/appengine/internal/urlfetch"
```

すでにこのエラーについては次の記事で取り上げられていました。

- [gcloud app deploy で cannot import internal package エラー](https://qiita.com/najeira/items/02eca8357c58d1460a51)

残念ながらまだ修正されてないようです。

そこで、[この問題のissue](https://issuetracker.google.com/issues/38449183) に上がっていた「古い `goapp` を使う方法」を試してみます。

## `goapp deploy` コマンドを使う
次のページから `goapp` コマンドを含む古い sdk をインストールできます。

https://cloud.google.com/appengine/docs/standard/go/download#previous-sdk

インストール完了したら、普通に `goapp deploy` コマンドを打つだけです。

```console
$ goapp deploy -application <PROJECT_ID> -version <VERSION> path/to/app.yaml
```

これでデプロイに成功！解決！…と思ったのですが、**CIで自動デプロイしようとしたときに問題が発生しました**

`goapp` コマンドは gcloud コマンドの認証トークンを読んでくれないので、認証が通らず、CI で自動デプロイできないということでした。

CI の出力を見ると、「ブラウザを開いて認証してね」というメッセージで完全停止してしまっていました。

```console
$ gcloud auth activate-service-account --key-file path/to/secret.json
$ goapp deploy -application *** -version master
Activated service account credentials for: [***@***.iam.gserviceaccount.com]
Updated property [core/project].
08:47 AM Host: appengine.google.com
08:47 AM Application: *** (was: None); version: master (was: None)
08:47 AM Starting update of app: ***, version: master
08:47 AM Getting current resource limits.
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth......

If your browser is on a different machine then exit and re-run this
application with the command-line parameter 

  --noauth_local_webserver

Too long with no output (exceeded 10m0s)
```


## `appcfg.py update` コマンドを使う
`goapp` コマンドには認証トークンをコマンドで設定するようなオプションがなかったため、`goapp` が内部で呼び出している `appcfg.py` コマンドを使います。

こちらのコマンドでは認証トークンを直接指定できるオプション `--oauth2_access_token` があるので、そこに `gcloud auth print-access-token` を使って `gcloud` コマンド側で認証したトークンを持ってくるという方法です。

```console
$ appcfg.py update --application=<PROJECT_ID> --version=<VERSION> --oauth2_access_token=$(gcloud auth print-access-token 2> /dev/null) path/to/app.yaml
```

これにて無事にCIからのデプロイに成功しました！ (⌒▽⌒)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/10713/8f88869b-c8fb-6717-29d9-88cae87c7be3.png)

```console
$ appcfg.py update --application=*** --version=master --oauth2_access_token=$(gcloud auth print-access-token 2> /dev/null) path/to/app.yaml
Activated service account credentials for: [***@***.iam.gserviceaccount.com]
Updated property [core/project].
09:35 AM Host: appengine.google.com
09:35 AM Application: *** (was: None); version: master (was: None)
09:35 AM Starting update of app: ***, version: master

...

09:35 AM Starting deployment.
09:35 AM Checking if deployment succeeded.
09:35 AM Deployment successful.
09:35 AM Checking if updated app version is serving.
09:36 AM Completed update of app: ***, version: master
```