GitHub Actions チュートリアル

# この記事の内容
この記事はGitHub Actionsを初めて作ってみる方向けのチュートリアルです。
CICDの重要性と実際にGitHub Actionsを作ってみる手順を記載します。

# GitHub Actionsとは
GitHubが提供するワークフローエンジンです。
GitHubの各機能と連携して、タスクを自動化できます。
GitHubの操作をトリガーにしてあらかじめ登録した操作を行うことができるため、CIの実装を簡単に行うことができます。

# CICDの重要性について
## ソフトウェアエンジニアの仕事
> ソフトウェアエンジニアの仕事は「ソフトウェアを通してユーザーに価値を届けること」です。
> その中心的な活動はプログラミングです。しかし単にコードを書くだけでは、価値はユーザーに届きません。
> 仕事を完遂するには、２つの活動が必須です。
> 
> １. コードをソフトウェアへ変換し、正しく動作するか検証する
> ２. ソフトウェアをユーザーが使える状態にする
> 
> これらの活動はソフトウェアの種類を問わず、普遍的に必要です。

GitHub CI/CD 実践ガイドより引用

ユーザーに価値を届けるためには、ソフトウェアを作った後に正しく動作するかを検証し、ユーザーが使える状態にする必要があります。

### 継続して価値を届ける
ユーザーに価値を届けるという活動は継続して行う必要があります。

どんなに素晴らしい製品の計画も本当に価値が届けられるかどうかは試してみないとわかりません。
どんなに優秀なエンジニアでも一度に全ての機能を作ることはできません。

我々は少しずつ価値を形にし、継続して届け続ける必要があります。
そのため「コードをソフトウェアへ変換し、正しく動作するか検証する」ことも「ソフトウェアをユーザーが使える状態にする」ことも繰り返し行う必要があります。

### チームで仕事をする
大きなソフトウェアを一人で作ることは難しいです。
そのためソフトウェアの開発はチームで行われることが多いです。

複数の人が関わる場合、検証のやり方は工夫する必要があります。
また作業を行う人のスキルや慣れによってミスが発生しないように工夫する必要があります。

こういったソフトウェアエンジニアとしての仕事をする上で重要になるのがCICDです。

## CICD

### CI　継続的インテグレーション
インテグレーションとは変更したコードをコードベースへ取り込んで検証することです。
ソフトウェアの検証ではビルド、静的解析、テストなどが行われます。

ソフトウェアの検証は小さな単位で繰り返し行うことが重要です。
たくさんの修正が入ってから検証をすると、問題が起きた際に以下のようなことが起こります。

- どの修正が原因だったのかを特定することが難しくなる
- 問題の修正が難しくなる

小さな単位で繰り返し行うためには自動化が重要です。

実際に行われるCIの例としては以下のようなものがあります。
- PreMerge(Pull Requestがマージされる前に行う検証)でビルドが通るかを確認
- PreMergeで修正箇所のUnitTestの行う
- PreMergeで静的解析ツールを使った検証を行う

PreMergeのチェックが通らない場合はマージをできなくすることでコードベースを守る。

- 日次で全てのUnitTestを実行する
- 日次でE2Eテストを実行する

PreMergeは速度も重要なので時間のかかる処理は日次で実行する。

### CD 継続的デリバリー
デリバリーとはソフトウェアをユーザーが利用できる状態にすることです。

Webアプリであればサーバーに変更したソフトウェアを反映する、iOSやAndroidのアプリであれば新しいバージョンのアプリをストアなどにリリースするといった作業を行います。デリバリーはソフトウェアによって異なる作業が必要で、手順も複雑なためヒューマンエラーが発生しやすい作業です。

デリバリーのスピードはソフトウェアの競争力に直結します。
新しい機能を早く届けることができれば、それだけユーザーを獲得できる可能性が高まります。また不具合が発生してしまった場合も、すぐに修正してデリバリーすることができれば、ユーザーへの影響を小さくすることができます。
そのためここでも自動化が重要なポイントになります。

# GitHub ActionsでCIを実装してみよう
このようにCICDはソフトウェアエンジニアにとって重要な活動を助けるツールであり、良いCICDを構築していくこともソフトウェアエンジニアの大事な仕事です。
GitHub Actionsを使ってCIを実装してみましょう。

## GitHub ActionsでHello World
まずはGitHub Actionsがどのように動作するのかを確認するため、Hello Worldをやってみましょう。

### ワークフローファイル
GitHub Actionsで実行されるワークフローはワークフローファイルとして定義し、リポジトリに含めることで実行されます。
ワークフローファイルはリポジトリの `.github/workflows/` にymlファイルとして配置します。
必ずこのフォルダ直下に配置する必要があるので注意してください。

