Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

DoxygenでC++クラスを分析し、GitHub ActionsでPRコメントする仕組みを作ってみました

こんにちは!

株式会社アカツキゲームスに所属クライアントエンジニアのスーです。 今年の The Game Awards もいっぱい情報が発表されましたね。モンハンの新作、FF7 Rebirthすごく楽しみしています。

この記事は Akatsuki Games Advent Calendar 2023 の12日目の記事です。

この記事では、私が所属するチームで Doxygen を利用して特定のクラスが変更された際に、GitHub Actionsで自動的にPRにコメントする仕組みを作ったの知見を共有できればと思います。

Advent Calendar の11日目は渡辺さんの DiscordのStage Channelに読み上げbotを導入する でした。 自分もDiscordのベビーユーザーなので、サクッとbotの作成する方法について大変勉強になりました。 自分で何かを作って、ツールをより便利にする姿勢はとてもいいですね!👍

では、本編を始めたいと思います!!

なぜこの仕組みを作るか

自分が今所属しているチームでは、日本版だけではなく、他の言語に翻訳して全世界のユーザーにプレイしています。 どの文字列が翻訳されるべきか、今まではエンジニアが機能実装する時に、「手動」で追加しています。 人のてでやるのはやはり限界があります。翻訳文字を網羅できなくて国際版制作の工数が増えたことがありました。

もし翻訳文字の追加作業が自動化できだらいいなーと思って、 コードの差分から翻訳文字を抽出して、PR出す時に自動的にその文字を下にコメントする仕組みを作ってみました! この仕組みをどうやって作るのはをここで紹介できればなと思います!

DoxygenでC++コードを分析する

対象コード

前提として、今回の対象コードは下記のようにレイアウトを示すC++ヘッダーです。 ui::Textui::FormatTextは翻訳対象クラスとして抽出したいです。 クラスの中に他のレイアウトクラスを参照する場合があります。参照されたクラスに翻訳文字が存在した場合、その参照先の文字も抽出したいです。 再帰的にヘッダーを分析する必要があります。

#include "LayoutBase.h"

class LayoutAAA : public LayoutBase
{
public:
    bool init() override;

    ui::Image* getImg();
    ui::Text* getText();
    ui::Marquee* getMarquee();
    LayoutBBB* getBBB();
};

class LayoutBBB : public LayoutBase
{
public:
    bool init() override;

    ui::Text* getText();
};

Doxyfile を作成

Doxygenは、C++、C、Java、Objective-C、Python、IDL (Corba、Microsoft 風)、Fortran、VHDL、PHP、C# 向けのドキュメンテーション・システムです。 コードを分析し、HTML、XMLなどの出力フォーマットにドキュメントを出力するプログラムです。 下記のようなよくみるドキュメントはDoxygenで作成しています。

Cocos2dxのドキュメントもDoxygenで生成されました

今回はDoxygenで特定ディレクトリーに入ってるヘッダーファイルをXMLフォーマットに出力します。Doxyfileというファイルで出力内容を設定します。 下記のコマンドで今のディレクトリーにDoxyfileを生成します。

doxygen -g

デフォルト設定を変更した項目だけ紹介します。詳しくはこちらをご覧ください。

GENERATE_XML = YES               # XMLフォーマットを出力
INPUT = path/to/code             # 対象コードのディレクトリー
OUTPUT_DIRECTORY = doxygen/xml   # 出力ディレクトリー

下記のコマンドでXMLを出力します。

doxygen ./Doxyfile

Git diffで取得した差分ファイルを分析する

Git diffで分析対象コードの差分を抽出します。変更されたファイル名を取得し、ファイルごとに分析します。 今回はRubyでスクリプトで書きました。

Doxygen XMLを読み込むするため、doxyparser という gem を使いました。

まずgit diffでコードの差分を取得します。差分があるファイルのXMLを読み込んで、再帰的に分析します。その中に翻訳対象があれば記録して最後にMarkdown形式で出力します。

▼クリックでコードを表示する

出力はこんな感じです:

## LayoutClassesの翻訳差分
### Added Strings
- LayoutAAA
  - [ ] ui::Text* getText
  - [ ] ui::Marquee* getMarquee
  - LayoutBBB
    - [ ] ui::Text* getText

### Removed Strings
- LayoutCCC
  - [ ] ui::Marquee* getMarquee

あとはその結果をPRにコメントすれば...!

GitHub Actionsで翻訳差分をPRにコメントする

対象ディレクトリーが変更があった場合、上記のスクリプトを実行し、その結果をPRにコメントするGitHub Actions workflowで実装しました。

ファイル変更は tj-actions/changed-files で取得します。 前回のプッシュからの差分だけ取得する場合、checkoutのfetch_depth を 0 に設定(超大事)して、since_last_remote_commit: true にすればOKです。

steps:
  - name Checkout Repo
     uses: actions/checkout@v4
     with:
       fetch-depth: 0

  - name: Get changed files
     id: changed-files
     uses: tj-actions/changed-files@v40
     with:
       since_last_remote_commit: true

GitHub CLIを利用してPRにコメントします。下記の処理を実行する前にGitHub CLIのインストールは必要です。 gh auth login しないとPRにコメントする権限がないので必須処理です。

  - name: Comment on pull request
     if: steps.changed-files.outputs.any_modified == 'true'
     env:
       OWNER: ${{ github.repository_owner }}
       REPO: ${{ github.event.repository.name }}
      run: |
        echo '${{ secrets.GITHUB_TOKEN }}' | gh auth login --with-token
        gh pr comment ${{ github.event.number }} --repo ${OWNER}/${REPO} -F ./output.txt

▼クリックでフルコードを表示する gist.github.com

結果

対象ディレクトリーに入ってるファイルを適切に変更して commit & push すると、下記のようなコメントが届きます! 🥳🥳🥳

github-actions君が翻訳差分をPRにコメントしてくれた!ありがとう!

まとめ

Doxygenを使用してC++コードを分析して、GitHub ActionsでPRにコメントする実装の知見とシェアしました。

はじめてRubyのカスタマイズクラスの Set を実装しました。Github Actionsの書き方やGitHub CLIの使い方もとても勉強になりました。Doxygenの他の活用法も考えたいですね〜

皆さんも、もしCIでの特定な差分内容を出力してコメントしたいなら、この記事を読んで、少しでも力になれたのなら嬉しいです。

明日の記事はEito Shimomuraさんの記事です。お楽しみに〜

最後まで読んでいただきありがとうございました!!!