Visual Studio 2019のプロジェクトをGitlab CI/CDで自動ビルド&Google Testでテストしてみた

前置き

前回の記事からだいぶ時間が経ってしまったですが、最近使っているGitlab CI/CDについてまとめていきたいと思います。 FizzBuzz問題を実行するプロジェクトとそれをテストするプロジェクトを作成して、それらをCI/CDで実行していきます。

Gitlab CI/CDについて

まずは今回の記事のメインになっているGitlab CI/CDについてです。 詳しい中身に入っていく前に、そもそもCI/CDとは何なのかについてさらっと説明します。

CI/CDとは

CI/CDはそれぞれ何の略でどういう意味なのかというと、以下のような感じみたいです。(CDには二つの意味がある)
参考にしたサイトです。

CI ... Continuous Integration(継続的インテグレーション)

ソースコードの変更を頻繁にメインのブランチにマージして、その度にビルドとテストを実行すること。 こうすることで、変更したコード内に実装ミスなどが含まれていた場合、ビルドやテストの段階ですぐに間違いに気が付くことができます。

CD ... Continuous delivery(継続的デリバリー)

自動でビルドやテストが実行されたあと、それらが成功した場合、手動による操作で本番環境にデプロイすること。

CD ... Continuous deployment(継続的デプロイメント)

自動でビルドやテストが実行されたあと、それらが成功した場合、自動で本番環境にデプロイすること。

ちなみに今回の場合、プロジェクトをビルドして実行ファイルを作成するだけなので、CDの部分はないですね。

Gitlab CI/CDの仕組み

次はGitlab CI/CDがどのような仕組みで動いているかの説明です。基本的に以下のイメージだと思っています。

f:id:ssssssh:20210806000121p:plain
Gitlab CI/CDのイメージ
文章で流れを説明していきます。

  1. ユーザがソースコードを編集する。
  2. ユーザが.gitlab-ci.ymlというファイルをレポジトリのルート直下に配置して、そのファイルにCIを実行したい環境の情報やその環境で実行したいコマンドを記述しておく。
  3. その後ユーザがリモートのブランチにgit pushを実行する。
  4. Gitlab Serverにソースコードと.gitlab-ci.ymlの情報が送られる。
  5. Gitlab ServerはGitlab Runnerにそれらの情報を送り、Gitlab Runnerが.gitlab-ci.ymlの内容を実行していく。

流れは上のような感じなのですが、Gitlab Runnerには二つの種類があります。それが図にも書いてるShared RunnerSpecific Runnerで、それぞれの説明は以下です。

  • Shared Runner

    • Gilabのサーバ上でCIを実行する方式。
    • 指定した環境をこのサーバ上で構築していくため遅い。
  • Specific Runner

    • ユーザがCIを実行する環境を自分で用意する方式。
    • CIを実行したいい環境でGitlab Runnerの実行ファイルをインストールする必要がある。
    • Sharedより早く実行される

それぞれどのように.gitlab-ci.ymlで指定するかはもう少し後で説明します。次からCIを実行するための準備に入っていきます。

全体の作業の流れ

全体の作業の流れは以下のような感じです。

  1. Gitlabでレポジトリ作成 & クローン
  2. Visual Studio 2019でプロジェクト作成 & コード追加 & .gitlab-ci.yml追加
  3. レポジトリにプッシュ

こうすることでレポジトリにプッシュした段階でGitlab Runner上で.gitlab-ci.ymlの内容が実行されます。

Gitlab側の準備

まずはアカウントを持っていない人は作成していただいてログインしてください。その後「New project」→「Create blank project」の順でクリックしてください。そうするとレポジトリの情報を設定できる画面になると思うので、お好きに設定してください。

f:id:ssssssh:20210806131205p:plain
レポジトリ情報入力画面

そのあとはgitコマンドを使ってクローンしてください。gitコマンドをインストールしていない人はインストールしてください。

prog-8.com

Gitlabのレポジトリのページの「Clone」をクリックしてClone with HTTPSのところをコピーしてください。その後コマンドプロンプトでお好きなディレクトリに移動してからgit clone の後にコピーしたurlを貼り付けて実行してください。

git clone <レポジトリのURL>

次はVisual Studio 2019側の準備です。

Visual Studio 2019側の準備

