Google App Engine で始める Go 実践入門 Part 9 【Makefile】

連載を通して簡単なブログアプリを作成しつつ Go/GAE について学んでいきます。
今回は Makefile についての説明です。

- [Part 1. 『GO / Cloud SDK のインストール』](https://qiita.com/rema424/items/743bc508ef70cd980e17)
- [Part 2. 『GOPATH』](https://qiita.com/rema424/items/009f6345eb75a80bf369)
- [Part 3. 『プロジェクトの作成』](https://qiita.com/rema424/items/19b946c311f3b3b3f953)
- [Part 4. 『ディレクトリ構成』](https://qiita.com/rema424/items/1a6096c77b90ea350a26)
- [Part 5. 『Visual Studio Code』](https://qiita.com/rema424/items/b2ecdd2c7ec7fc1b0a7c)
- [Part 6. 『Hello World』](https://qiita.com/rema424/items/66ce1b02d7de588e63cf)
- [Part 7. 『リモートデバッグ』](https://qiita.com/rema424/items/996aaf0ab69670224af4)
- [Part 8. 『デプロイ』](https://qiita.com/rema424/items/dbf851908dbfc95f9b6f)
- [Part 9. 『Makefile』](https://qiita.com/rema424/items/3a099dfb023aa06086f5) ← イマココ
- [Part 10. 『Circle CI』](https://qiita.com/rema424/items/4dcb37346cecc544dfaa)
- Part 11. 『Dependency Injection』
- Part 12. 『ローカルDB with Docker』
- Part 13. 『gorm』
- Part 14. 『Cloud SQL』
- Part 15. 『Cloud SQL Proxy』
- Part 16. 『HTML』
- Part 17. 『CSS/JS』
- Part 18. 『Google Analytics』
- Part 19. 『Google Search Console』
- Part 20. 『A/B テスト』
- Part 21. 『ユーザーの作成』
- Part 22. 『Firebase Auth』
- Part 23. 『記事の作成』
- Part 24. 『コメントの作成』
- Part 25. 『ページネーション』

# Makefile

Makefile にタスクを定義していきます。
Node.js で言うところの `npm run-scripts` に相当します。

まずはファイルを作成します。

```sh
# プロジェクトルートに移動
cd $GOPATH/src/github.com/rema424/go-gae-blog-app-example

# Makefile を作成
touch Makefile
```

Makefile を編集します。

```makefile:go-gae-blog-app-example/Makefile
.PHONY: all

# 環境変数を読み込んで変数に代入する
# ただし、コマンドライン引数で値が渡された場合は、環境変数が定義されていてもコマンドライン引数の方を優先する
# e.g.) make xxxxxx project_id=xxxxxxxxxxxx
project_id := ${GOOGLE_PROJECT_ID}
version := ${GAE_VERSION}

# シェルコマンドの実行結果を代入する時は$でエスケープする
OAUTH2_ACCESS_TOKEN=$$(gcloud auth print-access-token 2> /dev/null)

#
# タスク定義
#

# 認証
# e.g.) make login
login:
	gcloud auth activate-service-account --key-file key/deploy.json

# ローカルサーバーの起動
# e.g.) make dev
dev:
	dev_appserver.py module/blog/main/app.yaml --support_datastore_emulator=False --go_debugging=True

# デバッガーのアタッチ
# e.g.) make debug
debug:
	@PID=$$(ps u | grep _go_ap[p] | head -1 | awk '{print $$2}'); dlv attach $$PID --headless --listen=127.0.0.1:2345 --api-version=2

# デプロイ
# e.g.) make update version=1
update:
	appcfg.py update -A ${project_id} -V ${version} --oauth2_access_token=${OAUTH2_ACCESS_TOKEN} module/blog/main

# トラフィックを徐々に切り替える (500が発生しない 基本的にはこっち)
# e.g) make migrate version=1
migrate:
	appcfg.py migrate_traffic -A ${project_id} -V ${version} --oauth2_access_token=${OAUTH2_ACCESS_TOKEN} module/blog/main

# トラフィックを一瞬で切り替える (一瞬500が発生する)
# e.g) make set version=1
set:
	appcfg.py set_default_version -A ${project_id} -V ${version} --oauth2_access_token=${OAUTH2_ACCESS_TOKEN} module/blog/main

# e.g) make open version=1
open:
	gcloud app browse --version ${version}
```

タスクを定義したので、今後ローカル開発サーバーの起動やデプロイは `make` コマンドを使って次のように実行できます。

```sh
# ローカル開発サーバーの起動
make dev

# デバッガーのアタッチ
make debug

# デプロイ
make update project_id=<your-project-id> version=<version>

# トラフィックの移行
make migrate project_id=<your-project-id> version=<version>
```

# direnv

デプロイやトラフィックの移行を実行する際に `project_id` を指定する必要がありますが、`version` とは違い同一のプロジェクト内では常に一定です。

したがって `project_id` はコマンドライン引数で毎回指定するのではなく、設定ファイルに記述して値を使い回せるようにします。

これを実現するために、`direnv` というツールを使います。

まずは Homebrew で direnv をインストールします。

```sh
# direnv のインストール
brew install direnv
```

`.envrc` ファイルを作成します。

```sh
# プロジェクトルートに移動
cd $GOPATH/src/github.com/rema424/go-gae-blog-app-example

# .envrc を作成
touch .envrc

# .gitignore に .envrc を追加
echo '.envrc' >> .gitignore
```

`.envrc` を編集します。自分のプロジェクトの ID を記載してください。

```sh:go-gae-blog-app-example/.envrc
export GOOGLE_PROJECT_ID=XXXXXXXXXXXX
```

direnv を有効にします。

```sh
# direnv の有効化
direnv allow

# 環境変数が export されていることを確認
echo $GOOGLE_PROJECT_ID
```

デプロイやトラフィックの移行は次のコマンドで実行できるようになります。

```sh
# デプロイ
make update version=<version>

# トラフィックの移行
make migrate version=<version>
```

# おわりに

次回のテーマは『[Circle CI](https://qiita.com/rema424/items/4dcb37346cecc544dfaa)』です。

よかったら Twitter フォローしてね。[@_rema424](https://twitter.com/_rema424)