GitLabのCI/CDパイプラインでC#のDLLとドキュメントを書き出す

この記事は、シリーズ記事「[「C#のライブラリプロジェクトをGitLabにpushしたら自動でDLLが書き出されてついでにDocFXで作成されたドキュメントがCloud Run上にデプロイされる」っていうやつをやる](https://qiita.com/soumi/items/c13668052209a35a0965)」の一部です。

# はじめに

GitLab に備わっている CI/CD パイプライン機能を使用して C# プロジェクトのビルドを実行します。
今回対象とするのは、Visual Studio で作成されたライブラリプロジェクトです。
GitLabの方には、あらかじめ Windows の Runner を登録しておく必要がありますので、[この辺りの記事](https://qiita.com/soumi/items/3344dc2fa9538929390b)を参考にしてみて下さい。その上で、今回 Runner となる Windows に必要になるのは以下の機能です。

## Build Tools for Visual Studio 20XX

Visual Studio のプロジェクトをビルドできるツールです。今回はこの中に入っている ``MSBuild`` というコマンドを使用します。

こちらのサイトからダウンロードできます。

https://visualstudio.microsoft.com/ja/downloads/

ページ上部に出てくる「Visual Studio 20XX」 ではなく、その下部にある「すべてのダウンロード」の中から、「Visual Studio 20XX のツール」を選択します。

ダウンロードしたインストーラーでインストールを完了すると、以下のように Visual Studio Installer の一項目として Visual Studio Build Tools が表示されます。

<img width="600px" alt="4488ee2f-0dd3-0e35-f180-9b8909cff3aa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/4488ee2f-0dd3-0e35-f180-9b8909cff3aa.png">

ここから、 C++ Build Tools をインストールできます。

<img width="600px" alt="20ba1bf1-7990-dd05-91ba-f876070c67c6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/20ba1bf1-7990-dd05-91ba-f876070c67c6.png">

また、未イントールであれば、DLLの書き出しターゲットとなる .Net Framework もインストールする必要があります。

<img width="600px" alt="9ef9a39a-fbb4-0391-302a-331437ae2bfe.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/9ef9a39a-fbb4-0391-302a-331437ae2bfe.png">

## NuGet

今回は DocFX を使用してドキュメントを書き出します。
[以前の記事](https://qiita.com/soumi/items/ddb81dc02ea445081aa4)の通りにセットアップしていれば、 DocFX を使用するために NuGet パッケージマネージャを使用しているので、ビルドの際にも必要になります。

コマンドは以下のリンクからダウンロードできます。

https://www.nuget.org/downloads

インストーラーではなく exe が落ちてくるので、パスが通っている所に置くか、任意の所において 環境変数 ``Path`` にそのパスを追加してください。
ただ、今回は色々あってパスが通ってない状態のサンプルになっています。

# .gitlab-ci.ymlを書く

準備が出来たら、 CI のための ymlを書いていきます。
.gitlab-ci.yml というファイルを作成して、GitLab に push すると、自動でジョブが走ります。
最終的に以下のようになりました。

```.gitlab-ci.yml
variables:
  MSBuild: C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe
  NuGet: C:/Tools/nuget.exe

stages:
  - build

build:
  stage: build
  tags:
    - powershell
  script:
    - chcp 65001
    - Start-Process -FilePath $env:NuGet restore -Wait -NoNewWindow
    - Start-Process -FilePath $env:MSBuild ClassLibrary/ClassLibrary.csproj -Wait -NoNewWindow
  artifacts:
    name: ClassLibrary
    paths:
      - ClassLibrary/bin/Debug
      - ClassLibrary/_site

```

## variables

ローカルの環境変数を設定できます。
僕は実行コマンドをパスに通さないで使用したので、ここに各コマンドまでのパスを列挙しました。
以下のコマンド内で使用します。

## stages

以降で定義するコマンドの実行順を定義します。
ここに書かれた順番で実行され、基本的に結果は次のコマンドに持ち越されるようです。

## ジョブ

variables や stages は名称と機能が決まっていましたが、**ジョブの要素名(buildとか)は任意で名称変更可能です**。

### stage

前述の stages で使用する名称です。
ジョブの要素名(buildとか)でなく、ここで指定した名称が使用されます。

### tags

実行する Runner を指定するためのタグです。
ここで指定したタグをすべて持つ Runner でタスクが実行されます。
タグについては、 Runner の登録時に設定できる他、 GitLab のランナー設定で後からでも編集が可能です。

<img width="600px" alt="8a453c2a-9bb1-d8fc-f40a-12e770178e79.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/8a453c2a-9bb1-d8fc-f40a-12e770178e79.png">

<img width="600px" alt="a7a738f1-636c-204f-cee9-4e855aa2d669.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/a7a738f1-636c-204f-cee9-4e855aa2d669.png">


### script

実際に実行するスクリプトです。
今回は ``PowerShell`` を使用しているので、環境変数を参照するには ``$env:変数名`` となります。
``cmd`` を使用しても良いのですが、今後は ``PowerShell`` に[置き換わっていく](https://support.microsoft.com/ja-jp/help/4027690/windows-powershell-is-replacing-command-prompt)という話なので、将来の事を考えて ``PowerShell`` を使用しています。

色々あって前述のymlのような方になっているのですが、ポイントをいくつか挙げておきます。

#### chcp 65001

そのまま実行してしまうと文字化けしてしまうので、文字コードを ``UTF-8`` に変更しています。

が、

<img width="600px" alt="8f1e6d81-615b-2be5-e012-0762114a9e95.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/8f1e6d81-615b-2be5-e012-0762114a9e95.png">

結局文字化けします。
具体的には、コマンドが見つからないとか、そういうエラーを吐く時に文字化けしています。

``CI`` の設定が終わり、コマンドが安定してエラーが出なくなれば以降は問題ないのですが、試行錯誤の時にエラーの内容が分からないのは困りますね…
ご存じの方いましたら、お知恵をコメント頂けると嬉しいです。

### Start-Process -FilePath (コマンドまでのパス) -Wait -NoNewWindow

``PowerShell`` からコマンドを実行しようと思うと、この ``Start-Process`` を使用する必要がありました。最初はオプションをつけずに実行していたのですが、この方法だと別ウィンドウでコマンドが実行される関係上、**コマンドの完了を待たずに次の処理に行ってしまいます。**
そのため、``-Wait`` と ``-NoNewWindow`` オプションをつける事によって同じウィンドウで同期的に実行するようにしています。

### artifacts

このジョブが成功したら成果物として残すものです。
この成果物は、ジョブの結果としてwebからダウンロードできます。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321330/9720c742-6b37-2155-a26e-173f5d05b6af.png)

また、以下のようなリンクで最新版を取得できるので、共有する時はこれを使うと便利だと思います。

```
個人なら
https://(サーバーアドレス)/(ユーザー名)/(プロジェクト名)/-/jobs/artifacts/master/download?job=(ジョブ名)

グループなら
https://(サーバーアドレス)/(グループ名)/(プロジェクト名)/-/jobs/artifacts/master/download?job=(ジョブ名)
```

# おわりに

主に Runner の設定ではまった関係で、これを実現するのにかなり頭をひねった記憶があるのですが、一度正しく設定できてしまえば yml 一発で CI が実現できるのはとても簡単ですね。
``PowerShell`` を使った CI に関しては、探し方が悪かったのかあまり見つけられなかったので、この記事が同じ事を目指す人の一助になれば幸いです。