結論
以下のことを開発に取り入れると、コード品質の一定化、
ビルドが動くことの保証を得ることができます。
GitHub Actionsでプッシュ時に、GoogleTestとCppcheckを自動で実行する
流れは以下のとおりです。
- 開発者がGithubにPushする
- GoogleTest && Cppcheck 自動実行
- 自動実行が成功すれば、マージ可とする
本記事の前提条件
- VisualStudio 2022 C++ プロジェクト
- Msbuild と nuget
- GoogleTest と Cppcheck
GitHub Actionsを使い、自動で単体テストや静的解析するメリット
テストと静的解析
テストとは、様々な手法があります。
今回は単体テストをメインで取り上げます
静的解析は静的に(実行せずに)コードを文法解析して、問題点を検出するものです。
この記事ではテストと静的解析の詳細は解説しません。
テストと静的解析を自動で実行すると以下のメリットがあります。
- ビルドの動作の保証
- コード品質の一定化
- 環境構築の負荷軽減
GitHub Actions
開発フローにGitHubを使用している場合、
テストを自動化することのメリットが特に多いです。
なぜならば、不特定多数の開発者の環境構築の手間を減らせるからです。
GitHub Actionsはクラウド上で全てのテストが実行されるため、
テスト用の環境を用意する必要がありません。
また無料枠もかなりあるため、個人開発でも手軽に導入できます。
製品 | Storage | 分 (月あたり) |
---|---|---|
GitHub Free | 500 MB | 2,000 |
GitHub Pro | 1 GB | 3,000 |
具体例
では実際にやってみましょう。
まずは説明と練習のためMSBuildにてC++プロジェクトをビルドしてみます。
MSBuildでC++プロジェクトをビルドする
GitHub Actionの作成ページにて用意されている、
公式テンプレートをカスタマイズしたものです。
これから解説していきます。
name: MSBuild
on:
pull_request:
branches: [ "master" ]
workflow_dispatch:
env:
SOLUTION_FILE_PATH: .
BUILD_CONFIGURATION: Release
jobs:
build:
name: msbuild
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Add MSBuild to PATH
uses: microsoft/[email protected]
- name: Restore NuGet packages
working-directory: ${{env.GITHUB_WORKSPACE}}
run: nuget restore ${{env.SOLUTION_FILE_PATH}}
- name: Build
working-directory: ${{env.GITHUB_WORKSPACE}}
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: artifacts_win-x64
path: x64/${{env.BUILD_CONFIGURATION}}/
(見やすくするため、自動生成されたコメントは省略しています。)
on:
pull_request:
branches: [ "master" ]
workflow_dispatch:
masterブランチにプルリクエストされた際に、このアクションを実行します。
workflow_dispatchとはGitHubのGUI上から任意のタイミングで
アクションを実行できるようにするオプションです。
env:
SOLUTION_FILE_PATH: .
BUILD_CONFIGURATION: Release
このアクション内で使える変数を定義しています。
BUILD_CONFIGURATIONでは、DebugやReleaseなどコンフィグレーションを切り替えられます。
例えばBUILD_CONFIGURATIONを使いたい場合
以下の記法で変数を展開できます。
${{env.BUILD_CONFIGURATION}}
- name: Restore NuGet packages
working-directory: ${{env.GITHUB_WORKSPACE}}
run: nuget restore ${{env.SOLUTION_FILE_PATH}}
Nugetのパッケージを復元します。
- name: Build
working-directory: ${{env.GITHUB_WORKSPACE}}
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
msbuildのコマンドで実際にビルドしています。
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: artifacts_win-x64
path: x64/${{env.BUILD_CONFIGURATION}}/
ビルドした成果物をGithubにアップロードします。
path:にてビルド後のフォルダを指定しています。
つまり、プロジェクトの設定を変更して出力先を変更している場合は対応が必要です。
Google Testをビルドする
GoogleTestはヘッダーオンリーライブラリのため、
ヘッダーをインクルードした上で、通常通りビルド→実行
すればよいです。
つまり上記で説明した、MSbuildビルドを行う際に、
Google Testのプロジェクトも一緒にビルドすればよいです。
複数方法はありますが、
- RootProject.sln
- Library.sln
- Test_Library.sln
のようなプロジェクト構造にし、
RootProject.slnに子のプロジェクトを追加します。
その状態でビルドする時、以下のような構造にします。
- RootProject.sln
- Library.sln
- Test_Library.sln
- x64
- Debug
- Library.exe | Library.dll
- Test_Library.exe
このような状態なら、アクションのymlの最後に
以下のような文を追加すればよいです。
(パスは適時変更してください)
- name: Run Unit Test
run: |
./x64/${{env.BUILD_CONFIGURATION}}/Test_Library.exe
shell: powershell
もしテストが失敗すると
正常失敗の終了コードが返ってくるため、このアクションは失敗します。
アクションが成功しないとマージできないようにする
- プロジェクト → Settingを開く
- Branchesを開く
- Add ruleを開く
まずはBranch name patternに保護したいブランチ名を入力します。
patternなため、完全一致ではありません。
master*などで、一致する名前全てに適用することもできます。
そしてRequire status checks to pass before merging
マージする前にステータスチェックに合格する必要があります
をONにします。
この状態でプルリクエストを出してみると・・・
チェックが完了するまでマージボタンが存在せず、押せません。
※ 管理者に限り、強制的にマージすることは可能です。
Cppcheck
name: cppcheck-action
on:
pull_request:
branches: [ "master" ]
workflow_dispatch:
jobs:
build:
name: cppcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: cppcheck
run : |
sudo apt install cppcheck
cppcheck --max-ctu-depth=2 --output-file=cppcheck_report.txt --enable=all .
- name: print output
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
URL: ${{ github.event.pull_request.html_url }}
run: |
sudo apt-get install nkf
REPORTFILE=./cppcheck_report.txt
WARNINGSFILE=./warnings.txt
if test -f "$REPORTFILE"; then
# Filter innocuous warnings and write the remaining ones to another file.
# Note that you can add more warnings by adding it in the parenthesis,
# with "\|" in front of it. For example, "(missingIncludeSystem\|useStlAlgorithm\)"
sed 's/\[\(missingIncludeSystem\|internalAstError\|missingInclude\|ConfigurationNotChecked\|toomanyconfigs\)\]//g' "$REPORTFILE" > "$WARNINGSFILE"
# are there any remaining warnings?
if grep -qP '\[[a-zA-Z0-9]{5,}\]' "$WARNINGSFILE"; then
# print the remaining warnings
echo Warnings detected:
echo ==================
cat "$WARNINGSFILE" | grep -P '\[[a-zA-Z0-9]{5,}\]'
# fail the job
exit 0
else
echo No warnings detected
fi
else
echo "$REPORTFILE" not found
fi
CppcheckはC++言語の静的解析ツールです。
ローカルに導入する場合GUI版もあります。
これをGithub Actionで自動実行する際は以下の方法で行います。
- apt installでインストール
- 実行
- 結果から終了コードを求める。
apt installでインストール
実はcppcheckをgithub acitonで行うサンプルは、マーケットプレイスにも存在するのですが、
コマンドがラップされてしまい、融通がききませんでした。
Ubuntuランナーならaptが普通に使えるため、apt install cppcheck
でサクッと導入します。
実行
これは通常通りCppcheckをCLIで実行しているだけです。
結果から終了コードを求める。
- name: print output
以下が判定コード
これはくせ者です。
Cppcheckは結果をレポート(テキスト)として出力されるため、
結果がレポートを開いてみないとわかりません。
そのため、ファイルを開いてからロジックで終了コードを求めます。
これは以下のPRを参考にさせていただきました!
結論
テストを自動化することで、コードの品質を一定にできるだけでなく、
ビルドの正常性を保証できたり、
テスト環境の構築の統一や簡略化が期待できます。
これはOSSとして多数の開発者が関わる際に、多大なメリットとなります。
こういった技術をDevopsと言ったりします。
近年では、ビルドエンジニアという専門職もあったりしますので、
興味を持った方は、ぜひ極めてみてください!
コメント