🌟

gRPC開発におけるprotoリポジトリのCIベストプラティクス

2023/01/14に公開

以前gRPC開発におけるドキュメントを自動生成するという記事を書いたが、CIがGitLab CIだったのでGitHub Actionsを使用してみた。
ついでにprotoファイルのフォーマットをclang-formatを使用して組み込んで個人的protoリポジトリのベストプラティクスになったので紹介します。

作成したリポジトリはこちら
https://github.com/JY8752/gacha-app-proto

gRPCのドキュメントを自動生成する

適当なprotoのリポジトリを作成し.github/workflows配下にGitHub Actionsを実行するためのymlファイルを作成します。

protoファイルの変更を検知する

今回はprotoファイルの変更を検知したかったのでGitHubのマーケットプレイスで公開されている以下のActionを使用しました。

https://github.com/tj-actions/changed-files

とりあえずprotoファイルの変更を検知するために以下のようにymlファイルに記載。

gen-doc-and-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

ドキュメント生成スクリプトを作成する

https://zenn.dev/jy8752/articles/2e77da36cae0c3

これで作成したスクリプトを少し修正。

generate-document.sh
#!/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のセットアップと実行権限付与のワークフローを追加し、作成したスクリプトを実行する。

gen-doc-and-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

追加した処理はif: steps.changed-files.outputs.any_changed == 'true'を記載し、ファイルに変更があったときのみ実行するようにしている。

これでmainブランチにprotoファイルの変更をpushするたびにドキュメントが自動作成されるようになる。

作成したドキュメントをGitHub Pagesで公開する

ドキュメントはmarkdownとhtmlで出力しているのでGitHub Pagesを使用してネット上に公開することも可能です。公開手順はこちらを参照。

設定するとドキュメントが作成されるたびに公開ページも更新される。今回作成したドキュメントはこちら

https://jy8752.github.io/gacha-app-proto/

protoファイルをフォーマットする

protoファイルのフォーマットにはclang-formatが使用されることが多いようなのでこちらを採用します。

clang-formatのセットアップ

Macであれば以下でインストール。

brew install clang-format

protoファイルをいい感じにフォーマットするのに以下の設定ファイルを作成。

.clang-format
---
Language: Proto
BasedOnStyle: Google
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true

VSCodeでセッティングする

CI関係ないけどVSCodeでprotoファイルを書くなら設定しておくと自動でフォーマットされるので設定しておくといいかも。やり方はこちらの記事でまとめられているのでこちらを参照

https://zenn.dev/y16ra/articles/2a88926f71a744

clang-formatの実行スクリプトを作成

以下のような感じで作成。

clang-format.sh
#!/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に追加する。

gen-doc-and-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ファイルを作成。

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に組み込むといいかもしれない。

以上!!

GitHubで編集を提案

Discussion