Github Actionsってどんなことができるの？

:::note info
この記事は、社内勉強会の記録になります
:::

## はじめに
みなさま、Github ActionをはじめとしたCI/CDを活用しているでしょうか？
公式には、以下のような概要が記されています

> GitHub Actions は、ビルド、テスト、デプロイのパイプラインを自動化できる継続的インテグレーションと継続的デリバリー (CI/CD) のプラットフォームです。 リポジトリに対するすべての pull request をビルドしてテストしたり、マージされた pull request を運用環境にデプロイしたりするワークフローを作成できます。
> 
> GitHub Actions は、DevOps であるだけでなく、リポジトリで他のイベントが発生したときにワークフローを実行できます。 たとえば、リポジトリで新しい issue が作成されるたびに、適切なラベルを自動的に追加するワークフローを実行できます。
>
> GitHub では、ワークフローを実行するための Linux、Windows、macOS 仮想マシンが提供されます。また、自身のデータセンターまたはクラウド インフラストラクチャで独自のセルフホスト ランナーをホストすることもできます。

## 活用事例
以下はあくまで表面的な部分ですが、日本でも活用事例があります

#### Y株式会社
Y株式会社は、GitHub Actionsを利用して、スマートフォンアプリの開発プロセスを自動化しています。たとえば、ビルド、テスト、デプロイ、セキュリティチェック、メトリクスの収集などを自動化することで、品質の向上とリリースの高速化を実現しています。

#### 株式会社SM
株式会社SMは、GitHub Actionsを利用して、音楽配信サービスの開発プロセスを自動化しています。たとえば、ビルド、テスト、デプロイ、セキュリティチェック、メトリクスの収集などを自動化することで、品質の向上とリリースの高速化を実現しています。

#### 株式会社SJ
株式会社SJは、GitHub Actionsを利用して、店舗システムの開発プロセスを自動化しています。たとえば、ビルド、テスト、デプロイ、セキュリティチェック、メトリクスの収集などを自動化することで、品質の向上とリリースの高速化を実現しています。

#### 株式会社RH
株式会社RHは、GitHub Actionsを利用して、採用サイトの開発プロセスを自動化しています。たとえば、ビルド、テスト、デプロイ、セキュリティチェック、メトリクスの収集などを自動化することで、品質の向上とリリースの高速化を実現しています。

#### 株式会社ND
株式会社NDは、GitHub Actionsを利用して、さまざまなサービスの開発プロセスを自動化しています。たとえば、ビルド、テスト、デプロイ、セキュリティチェック、メトリクスの収集などを自動化することで、品質の向上とリリースの高速化を実現しています。

これらの事例は、日本企業でも、GitHub Actionsがさまざまなソフトウェア開発タスクの自動化に利用されていることを示しています。GitHub Actionsは、日本企業のソフトウェア開発の効率化と品質向上に大きく貢献するツールです。

具体的な活用例としては、以下のようなものが挙げられます。

- ビルド、テスト、デプロイなどの自動化による開発プロセスの効率化
- セキュリティチェック、コンプライアンスチェックなどの自動化による品質向上
- メトリクスの収集によるパフォーマンスや機能の改善
- リリースノートの自動作成によるコミュニケーションの円滑化
- リポジトリの監視によるセキュリティの強化

## サンプル

早速ですが、どう言うものか知るためにサンプルを見てみましょう。

### mainにマージされたらリリースノートを作成するワークフロー
```yaml: create-release-note.yaml
name: リリースノート生成

on:
  push:
    branches:
      - main

jobs:
  generate-release-notes:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Generate release notes
        run: |
          echo "リリースノート" > release-notes.md
          echo "変更点" >> release-notes.md
          echo "${GITHUB_REF##v}" >> release-notes.md
          echo "その他" >> release-notes.md
          echo "- 本リリースで修正されたIssues" >> release-notes.md
          echo "${jq -c '.[] | .issue_url' $GITHUB_EVENT_PATH | sort}" >> release-notes.md

      - name: Create release
        uses: actions/create-release@v1
        with:
          tag_name: v${GITHUB_REF##v}
          release_name: リリース ${GITHUB_REF##v}
          body: |
            リリースノート

            ${cat release-notes.md}
```

### Flutter WebをFirebase Hostingに商用デプロイするワークフロー

```yaml: production-workflow.yaml
name: 商用ワークフロー

on:
  push:
    branches:
      - main # mainブランチにプッシュされたら実行される

jobs: # 各セクションを構成していく
  build: # buildセクション
    runs-on: ubuntu-latest # 実行環境（ランナー）の指定
    steps:
      - uses: actions/checkout@v2 # Actionsで使うツール
      - name: Flutterインストール
        uses: subosito/flutter-action@v1
        with:
          channel: stable # バージョン固定が好ましい
      - name: パッケージインストール
        run: flutter pub get # 実行するコマンドを記載
      - name: テストの実行
        run: flutter test
      - name: 静的解析（analyze）
        run: flutter analyze
      - name: コード整形
        run: flutter format --set-exit-code
  deploy: # デプロイセクション
    needs: build
    runs-on: ubuntu-latest
    steps: # 上から実行される
      - uses: actions/checkout@v2
      - name: Firebase CLIのインストール
        run: npm install -g firebase-tools
      - name: Firebase ログイン
        run: firebase login
      - name: Firebase 初期化
        run: firebase init --only hosting
      - name: Firebase デプロイ
        run: firebase deploy --only hosting
```