メインのプロジェクトを作成

 まずは自動ビルドの対象となるプロジェクトを作成します。Visual Studio 2019を起動したら、「新しいプロジェクトの作成」をクリックして、次に「空のプロジェクト」を指定します。その後プロジェクト名をci_sampleと入力し、場所をレポジトリをクローンしてきたディレクトに指定します。そうすると以下のような画面が出てくると思います。

f:id:ssssssh:20210803234330p:plain
プロジェクト作成後の画面

実際にソースコードを作成する前にまず.gitignoreファイルを作成します。.gitignoreファイルとはgitによる追跡から特定のファイルを除外するための設定を書き込むファイルです。Visual Studioでプロジェクトを作成するといろいろなファイルが作成されるのですが、実際のビルドに関係が無いファイルや余計な情報などをレポジトリに含めないためにこのファイルを作成します。一から書いていくのは大変なので下のサイトを使います。

www.toptal.com

Visual Studio」を入力すると対応する.gitignoreファイルが作成されるので、それをコピーしてクローンしてきたディレクトリのルート直下に.gitignoreファイルを作成しそこに貼り付けます。エクスプローラーからファイルを作成する方が楽かもしれません。


 次に実際にファイルを作成していきます。ソリューションエクスプローラーのヘッダファイルのところを右クリックして「追加」-> 「新しい項目」->「ヘッダファイル(.h)」を選択します。ファイル名はfizzbuzz.hとします。内容は以下です。#pragma onceは二重インクルード防止のためのものです。

#pragma once
#include<string>
#include <iostream>

using namespace std;

string FizzBuzz(int x) {

    if (x % 15 == 0) {
        return "FizzBuzz";
    }
    else if (x % 5 == 0) {
        return "Buzz";
    }
    else if (x % 3 == 0) {
        return "Fizz";
    }
    else {
        return to_string(x);
    }
}

 次にこのFizzBuzz関数を呼び出すmain.cppを作成してきます。ソリューションエクスプローラーのソースファイルを右クリックして「追加」-> 「新しい項目」->「C++ ファイル(.cpp)」を選択します。ファイル名はmain.cppとします。内容は以下です。

#include <iostream>
#include "../ci_sample/fizzbuzz.h"

using namespace std;

int main() {

    cout << "Hello Visual Studio!" << endl;

    for (int i = 1; i <= 20; i++) {
        cout << FizzBuzz(i) << endl;
    }
    return 0;
}

実行できるか確認してみましょう。ウィンドウの上部にある「ローカル Windows デバッガー」をクリックすると実行されます。 以下のような実行結果がでれば大丈夫です。もし実行してもエラーが出てしまった場合はエラー文を見て対応してください。(main.cppの2行目のincludeのパスが合っているか、ウィルス対策ソフトが邪魔をしていないかなどを確認してもいいかもしれません。)

Hello Visual Studio!
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz

テスト用のプロジェクトを作成

次に今作成したFizzBuzz関数をテストするためのプロジェクト作成していきます。テストにはGoogle Testという単体テスト用のフレームワークを使います。

ソリューションエスクプローラのソリューションと書かれている部分を右クリックして「追加」→「新しいプロジェクト」を選択して「テンプレートの検索」の入力欄でGoogle Testと入力して検索してそれを選択してください。そのあとプロジェクト名をtestとして作成のボタンを押すとテストプロジェクトの構成のウィンドウが出てくるので、テストするプロジェクトの選択で先ほど作成した「ci_sample」を選択して、他の選択肢はそのままで大丈夫です。

f:id:ssssssh:20210806142054p:plain
テストプロジェクトの構成

その後test.cppを以下のように編集してください。テストを追加したい場合は今後このファイルに追加してきます。テストでは3をFizzBuzz関数に入れたとき、文字列の"Fizz"が帰ってきているかどうかなどをテストしています。

#include "pch.h"
#include "../ci_sample/fizzbuzz.h"

/*
TEST(TestCaseName, TestName) {
  EXPECT_EQ(1, 1);
  EXPECT_TRUE(true);
}
*/

TEST(FizzBuzzTest, Fizz) {
    EXPECT_EQ(FizzBuzz(3), "Fizz");
}

TEST(FizzBuzzTest, Buzz) {
    EXPECT_EQ(FizzBuzz(5), "Buzz");
}