例 `.github/workflows/HelloWorld.yml` 
```yml
name: HelloWorld                 # ワークフローの名前
on: push                         # ワークフローが動作するトリガー、この記載ではpushしたときに動作する
jobs:                            # jobの定義
  hello-world:                   # jobのID
    runs-on: ubuntu-latest       # ランナー（ジョブが動作するDocker Image）、今回はubuntuの最新のイメージを利用
    steps:                       # ここからjobの中で実行されるコマンドですよーという意味
      - name: Hello World        # stepは一つ一つ名前がつけることができます（つけておくとどこで失敗したのかがわかりやすくなります）
        run: echo "Hello World"  # 実行されるコマンド、echoでHello Worldを表示
```

ファイルが作成できたらリポジトリにpushしてHello Worldが表示されることを確認してみましょう。
リポジトリのActionsタブを選択すると、これまでに実行されたワークフローが表示されます。
緑のアイコンが成功したもの、赤のアイコンが失敗したものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/67ee3a6b-b083-4b53-a80b-fcda0394f623.png)

ワークフローを選択すると実行されたジョブがすべて表示されます。
今回は１つだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/5b5a8737-6990-4cd3-b5b5-f4efe57d0498.png)

さらにジョブを選択すると実行されたジョブの詳細を確認できます。
ここに各ステップが表示され、ステップを開くとechoコマンドが実行されていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/a15be63d-dde5-4027-8976-27324e53c470.png)

## PreMergeでbuildが通ることをチェックする
次にPull Requestが作成された時にbuildを実行してチェックするCIを作成してみましょう。
最後に答えの例を記載していますが、まずは自分でやり方を考えてみてください。

:::note info
ヒント
ubuntu-latestはまっさらな環境のため、buildを行うためには準備が必要です。
:::

- ソースコードの取得
```yml
    - name: Checkout repository   
      uses: actions/checkout@v4   # uses: actions でGitHubが用意しているアクションを実施します
                                  # ここではcheckoutを実施する指示です。@v4はcheckoutを行うactionのバージョン
                                  # この記載でPR元のbranchのコードがcheckoutされます
```

- node.jsのインストール
```yml
    - name: Setup Node.js         # Node.jsのセットアップもActionが用意されています
      uses: actions/setup-node@v3
      with:
        node-version: '23'        # セットアップするバージョンを指定できます
```

- コマンドを実行する際は毎回ルートディレクトリが起点になるので注意
- ymlファイルのインデントのミスに注意

うまくいけばこのようにmainブランチへのPull Requestを作成した際にbuildが実行されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/054653a0-0b31-4c80-98fe-d601ea981ffe.png)

<details><summary>答えの一例</summary>
frontendディレクトリ以下にあるnode.jsのアプリケーションのbuildをする場合

```yml
name: PreMerge Build

on:
  pull_request:
    branches:
      - main  # PRのターゲットブランチがmainの場合に動作する

jobs:
  pre-merge-build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '23'

      - name: Install dependencies
        run: cd frontend && npm install

      - name: Build the project
        run: cd frontend && npm run build
```
</details>

## Branch保護ルールの設定
上記の作成したワークフローだけではPull Requestのマージを自動的に防ぐことはできません。
ワークフローがエラーになった際にマージを禁止するためにはブランチ保護ルールを設定する必要があります。

1. リポジトリの「Settings」タブに移動します
1. 左側のメニューから「Branches」を選択します
1. 「Branch protection rules」セクションで「Add branch ruleset」をクリックします
1. 「Ruleset Name」に任意の名前を入力します
1. 「Enforcement status」をActiveにします
1. 「Branch targeting criteria」の「Add target」をクリックし「Include by pattern」からmain（または対象とするブランチ名）を指定します
1. 「Require status checks to pass before merging」にチェックを入れます
1. 下にある「Status checks that are required」の「Add checks」をクリックし、さきほどのワークフローの名前を入力して検索し、チェックする（答えの一例の場合: `pre-merge-build`）
1. オプションを保存します

これで指定したワークフローが完了しないとマージができないように制御されます。

ワークフローの待機中
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/5266c6d8-401d-4a02-85ca-1942125ede4f.png)

ワークフローが失敗した時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/18257b6d-59be-47ce-827d-ae48da742a3a.png)

ワークフローが成功した時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1126770/e32992ad-451b-485a-8536-c3ea00848bac.png)

# まとめ
このようにGitHubActionsを利用することで、繰り返し行う必要がある検証を自動で確実に行うことができます。
GitHubActionsをうまく利用して、CICDを確実に実行し、顧客に価値を届ける開発に集中できる環境を整えてみてください。

おわり。