GitHub Actionsでgit submoduleを使う方法

# はじめに
本記事はGitHub Actionsでc++プロジェクトのビルド＆ユニットテストを自動化してみる試みです。
テストフレームワークとしてgoogletest、ビルドツールはCMakeを利用します。
GitHub Actionsとsubmoduleを使ったCI環境構築の参考になれば幸いです。

# 適当なc++プロジェクトを作成
適当なc++プロジェクトを作成。
c++ライブラリはコア処理を行うソースとApiを記述するソースを別で用意。

```
.
└── GitHubActionsTest
    ├── CMakeLists.txt
    ├── include
    │   └── libSampleApi.h
    ├── src
    │   ├── include
    │   │   └── libSampleCoreLib.h
    │   ├── libSampleApi
    │   │   └── libSampleApi.cpp
    │   ├── libSampleCoreLib
    │   │   └── libSampleCoreLib.cpp
    ├── test
    │   └── test.cpp
    └── third_party
        └── googletest
```

# googletestをadd submoduleする
用意しておいた`third_party/googletest`フォルダ以下にgoogletestをadd submoduleする。

```
cd GitHubActionsTest
mkdir third_party
cd third_party/
git submodule add git@github.com:google/googletest.git googletest
cd googletest
git checkout release-1.8.1
```

# testコードを書く
動作チェックのため適当にSuccessになるようなテストを実装。

```C++:test.cpp
#include "libSampleApi.h"
#include "gtest/gtest.h"
TEST(libSampleTestSuite, libSampleConformanceTest) {
	EXPECT_EQ(1, 1);
}
```

# CMakeLists.txtを作成
`add_subdirectory`でgoogletestのビルドを指示し、`add_library`でライブラリのビルドを指示する。
testプロジェクトにはテスト対象のライブラリと`gtest_main`をリンクする。

```CMakeLists:CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
# CMake setup for main library and sample executable
project(CMake_test)
add_subdirectory(third_party/googletest/googletest)
add_library(libSampleApi STATIC
    src/libSampleApi/libSampleApi.cpp
    src/libSampleCoreLib/libSampleCoreLib.cpp
)
add_executable(test
    test/test.cpp
)
target_link_libraries(test
    libSampleApi
    gtest_main
)
target_include_directories(test PUBLIC
    ./include
    third_party/googletest/googletest/include
)

```

# GitHub Actionsの設定
### Personal Access Tokenの取得
Personal Access Token(PAT)はGitHub Actions上でパスワードに代わりに使用する個人アクセストークンです。
[公式ドキュメント](https://docs.github.com/ja/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token)に従い取得しましょう。その際`repo`と`workflow`にチェックを付けます。
取得した値をメモしておきます。
![PersonalAccessToken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014767/28c93950-dc6a-8e63-0ca5-cfcb1ea3e79b.png)
### Personal Access Tokenの設定
c++プロジェクトのrepositoryに取得したPATを設定します。
Nameは後で分かりやすいように、`SUBMODULE_TOKEN`などを設定。
先程メモした値をvalueにコピペします。
![PersonalAccessTokenSet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014767/c89526cc-1c63-829f-f741-9b5e33c03f60.png)

# GitHub Actionsの作成
repositoryホームからActions->New Workflowへ進み、`CMake based projects`の`Set up this workflow`へ進む。
ここでやる事は以下。

 - submoduleのチェックアウト(本記事ではgoogletest)
 - 自分のリポジトリのチェックアウト
 - CMake confitgure
 - build
 - unitテストの実行

設定しておいたPATをsubmoduleのチェックアウト時に利用します。
`token: ${{secrets.SUBMODULE_TOKEN}}`の記述でOK。

```yml:cmake.yml
name: CMake build and unit test

on: pull_request

env:
  BUILD_TYPE: Release

jobs:
  build:
    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{matrix.platform}}

    steps:    
    - name: Checkout submodule
      uses: actions/checkout@v2
      with:
        fetch-depth: 0
        token: ${{secrets.SUBMODULE_TOKEN}}
        submodules: true

    - uses: actions/checkout@v2
    - name: Configure CMake

    - name: Build
      # Build your program with the given configuration
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
      
    - name: Test on Windows
      # test execution on windows-latest
      id: windows
      if: matrix.platform == 'windows-latest'
      run: ./build/${{env.BUILD_TYPE}}/test.exe

    - name: Test on ubuntu
    # test execution on ubuntu-latest
      id: ubuntu
      if: matrix.platform == 'ubuntu-latest'
      run: ./build/test

    - name: Test on macos
    # test execution on macos-latest
      id: macos
      if: matrix.platform == 'macos-latest'
      run: ./build/test
```

# 動作テスト
試しにpull_requestを作成しActionsのログを見てみると、うまく動作し、googletestのログが表示されている事がわかります。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014767/b88555ef-a254-7aab-13b4-24d6e98cb7a5.png)

# Branch Protectionの設定
mainブランチなどにpull_requestした時に自動でテストを実行して、successのときのみmergeを許可するように設定します。
複数のブランチを指定したい時には`[main,release-*,dev]*`のように記述します。
`Require status checks...`にチェックを入れ、テストしたいjob名を入力します。
`Include administrators`にもチェックを入れておくとよいでしょう。
![branchProtectionRule2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014767/fb81662b-5343-64cf-0b16-292c1a6c10d2.png)

unitテストが失敗した時はjobが失敗しpull_requestボタンが押せなくなります。
![testfail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014767/bcf1d735-4953-45d9-1db0-2fc5f89ebd46.png)


# 参考記事
 - [Google TestをCMakeでビルドしテストする](https://qiita.com/toppy-luna/items/5053329537c2826757c1)
 - [GitHub Actionsを使ってみた](https://qiita.com/toppy-luna/items/8358c19bbfb2aee4e848)
 - [GitHubActionsでサブモジュールや他のリポジトリをチェックアウトする方法](https://itneko.com/actions-checkout/)
 - [How to apply github branch rules to two branches?](https://stackoverflow.com/questions/53135414/how-to-apply-github-branch-rules-to-two-branches)