Azure Pipelines でネイティブミドルウェアの CI しました

この記事はMicrosoft Azure Advent Calendar 2018 12/25 の記事です。
https://qiita.com/advent-calendar/2018/azure

はじめに
--------
C++ と C# で構築されたミドルウェアを Azure Pipelines でビルドし、成果物をダウンロードするまでの流れを試してみます。

### 環境
個人開発しているゲームエンジンをビルドします。

| カテゴリ       |       要素 | 
|-----------------|------------------|
| リポジトリ | https://github.com/lriki/Lumino |
| ビルド環境 | Windows, macOS |
| ターゲット環境 | Windows, macOS, iOS, Android, Web(Emscripten) |
| 開発言語 | C/C++, C# |

以下、ビルドシステムの特徴です。

- コマンドひとつでビルド、テスト、デプロイ（zipとインストーラの作成）が行える状態になっています。
- ビルドスクリプトは C# で書かれており、リポジトリルートで "dotnet run" を実行します。
- ほとんどの依存ライブラリ、ツール類はビルドスクリプト内でダウンロードを行います。
- cmake など一部のツールはあらかじめインストールの必要があります。

### 注意点
- 他の CI サービスは使ったことがないので「なぜ Azure Pipelines？」とかは触れません。
- Azure PipeLines の設定は [ビジュアルデザイナ](https://docs.microsoft.com/ja-jp/azure/devops/pipelines/get-started-designer?view=vsts&tabs=new-nav) で行います。YAML はまたこんど。
- 今回は単にビルドするだけで、Pull Request にフックして自動ビルド実行とかはしないです。これもまたこんど。


Build Pipeline の作成
---------
### プロジェクトの作成
最初はまっさらなので、まずプロジェクトを作ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/934c17ee-3f12-7101-3234-02681228e92c.png)


### リポジトリの選択
GitHub を選びます。
初回は [Authorize using OAuth] をクリックして、自分の Github アカウントと Azure を連携させる必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/6f3bf6a7-99ea-7875-d581-b655970cd4d6.png)

認証したら、リポジトリと checkout してくるブランチを選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/9330c816-c5aa-1cef-f240-fbf28389950f.png)


### テンプレートの選択
Pipeline を実行するための設定のひな型を選択します。

今回のターゲットは C++、C# の他にもビルドするものはたくさんあるのですが、まずはビルドの起点となる dotnet コマンドが使いたいので「ASP.NET core」を選んでおきます。（もしかしたら空テンプレートでも dotnet コマンドは入ってるかも）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/fc1d9301-4c4b-b06d-49e4-9c9ffceb41e4.png)

選択すると、Build pipeline がひとつできます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/9e6c348d-3623-443e-d2b4-f94e8fc6752a.png)

### ビルド実行（テスト）
とりあえずデフォルト状態で実行して様子を見てみます。

[Save & queue] から実行できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/dab29054-9f51-6b95-cc55-249c8acfdc1a.png)

ダイアログが出てきますが、そのまま [Save & queue] します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/4aa6e580-ba2c-346c-5a57-e73c07d4f191.png)

画面上部に通知が出てきます。リンクをクリックするとビルドのページに移動します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/97566025-a08f-f919-454f-ffdde9a78492.png)

失敗してました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/af9fbabf-2d5b-969b-2dd2-af26250c9254.png)

ここからビルドできるようにいくつか設定を追加していきます。


Windows ビルド設定
---------
### Agent pool の変更
タスクリスト上部の [Pipeline] をクリックし、右の "Agent pool" から [Hosted VS2017] を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/b444c0f2-cee6-8c1e-234f-1dd1699950fb.png)

### Test, Publish タスクの削除
今回のターゲットシステムでは、これらのタスクに相当する処理は "dotnet run" コマンドの中でまとめて行われるため、不要なので消しておきます。
タスクを右クリックして [Remove selected task(s)] です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/21a40ca2-37ce-e738-e7bd-c87c764263d6.png)