TEST(FizzBuzzTest, FizzBuzz) {
    EXPECT_EQ(FizzBuzz(15), "FizzBuzz");
}

TEST(FizzBuzzTest, NotFizzBuzz) {
    EXPECT_EQ(FizzBuzz(7), "7");
}

その後ソリューションエクスプローラーのtestの部分を右クリックして、「スタートアッププロジェクトに設定」をクリックします。これをやることで実行するプロジェクトを変更することができます。実行して以下のような出力がでたらOKです。

Running main() from c:\a\_work\32\s\thirdparty\googletest\googletest\src\gtest_main.cc
[==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from FizzBuzzTest
[ RUN      ] FizzBuzzTest.Fizz
[       OK ] FizzBuzzTest.Fizz (0 ms)
[ RUN      ] FizzBuzzTest.Buzz
[       OK ] FizzBuzzTest.Buzz (0 ms)
[ RUN      ] FizzBuzzTest.FizzBuzz
[       OK ] FizzBuzzTest.FizzBuzz (0 ms)
[ RUN      ] FizzBuzzTest.NotFizzBuzz
[       OK ] FizzBuzzTest.NotFizzBuzz (0 ms)
[----------] 4 tests from FizzBuzzTest (4 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (8 ms total)
[  PASSED  ] 4 tests.

D:\downloads_d\hb_project\ci_sample\Debug\test.exe (プロセス 13208) は、コード 0 で終了しました。
デバッグが停止したときに自動的にコンソールを閉じるには、[ツール] -> [オプション] -> [デバッグ] -> [デバッグの停止時に自 動的にコンソールを閉じる] を有効にします。
このウィンドウを閉じるには、任意のキーを押してください...

.gitlab-ci.ymlの追加

Shared Runnerの場合

以下のようにクローンディレクトリのルート直下に.gitlab-ci.ymlとshared_script.cmdを追加してください。


.gitlab-ci.yml

build on windows:
    tags:
      - windows
    script:
      - CMD.exe /C shared_script.cmd

shared_script.cmd

call "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Auxiliary\\Build\\vcvarsall.bat" x86_x64
echo "build on windows"
cd ci_sample
cd ci_sample
dir
msbuild ci_sample.vcxproj
cd x64/Debug
ci_sample.exe
cd ../../../
dir
nuget.exe restore ci_sample.sln
cd test
msbuild test.vcxproj
dir
cd x64/Debug
dir
test.exe

軽くスクリプトに触れておくと

  • Gitlab Runner上でWindowsを動かすとデフォルトのシェルがパワーシェルになっているため、.batファイルを実行するためにcmd.exeを使ってスクリプトで実行しています。
  • vcvarsall.batはプロジェクトファイル(.vcxproj)をビルドするためのmsbuildコマンドを使うために実行する必要があります。(中身はパスを設定しているだけっぽいです。)
  • nuget.exeはパッケージ管理のコマンドで、今回はGoogle Testをパッケージとして使っているのですが、.gitignoreでpackageフォルダを無視しているのでRunner上でもう一度インストールします。

次はWindows SDKのバージョン確認&変更です。 自分が使っているWindows SDKのバージョンとShared Runnerのwindowsが使っているWindows SDKのバージョンが違う場合はビルドに失敗するので、10.0で合わせておきます。

ソリューションエクスプローラーのtestの部分を右クリックして「プロジェクトの再ターゲット」を選択してWindows SDKのバージョンが10.0になっていることを確認してください。なっていなかったら10.0を選択してください。もしも選択肢に10.0がなかった場合はtest.vcxprojの24行目を以下のように変更してください。

<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>

最後にpushします。

git add .
git commit -m "use CI"
git push

最後にGitlabの自分のレポジトリのページからCIの結果を見てみましょう。

ですが初めての人の場合は、必ず失敗します。ページの上らへんにクレジットカードを入力して、アカウントをバリデーションしろみたいなことが書かれていると思うので、そこからクレジットカードの情報を入力してください。そのあと、「CI/CD」→「Jobs」で一番上のjobを選択してそのページの右上部にあるRetryボタンをクリックしてもう一度CIを走らせてください。

うまくいっていれば以下のような画面が見られるはずです。

f:id:ssssssh:20210806153445p:plain
CIの結果

Specific Runnerの場合

Specific Runnerを使う場合はプライベートのレポジトリで実行することを強くお勧めします。今回の場合、自分のpcをSpecific Runnerとして使用するので、パブリックのレポジトリにしていると、第三者が編集したコードが自分のpcで実行されてしまう可能性があるからです。なのでプライベートレポジトリで実行したほうが安心です。

自分のwindows pcをSpecific Runnerとして使用する場合、Gitlab Runnerをインストールする必要があります。以下のGitlabのページから実行ファイルをダウンロードします。載っている手順を参考に準備をしていきます。

Install GitLab Runner on Windows | GitLab

  1. C:\GitLab-Runnerを作成
  2. 環境にあった実行ファイルを ダウンロードしてgitlab-runner.exeにリネームし、作成したディレクトリに配置
  3. このフォルダと実行ファイルの書き込み権限を制限するのですが、いまいちやり方が分からなかった。プロパティのセキュリティのところから編集?
  4. 管理者でコマンドプロンプトを開いて作成したフォルダに移動して、以下のコマンドを実行してGitlab Runnerをインストール。
 gitlab-runner install

5, 次のコマンドでGitlab Runnerを登録

gitlab-runner.exe register

このコマンドを実行すると入力を求められるので以下のように入力していきます。 最初のurlとtokenはレポジトリのページの「Settings」→「CI/CD」とクリックしていき「Runners」のところの「Expand」をクリックしたところで見ることができます。

C:\GitLab-Runner>gitlab-runner.exe register
Runtime platform                                    arch=amd64 os=windows pid=26664 revision=8925d9a0 version=14.1.0
Enter the GitLab instance URL (for example, https://gitlab.com/):
https://gitlab.com/        ← URLを入力
Enter the registration token:
XXXXXXXXXXXXXXXXX      ← tokenを入力
Enter a description for the runner:    
[LAPTOP-AAAAAAA]: MyRunner    ← runnerの名前を登録
Enter tags for the runner (comma-separated):
hogehoge(お好きにどうぞ)    ← 重要:.gitlab-ci.ymlでこれを指定すると.gitlab-ci.ymlの内容がこのタグと一致するマシンで実行される
Registering runner... succeeded                     runner=SVUUqTs7
Enter an executor: custom, shell, ssh, docker+machine, kubernetes, docker, docker-windows, docker-ssh, parallels, virtualbox, docker-ssh+machine:
shell    ← shellを入力
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

6, config.tomlの編集。installなどを実行するとC://Gitlab-Runnerのフォルダにconfig.tomlがあります。それを開いて以下のように編集してpowershellではなくコマンドプロンプトを使うように変更します。

concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "MyRunner"
  url = "https://gitlab.com/"
  token = "hogegeogheogaweog"
  executor = "shell"
  shell = "cmd"    ← ここをpwshからcmdに変更
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]

7, 最後に次のコマンドでGitlab Runnerをサービスとして起動します。

gitlab-runner.exe start

またconfig.tomlを編集したら再読み込みするために一度stopを実行した後にもう一度startをしてgitlab-runnerを再起動しましょう。 以上がGitlab Runnerの設定でした。

この後はShared Runnerのときと同じで、メインとテストのプロジェクトの作成の両方してください。shared_script.cmdを作成する必要はないのですが、.gitlab-ci.ymlは以下のようにしてください。

.gitlab-ci.yml

build on windows:
    tags:
      - hogehoge(自身が設定したタグ)
    script:
        - chcp 65001
        - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_x64
        - echo "build on windows"
        - cd ci_sample
        - cd ci_sample
        - dir
        - msbuild ci_sample.vcxproj
        - cd x64/Debug
        - ci_sample.exe
        - cd ../../../
        - dir
        - nuget.exe restore ci_sample.sln
        - cd test
        - msbuild test.vcxproj
        - dir
        - cd x64/Debug
        - dir
        - test.exe

またnuget.exeをci_sample.slnと同じ階層に配置してください。ダウンロードは次のサイトからできます。

docs.microsoft.com

そして最後にSharedのときと同じようにgitコマンドを使ってaddしてcommitしたらpushしてください。 これもGitlabのCI/CDのページから確認できて、最後にJob succeededが確認出来たら成功です。

あとがき

文章書くのが遅すぎて、完成に結構時間がかかってしまった。