gRPC開発におけるprotoリポジトリのCIベストプラティクス
以前gRPC開発におけるドキュメントを自動生成するという記事を書いたが、CIがGitLab CIだったのでGitHub Actionsを使用してみた。
ついでにprotoファイルのフォーマットをclang-formatを使用して組み込んで個人的protoリポジトリのベストプラティクスになったので紹介します。
作成したリポジトリはこちら
gRPCのドキュメントを自動生成する
適当なprotoのリポジトリを作成し.github/workflows配下にGitHub Actionsを実行するためのymlファイルを作成します。
protoファイルの変更を検知する
今回はprotoファイルの変更を検知したかったのでGitHubのマーケットプレイスで公開されている以下のActionを使用しました。
とりあえずprotoファイルの変更を検知するために以下のようにymlファイルに記載。
name: Generate Document And Format
on:
push:
branches:
- "main"
jobs:
generate-doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# 変更検知するのに前回の履歴も取得
with:
fetch-depth: 2
# 変更ファイルを取得
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
with:
files: |
**/*.proto
ドキュメント生成スクリプトを作成する
これで作成したスクリプトを少し修正。
#!/bin/bash
apt-get update && apt-get install -y unzip
# protocolbufのインストール
curl -OL https://github.com/google/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip
unzip protoc-3.19.4-linux-x86_64.zip -d protoc3
sudo mv protoc3/bin/* /usr/local/bin/
sudo mv protoc3/include/* /usr/local/include/
# protoc-gen-docのインストール
go install github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc@latest
# gitのセットアップ
git remote set-url origin https://github-actions:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}
git config --global user.name "${GITHUB_ACTOR}"
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
# docディレクトリがなければ作る
if [ ! -d ./docs ]; then
mkdir ./docs
fi
# ドキュメント作成(markdownとhtmlの2種類を生成)
protoc \
--doc_out=./docs \
--doc_opt=html,index.html \
./**/*.proto
protoc \
--doc_out=./docs \
--doc_opt=markdown,index.md \
./**/*.proto
# ごみ削除
if [ -d ./protoc3 ]; then
rm -r protoc3
fi
if [ -e protoc-3.19.4-linux-x86_64.zip ]; then
rm protoc-3.19.4-linux-x86_64.zip
fi
# 差分があればコミットし直す
if [ `git status -s | wc -l` -gt 0 ]; then
git add ./docs
git commit -m 'update document'
git push --push-option=ci.skip origin $CI_COMMIT_REF_NAME
echo "Success commit"
else
echo "Exit due to no difference"
fi
実行環境を整えスクリプトを実行する
ymlファイルにgoのセットアップと実行権限付与のワークフローを追加し、作成したスクリプトを実行する。
name: Generate Document And Format
on:
push:
branches:
- "main"
jobs:
generate-doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# 変更検知するのに前回の履歴も取得
with:
fetch-depth: 2
# 変更ファイルを取得
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
with:
files: |
**/*.proto
+ # goのセットアップ
+ - name: Set up golang
+ if: steps.changed-files.outputs.any_changed == 'true'
+ uses: actions/setup-go@v3
+ with:
+ go-version: '>=1.18.4'
+ # 実行権限付与
+ - name: Add Permision
+ if: steps.changed-files.outputs.any_changed == 'true'
+ working-directory: .github/script
+ run: chmod a+x generate-document.sh
+ # 変更ファイルがあればドキュメント更新を実行する
+ - name: Run
+ if: steps.changed-files.outputs.any_changed == 'true'
+ run: ./.github/script/generate-document.sh
追加した処理はif: steps.changed-files.outputs.any_changed == 'true'
を記載し、ファイルに変更があったときのみ実行するようにしている。
これでmainブランチにprotoファイルの変更をpushするたびにドキュメントが自動作成されるようになる。
作成したドキュメントをGitHub Pagesで公開する
ドキュメントはmarkdownとhtmlで出力しているのでGitHub Pagesを使用してネット上に公開することも可能です。公開手順はこちらを参照。
設定するとドキュメントが作成されるたびに公開ページも更新される。今回作成したドキュメントはこちら
protoファイルをフォーマットする
protoファイルのフォーマットにはclang-formatが使用されることが多いようなのでこちらを採用します。
clang-formatのセットアップ
Macであれば以下でインストール。
brew install clang-format
protoファイルをいい感じにフォーマットするのに以下の設定ファイルを作成。
---
Language: Proto
BasedOnStyle: Google
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
VSCodeでセッティングする
CI関係ないけどVSCodeでprotoファイルを書くなら設定しておくと自動でフォーマットされるので設定しておくといいかも。やり方はこちらの記事でまとめられているのでこちらを参照
clang-formatの実行スクリプトを作成
以下のような感じで作成。
#!/bin/bash
apt-get update && apt-get install -y clang-format
find . -name "*.proto" | xargs clang-format -i
# gitのセットアップ
git remote set-url origin https://github-actions:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}
git config --global user.name "${GITHUB_ACTOR}"
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
# 差分があればコミットし直す
if [ `git status -s | wc -l` -gt 0 ]; then
git add .
git commit -m 'clang-format'
git push --push-option=ci.skip origin $CI_COMMIT_REF_NAME
echo "Success format"
else
echo "Exit due to no difference"
fi
ワークフローにclang-formatの実行を追加する
上記で作成したスクリプトの実行をymlに追加する。
name: Generate Document And Format
on:
push:
branches:
- "main"
jobs:
generate-doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# 変更検知するのに前回の履歴も取得
with:
fetch-depth: 2
# 変更ファイルを取得
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
with:
files: |
**/*.proto
# goのセットアップ
- name: Set up golang
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/setup-go@v3
with:
go-version: '>=1.18.4'
# 実行権限付与
- name: Add Permision
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: .github/script
run: chmod a+x generate-document.sh
# 変更ファイルがあればドキュメント更新を実行する
- name: Run
if: steps.changed-files.outputs.any_changed == 'true'
run: ./.github/script/generate-document.sh
+ clang-format:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ # 実行権限付与
+ - name: Add Permision
+ working-directory: .github/script
+ run: chmod a+x clang-format.sh
+ # フォーマット実行
+ - name: Run
+ run: ./.github/script/clang-format.sh
これでドキュメントの作成とフォーマットを自動で実行されるはず。
pre-commitでclang-formatの実行を設定する
CI上でのフォーマットは保険的な感じで基本的にはローカルでフォーマットしておきたい。
VSCodeなどで開発しているならば保存時の自動フォーマット設定をプラグインなどで設定できるかもしれないがコミット前に実行するようにpre-commitを設定しておくのが確実。
.githooks配下に以下のpre-commitファイルを作成。
#!/bin/bash
if type "clang-format" > /dev/null 2>&1; then
echo "Execute clang-format"
find . -name "*.proto" | xargs clang-format -i
else
echo "Not exist clang-format"
exit 1
fi
以下のコマンドを実行することでpre-commitを設定することができる。
git config core.hooksPath .githooks
まとめ
ドキュメントの手動作成はメンテナンスコストが高くて辛みなのでできればドキュメントは自動で作成されるようにしておきたい。そして、ドキュメントの内容を充実させるためにprotoファイルのコメントをちゃんと書くようにもなるという効果も期待できるのでこのようなCIは組み込みたいなと思う。
また、ファイルのコメントも増えて記述量も多くなってきてもいるのでprotoファイルのフォーマットをかけられるのは嬉しい。フォーマットはローカルで実行でいいかもしれないがドキュメント作成のようなCIを作成するなら保険でCIに組み込むといいかもしれない。
以上!!
Discussion