### dotnet run コマンドの追加
任意のコマンドを実行するために「Command Line」タスクを追加します。
"Agent job 1" の右の + ボタンから追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/32e945c7-7271-0ace-4d53-31e2c453e18d.png)

[Script] に実行するコマンドを書き込みます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/5a9ca668-5473-088d-6fed-ce179a0c39ab.png)

### Chocolatey Tools の追加
本記事の執筆時点では、cmake や doxygen などのツールをインストールする Task は標準では用意されていないようでした。（この辺りの C++ サポートは少し弱い印象です。Go や Node はありますが・・・）
今回は [Chocolatey](https://chocolatey.org/) でインストールしていきます。

Chocolatey は Marketplace から入手する必要がありました。"Add tasks" のビューで検索すると出てきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/9bb576c4-4d30-037a-ba23-a4f817663d25.png)

入手したら、"Chocolatey - Install Package" を追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/3afb0590-b9a5-9daa-d3de-8d5a5523eedf.png)

[Display name] と [Package] を指定していきます。
全部で 6 個のパッケージをインストールしました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/2ac8d4d1-2286-127f-9f10-aa67a8592283.png)


### ビルド成果物を配布するための設定
成果物は Azure pipelines の環境変数で示されるフォルダにコピーしておく必要があります。
こうしておかないと永続的に保存できません。

"Copy Files" タスクを追加して、成果物ファイルを $(Build.ArtifactStagingDirectory) フォルダにコピーします。
今回はリポジトリルート下の build フォルダ内に生成される .zip と .msi を配布したいので、それぞれの Copy Files タスクを追加しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/9d03deb9-5e3e-7687-eb82-14989d8c3dab.png)

"Publish Artifact" タスクはデフォルトのままです。
成果物一式に "drop" という名前を付けて、ビルドのページからアクセスできるようにしてあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/ad700de5-79fe-f324-01c1-54b6295a32b8.png)

ここまでで設定は終了です。[Save & queue] からビルドを実行します。


### ビルド成果物のダウンロード
ビルドが成功すると、ビルドのページの右上に [Artifacts] というボタンが表示されます。
ここからたどって、目的のファイルをダウンロードします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/5dcbb2a3-962a-7aa8-8b8e-4ba7b2cfd4e8.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/89342b20-e591-7bc9-1963-57c324543940.png)


macOS ビルド設定
--------
ほとんどの設定は [Build Pipeline の作成](https://qiita.com/drafts/84de17564998d34fc3ef/edit#build-pipeline-%E3%81%AE%E4%BD%9C%E6%88%90) 及び [Windows ビルド設定](https://qiita.com/drafts/84de17564998d34fc3ef/edit#windows-%E3%83%93%E3%83%AB%E3%83%89%E8%A8%AD%E5%AE%9A) と同様です。

### 新しい Build pipeline の追加
Pipeline のリストから、[New] > [New build pipeline] で追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/a10a2d1a-d1f5-045f-cbaf-e372cd337fc6.png)
作成方法は先ほどの [Build Pipeline の作成](https://qiita.com/drafts/84de17564998d34fc3ef/edit#build-pipeline-%E3%81%AE%E4%BD%9C%E6%88%90) と同様です。

### Agent pool の変更
[Hosted macOS] を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/4e8e52d2-4a6c-ed14-7d5a-a23ec8faa8e8.png)

### Task の変更
Windows ではたくさんツールをインストールしましたが、macOS agent ではすでにインストールされていました。
そのため、念のためバージョンをビルドログに表示するだけにしてあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/129567/f266eaae-58d9-5521-4bfb-6622fadcb6c8.png)
他のコマンドも Windows と同様です。

ちなみにタスク名が "Command Line" なところがいかにも Windows ぽいですが、macOS や Linux agent では bash で実行されます。


まとめ
--------
C++ と C# で構築されたミドルウェアを Azure Pipelines でビルドし、成果物をダウンロードするまでの一連の流れを紹介しました。

CI サービスを利用するのは今回が初めてでしたが、意外とすんなり設定を終えることができました。

今回は単にビルドするだけでしたので、今後はもう少し CI ツールらしい運用も試してみようと思います。