WSLを使ってWindows環境で完結するCI環境を構築する

# 目的
ローカルのWindows PCで完結するCI環境を構築すること。
全体イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/b8086ef3-2964-5f54-47c2-4eacd0b448e0.png)

# 前提条件
## 環境
- WSL(Ubuntu)はインストール済
- Visual Studio Codeはインストール済
    - プラグインとしてRemote-WSLはインストール済（Visual Studio Code上からWSL上で作業できるようになる）
- Jenkinsで基本的なjobの作成ができる

## ソースコード
設定例の説明用

https://github.com/azukibar0713/wsl-ci-env

```
├── CMakeLists.txt
├── build                   # CMake実行ディレクトリ
├── include
├── lib
│   ├── ubuntu              # ライブラリ置き場(gtest, gmock)
├── pkgconfig
│   └── ubuntu
├── src                     # ソースコードディレクトリ（テストしたいコード）
│   ├── CMakeLists.txt
│   └── *.cpp               # テスト対象ファイル
└── test                    # テストコードディレクトリ
    ├── CMakeLists.txt
    ├── main.cpp
    └── unittest_***.cpp    # テストケースファイル
```

# 環境構築手順
## gccなどビルド環境に必須なツール
```console:
$ sudo apt install build-essential
```

## CMake
### インストール
```console:
$ sudo apt get -y install cmake
```

## コンパイラをClangに切り替え
`./CMakeLists.txt`に以下記載

```cmake:
set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE string "clang compiler" FORCE)
set(CMAKE_CXX_COMPILER "/usr/bin/clang++" CACHE string "clang++ compiler" FORCE)
```

## GoogleTest
### インストール
レポジトリではビルドしたライブラリを`./lib/ubuntu`以下に含ませているので不要
ライブラリのリンク方法はレポジトリのCMakefile.txtを参照。
自身でインストールする場合は、以下の記事が参考になると思います。

https://qiita.com/ktrmnm/items/667a7b7c93cd3fb78419

### C++ TestMate(VSCode上にGoogleTestの結果を可視化するプラグイン)
https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter

見た目は以下のようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/31cac0cb-9cb9-42c7-bffe-5fe1e1b7bdb0.png" width=80%> 

## カバレッジ
### lcovのインストール
```console:
sudo apt install lcov
```

### coverageを取れるようにするCMake設定

```cmake:
set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} --coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
```

参考
https://qiita.com/imasaaki/items/0021d1ef14660184f396#%E8%A7%A3%E8%AA%AC
https://www.hiroom2.com/2015/07/06/jenkins%E3%81%AEcobertura-plugin%E3%81%A8lcov-to-cobertura-xml%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/

### Code Coverage(VSCode上にカバレッジの結果を可視化するプラグイン)
https://marketplace.visualstudio.com/items?itemName=markis.code-coverage
#### 使い方
カバレッジ情報が含まれているファイルを `coverageディレクトリ` 内に置く必要がある
buildディレクトリ内で `cmake ..`, `make` して実行ファイルを走らせた後

```shell:
$ lcov -c -d ./build -o lcov.info
$ lcov -r lcov.info */googletest/* test/* */c++/* -o lcov.info
$ mv lcov.info ./coverage
```

これで、以下のような見た目になる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/4a94a3ce-9993-891f-06fd-358b508e7d5b.png" width=80%> 

