Github ActionsでCI構築

## はじめに
「今の開発ブランチ、ビルドできなくない？」
ソース管理してるのにCIを構築していないと実際に起こる会話です。
手元ではビルドできるしターゲットブランチとのコンフリクトもないけど、マージしてみたらビルドは駄目だったなんてことは普通にある話です。

今回はGitHub Actionsを使ってゼロからCIを構築し、「エラーを起こしているブランチがmaster（や、develop）にマージされることはない」という状態を目指してみたいと思います。

## 環境
- .NET 6（今回はそこまで触れません）
- WIndows
- Powershell Core

## 準備
リポジトリ直下に.github/workflowsディレクトリを作成します。
```bash
> mkdir .github/workflows | cd
```
作成したworkflowディレクトリに適当な名前のymlファイルを作成します。
```bash
> New-Item workflow.yml
```
作成したymlファイルが、GitHub Actionsで実行するワークフローを定義するためのファイルになります。

## ワークフローを作る
今回はVisual Studio 2022で作成した適当なサンプルプログラムを対象にCIを構築してみます。

### ワークフロー名をきめる
ワークフローの名前を決めます。
これはGithub上のページで確認したりするのに使う名前なので、わかりやすいものがいいでしょう。
```yaml:workflow.yml
 name: Build
```

## どのタイミングで実行するかを決める
Github Actionsは特定のトリガーをもとに実行されます。
今回はプルリクエストのチェックに使いたいので、pull_requestをトリガーに設定します。
```diff_yaml:workflow.yml
  name: Build

+ on:
+   pull_request:
+     types: [opened, synchronize]
```

利用できるトリガーは[GitHub Docs](https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows)に記載があります。

## 実行するアクションを定義する

```diff_yaml:workflow.yml
  name: Build

  on:
    pull_request:
      types: [opened, synchronize]

+ jobs:
+   build:
+     runs-on: ubuntu-latest
```

一気に書きましたが一つづつ説明します。

### 実行単位
GitHub Actionsには、３つの実行単位があります
- Workflow
  - ワークフロー全体のことです。yamlファイル全体という認識で基本的には問題ないはずです。
- Job
  - 実行するマシンを共有する単位です。同一job内であれば同じマシン、jobを複数作成すれば別々のマシンが使われることになります。
- Step
  - 実行するシェルを共有する単位です。
    stepが複数ある場合、マシンは同じものですが別のシェルが与えられているため、シェル変数などはstep間で共有できません。
    単にコマンドを実行することもできるし、GitHubやサードパーティが公開しているアクションを使用することもできます。

今回は実行するマシンは単一で問題ないので、「build」ジョブ一つのみです。
実行環境は```ubuntu-latest```を選択しています。

実行環境はGitHub側で用意してあるものを利用する「ホステッドランナー」と、自前で用意する「セルフホステッドランナー」のどちらかを選択できます。


### ブランチのチェックアウト
ソースコードを引っ張ってこなければ意味がないので、まずはGitHubからソースコードを取得します。
GitHubの公式アクションを使います。

```diff_yaml:workflow.yml
  name: Build

  on:
    pull_request:
      types: [opened, synchronize]

  jobs:
    build:
      runs-on: ubuntu-latest
+     steps:
+       - name: Checkout
+         uses: actions/checkout@v3
+         
```

### ビルド
ここまでくれば各言語、フレームワークで手元の環境と同じようなコマンドをランナーにやらせるだけです。
今回は.NET 6なのでdotnetコマンドを流します。
（※.NETの場合、事前にSDKのセットアップを実行しておく必要があります。）

```diff_yaml:workflow.yml
  name: Build

  on:
    pull_request:
      types: [opened, synchronize]

  jobs:
    build:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v3
+       - name: Setup .NET
+         uses: actions/setup-dotnet@v2
+       - name: build
+         run: dotnet build -c Release
```

## 実行してみる
master（main）以外のブランチにチェックアウトした後適当にコミットしてプッシュします。
プルリクエストを立てると、ワークフローが実行されます。
成功すれば、緑色のチェックが付きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199145/58087486-8bbd-e806-e0f2-cdffd7171a8b.png)

とりあえずこのプルリクエストはマージしておきます。

## ブランチ保護ルールの設定
さて、これだけでは「ビルド成否はチェックされるけど、ビルドエラーでもマージはできる」という状態なのでmaster（main）にブランチ保護ルール（Branch protection rules）を設定します。
”Require status checks to pass before merging”にチェックを入れ、ワークフロー名を入力し選択します。
”Do not allow bypassing the above settings”にもチェックを入れるとよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199145/403d339e-5f2f-eed7-338c-4cb0cb175743.png)

これを設定した後、適当にビルドエラーになるコードを新規ブランチにプッシュ、プルリクエストを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199145/97a502dd-db35-7552-3ca6-1e1bc3d296cc.png)

プルリクエストを確認すると、ビルドエラーが発生しマージボタンがグレーアウトされます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199145/31b79633-f941-b853-e75a-4b628eb698fe.png)