## 各セクションでできること
### トリガー
CICDといえば、様々なトリガーを設定できることも魅力のうちの一つかと思います。
Githubでは以下のリンクにトリガー一覧が設定されています

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#issues

代表的なトリガーを見てみましょう

#### issues
トリガー：issueが開かれた、編集された、またはマイルストーンが設定されたとき
```yaml
on:
  issues:
    types: [opened, edited, milestoned]
```
#### label

トリガー：ラベルが作成または削除されたとき
```yaml
on:
  label:
    types: [created, deleted]
```

#### merge_group

トリガー：checks_requested イベントが発生したとき
```yaml
on:
  merge_group:
    types: [checks_requested]
```

#### milestone

トリガー：マイルストーンが開かれた、または削除されたとき
```yaml
on:
  milestone:
    types: [opened, deleted]
```

#### project

トリガー：プロジェクトが作成または削除されたとき
```yaml
on:
  project:
    types: [created, deleted]
```

これらのイベントを使用することで、特定のアクションやアクティビティがリポジトリで発生したときにGitHub Actionsのワークフローを自動的に実行することができます。

### ジョブの選択

実際に実行していくコマンドや設定については、それぞれ`job`で設定していきます

https://docs.github.com/ja/actions/using-jobs/using-jobs-in-a-workflow


```Yaml
jobs:
  my_first_job:
    name: My first job
  my_second_job:
    name: My second job
```

#### 前提条件の設定
ワークフローの中では、job1が成功していないのにjob2が実行されたら困る場合がありますね。
その場合、`needs`を設定することでそのジョブの成功（正常終了）を持って実行することができます

```yaml
jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]
```

#### コンテナの定義
ワークフローの実行環境として、以下のようにコンテナの設定も可能です

https://docs.github.com/ja/actions/using-jobs/running-jobs-in-a-container

```Yaml
name: CI
on:
  push:
    branches: [ main ]
jobs:
  container-test-job:
    runs-on: ubuntu-latest
    container:
      image: node:14.16
      env:
        NODE_ENV: development
      ports:
        - 80
      volumes:
        - my_docker_volume:/volume_mount
      options: --cpus 1
    steps:
      - name: Check for dockerenv file
        run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)
```

### シークレットキーの格納

時には、実行する際にAPIキーを使いたいがGitにはあげたくないものもあると思います。
その場合、シークレットキーをGithubで設定することで安全にAPIキーの利用をすることが可能です

https://docs.github.com/ja/actions/security-guides/encrypted-secrets

## 総合ガイド

Github Actionの公式を見たい場合は、こちらのガイドを参照していただければいいかなと思います。

https://docs.github.com/ja/actions/guides


## Github Marketplace

ワークフローの中で、以下のような記述があったと思います
```yaml
uses: actions/checkout@v2
```

この`actions/checkout@v2`がどこにあるものを指しているかというと、Github Marketplaceに展開されているものを指定することができます。

https://github.com/marketplace?category=api-management&query=sort%3Apopularity-desc&type=actions&verification=

### MArketplaceのサンプル

https://github.com/marketplace/actions/github-script

https://github.com/marketplace/actions/fetch-api-data

https://github.com/marketplace/actions/fetch-api-data

## その他CIで使えるもの

Git（Githubではない）にはhooksという機能があります。
hooksは、gitのpush, commitなどのトリガーをもとにある程度のワークフローを実行することができます。
Github Actionsを走らせるようにすると、どうしてもIDEを離れて待機しなくてはならないため、簡易的なチェックはローカルでしたいですね。

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

たとえば、コミット前にチェックしたい場合は、リポジトリの直下に
`.git/hooks/pre-commit`というファイルを作成してください。
以下がサンプルです。

サンプルの例として、mainブランチへの直コミットを抑止するスクリプトを記載します

```:pre-commit
#!/bin/sh

# コミットしようとしているブランチを取得する
branch=$(git rev-parse --abbrev-ref HEAD)

# mainブランチにコミットしようとしているかチェックする
if [ "$branch" == "main" ]; then
  # アラートを表示する
  echo "mainブランチへのコミットは禁止されています。"

  # コミットを抑止する
  exit 1
fi
```

gitの性質上、一度コミット・プッシュをしてしまうと後戻りが面倒です。
そのため、このように事前抑止するもいいですね。
次に、`.git/hooks/pre-push`というファイルを作成してみます。

#### Java - Spring

```:pre-push
#!/bin/sh

# 静的解析を実行する
mvn clean compile -P static-analysis

# ユニットテストを実行する
mvn test

# 統合テストを実行する
mvn verify
```

#### PHP - Laravel
```:pre-push
#!/bin/sh

# 静的解析を実行する
php artisan ide-helper:generate

# コードの整形を実行する
php artisan code:fix

# 単体テストを実行する
php artisan test

# 統合テストを実行する
php artisan test --group=integration
```

#### JavaScript - React
```:pre-push
#!/bin/sh

# 静的解析を実行する
eslint --ext .js,.tsx --fix .

# コードの整形を実行する
npm run format

# 単体テストを実行する
npm test
```

上記はサンプルとして`pre-push`で実行してますが、pushで失敗しても...と思う方は`pre-commit`で仕込んでもいいですね！
ただ、コミットの度解析が走るのも面倒な気もするのでバランスが大切ですね。