## コード管理、分析
### clang-format(フォーマッター)
Googleで採用されている(by [Googleのソフトウェアエンジニアリング](https://www.oreilly.co.jp/books/9784873119656/))
clang-formatのインストール

```console:
sudo apt install clang-format
```

### clang-tidy(静的解析ツール) 
Googleで採用されている(by [Googleのソフトウェアエンジニアリング](https://www.oreilly.co.jp/books/9784873119656/))
clang-tidyのインストール

```console:
sudo apt install clang-tidy
```

### clang-format, clang-tidyのCMake設定
https://qiita.com/tenmyo/items/f8548ee9bab78f18cd25

を参考に設定する。

他参考サイト
https://qiita.com/yoyomion/items/8ff1f5a63b4b4f757732

## Jenkins
### 参考サイト
https://dev.to/davidkou/install-jenkins-in-windows-subsystem-for-linux-wsl2-209
### インストール
```sh:
$ sudo apt -y install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# JAVA
$ sudo apt -y install openjdk-8-jdk
$ sudo apt -y install openjdk-11-jre-headless
# Jenkins
$ wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add
$ sudo bash -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
$ sudo apt update
$ sudo apt install jenkins
# Update Firewall to enable Jenkins service
$ sudo ufw enable
$ sudo ufw allow 8080 # whatever port number you like
$ Check the status of your port:
$ sudo ufw status
# Run Jenkins server
$ sudo service jenkins start
# この後、Winodwsブラウザのhttp://localhost:8080/ からJenkinsにアクセスできる
# できない場合は JenkinsにWSLをpower shellから`wsl.exe --shutdown` で再起動してから再度jenkins startしてみる
# 初期パスワード確認
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

### 起動
sudo service Jenkins start
### Tips
localhostから拒否されるときは
WSLをpower shellから`wsl.exe --shutdown` で再起動してから、再度WSLを立ち上げてjenkins startしてみる（原因はよくわからない。。）

### 初期設定
Windowsブラウザで http://localhost:8080 にアクセス
Adminパスワードは `$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword` で確認する

## Jenkinsプラグインのインストール設定
### Warningの集計、可視化するプラグイン(Warnings Next Generation)
以下をインストール
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/6aab878f-707a-19b3-6608-08abb6d415b3.png" width=70%>


設定はビルド後の処理から `Record compiler warnings and static analysis results` を選んで、ツールとして `Clang-Tidy` を選択する
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/f282a31a-dd07-fd00-855c-8c29328b8a6c.png" width=70%>

これで↓のような出力が得られる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/7b114574-f677-3939-b953-92ad6d9edbfa.png" width=70%>

### テスト結果集計のプラグイン(JUnitテスト結果の集計)
C++でも`JUnitテスト結果の集計`を使う。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/02dce13b-67b2-0e2f-edb8-04dc5e46db4d.png" width=70%>

`test_result.xml`は実行時に`--gtest_output=xml:test_result.xml`をオプション設定することで出力される。
参考 : https://srz-zumix.blogspot.com/2012/03/google-test-jenkins.html

これで↓のような出力が得られる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/7d5cddcf-2b53-8cf3-7d56-8d8a08e67570.png" width=70%>

### カバレッジをレポートするプラグイン(Cobertuna)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/9622a9fa-7b96-a97a-4d78-b5f89bd0a8dd.png" width=70%>

カバレッジをレポートするにはlcovの出力結果をxmlに変換する必要がある。
[カバレッジ](#カバレッジ) のセクションでlocvのインストールとCMakeの設定は済。
xmlへの変換は`lcov_cobertura.py`が必要となる。
`wget https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-xml/master/lcov_cobertura/lcov_cobertura.py`
から落とせるが、今回はレポジトリ内の`./tool`においてあるファイルを使う。

```shell:
lcov -c -d ./build -o coverage.info
lcov -r coverage.info */googletest/* test/* */c++/* -o coverageFiltered.info
./tool/lcov_cobertura.py coverageFiltered.info -b ./ -o coverage.xml
```

生成されたcoverage.xmlを設定する。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/0590cec9-62e6-3061-9a95-cdd370b699c1.png" width=70%>

これで↓のような出力が得られる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/0ae26c47-0422-07a0-ad39-225d20bf2481.png" width=70%>


### 最終的なshellの内容
```terminal:
git clone https://github.com/azukibar0713/wsl-ci-env/
cd wsl-ci-env
mkdir build
cd build
cmake ..
make
./test/TestSample1 --gtest_output=xml:test_result.xml
cd ..
lcov -c -d ./build -o coverage.info --gcov-tool `pwd`/tool/llvm-gcov.sh
lcov -r coverage.info */googletest/* test/* */c++/* -o coverageFiltered.info
./tool/lcov_cobertura.py coverageFiltered.info -b ./ -o coverage.xml
```