GitHub Actions v2使ってMSBuildを試してみた


週末にGitHub Actionsを使ってMSBuildするやり方を色々調べつつ、色々触ってみたのでまとめました。
リポジトリ: https://github.com/yuta0428/msbuild-actions-sample/blob/master/.github/workflows/msbuild.yml

GitHub Actions自体のセットアップや詳細な解説は省いてます。（というか自分もまだあまり理解してない）
👇らへん見つつ試しました。

- [ワークフローを設定する](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/configuring-workflows)
  - [GitHub Actionsのワークフロー構文](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions)
  - [ワークフローをトリガーするイベント](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows)
  - [GitHub Actions のコンテキストおよび式の構文](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions)


## 前提

- Visual Studio 2019 Community(16.3.9)で作成したWindowsデスクトップアプリケーション(C++)
- GitHub Actions v2（2019/11/17時点）

## コード
- 最小コードとしてはこれで動きます。
- リポジトリにある `msbuild.yml` は後述する色々を試した結果です。

```yml
name: MSBuild
on: push
jobs:
  build:
    name: MSBuild
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v1

    - name: Setup MSBuild.exe
      uses: warrenbuckley/Setup-MSBuild@v1

    - name: MSBuild
      run: msbuild msbuild_actions_sample.sln
      shell: cmd
```

### 解説
- Windows runnersにVS2019 Enterprise版が入っているため、実行環境は`runs-on: windows-latest`を指定で問題なかったです。
    - 参考：[Using self-hosted runners in a workflow #windows-server-2019
](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/software-installed-on-github-hosted-runners#windows-server-2019)
- VS2017を使用したい、開発環境とバージョンを合わせたい場合などは_self-hosted runner_を使用すればいいです。
   - :warning: privateリポジトリでやること。
   - 参考：[GitHub Actions をローカル環境で実行したい（Self-hosted runners）](https://qiita.com/Kurom96/items/c6782ecc37d41e1d446c)

```yml
    # runs-on: windows-latest
    runs-on: self-hosted
```

- デフォルトでは`msbuild`コマンドへのPATHが通ってないので通す必要があります。
- それをやってくれるのが`uses: warrenbuckley/Setup-MSBuild@v1`です。
    - 内部的には_vswhere.exe_をダウンロードしてきて_MSBuild.exe_を探してPATHに追加してるだけです。
    - https://github.com/warrenbuckley/Setup-MSBuild/blob/master/src/main.ts
- なので、自前で建ててるなら直接PATH通しておいた方が速いです。

## 以下+αでやったこと。できなかったこと。
### 生成結果をアップロードする / upload-artifact
- `uses: actions/upload-artifact@v1@`でできました
    - デフォルトだと_x64/Debug_みたいなパスになるので`-p:OutDir="out/`を指定しました。

```yml
    - name: MSBuild
      run: msbuild msbuild_actions_sample.sln -p:OutDir="out/"
      shell: cmd

    - name: Upload artifact
      uses: actions/upload-artifact@v1
      with:
        name: build-result
        path: ./msbuild_actions_sample/out/
```

### Self-hosted runnersを追加する
- _Self-hosted runners_を追加すると、ワークスペースに `actions-runner` というフォルダが追加されます。
- このフォルダの中に追加時に設定した作業ディレクトリ（この場合だと`work`）が作成され、actions packageやビルド実行結果などが追加されます。

```
.
└── actions-runner
    ├── _diag
    ├── actions-runner-win-x64-2.160.2.zip
    ├── bin
    ├── config.cmd
    ├── externals
    ├── run.cmd
    └── work
```
- 差分として余計なので.gitignoreに追加していいと思います。（言及されてるの見つけれなかったので参考程度に）

```diff:.gitignore
+ actions-runner/ 
```

### dotnet msbuildでもできるのか
- 必要な依存関係をちゃんと解決すればできるのか検証してみた。
- 結論：エラーを解決できなかった:innocent:
- コード：https://github.com/yuta0428/msbuild-actions-sample/blob/master/.github/workflows/dotnetmsbuild.yml
    - Windows runnersに.NET Core 3.0が既に入ってるので`dotnet msbuild`にしただけ。
- 変数設定が必要で、検証時は `runs-on: self-hosted` にしてlocal環境でごちゃごちゃやってました

環境

```cmd
> dotnet --version
3.0.100
```

**VCTargetsPathなくて死ぬ**

```
...\msbuild-actions-sample\msbuild_actions_sample\msbuild_actions_sample.vcxproj(28,3): error MSB4019: The imported project "d:\Microsoft.Cpp.Default.props" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
```
=> VCTargetsPathに`C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160`を設定

**MSB4018: System.TypeLoadException: Could not load type 'Microsoft.Build.Utilities.CanonicalTrackedOutputFiles' from assembly 'Microsoft.Build.Utilities.Core...で死ぬ**

```
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(185,5): error MSB4018: "GetOutOfDateItems" タスクが予期せずに失敗しました。
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(185,5): error MSB4018: System.TypeLoadException: Could not load type 'Microsoft.Build.Utilities.CanonicalTrackedOutputFiles' from assembly 'Microsoft.Build.Utilities.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. 
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(185,5): error MSB4018:    at Microsoft.Build.CPPTasks.GetOutOfDateItems.Execute()
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(185,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() 
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(185,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask) 
```
=> `VCToolsInstallDir`と`WindowsSDKDir`が無いよWarning出てたけどそれ消しても解決できなかった。よく分かってないので諦めました。


## 所感
#### コマンドとか一式入った実行環境が一通り揃っているので簡単にセットアップできる
- ありがたい。細かいことやろうとするなら自前で建てればいいので最悪なんとかなる。
- 料金もprivateリポでも一定時間（月2000分~）までは無料なのでとりあえず試せる。

#### local executeができないのが辛い
- （自分が発見できなかっただけでもしかしたらあるのかもですが）
- 基本的にpushして確認するので、動いてほしくないの別のworkflowも発火して無駄にビルド時間取られます。
- そのため、基本稼働させるworkflowにはbranch filterを設定してあげておいたよさそうに感じました。
    - `master` 、`develop`、 `feaure/*` とかで制限しておく。
    - テスト用に試したいときは該当しないブランチで作業する。
    - 参考：[GitHub Actionsのワークフロー構文#onpushpull_requestbranchestags](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#onpushpull_requestbranchestags)

#### workflowをvalidateできないの辛い
- （自分が発見できなかっただけでry）
- 構文チェックないのでsyntax errorのままpushして失敗することあります
- 自分はGitHub上で_Actions_タブから_Set up a workflow yourself_を押して、新規ファイル追加画面にコピペして確認してました。（そこならsyntax checkしてくれるので）
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83373/0e815466-cf57-e5c4-7cd6-4f7c72c0c8ae.png)


個人的にはCircleCIより使い勝手よくて楽だったのでもっと使っていきたいですね。

うまくいかない場合はコメント等で指摘して頂けると助かります🙇