趣味プロダクトにおけるGitHub Actionsの活用事例


この記事は ミクシィグループ Advent Calendar 2020 21日目の記事です。

趣味でhato-botというSlack botの開発に参加していますが、こちらのプロジェクトでGitHub Actionsをどう使っているかをいくつか紹介します。
なお、本記事内でのコードや名称は意図がわかりやすいよう一部簡略化・変更を加えていますが、実際のコードへのリンクも併記しています。

GitHub Actionsとは

GitHubが提供しているCI/CDになります。
個人的には以下のような利点があると感じています。

  • パブリックリポジトリであれば無料で利用できるので、趣味の開発やOSSでCI/CDを導入したいときに便利。
  • 事前の設定なしにGitHub APIを使えるため、PRにコメントする等のリポジトリに対する操作を伴うCI/CDを組みやすい。

活用事例

Dockerイメージをビルドできるかテストする

apk (Alpine Linuxのパッケージ管理システム) はデフォルトでは最新バージョンのパッケージしか対応していません。
そのため、パッケージがアップデートされると、インストール時に指定したバージョンとapkが対応しているバージョンの間にズレが生じ、パッケージのインストールに失敗します。
これが原因で、正常にビルドできていたDockerイメージがいつの間にかビルドできなくなる事態が起きていたので、それを検知しやすくなるよう、Dockerイメージをビルドできるか確かめるCIを作成しました。

CIのコード

github/workflows/pr-test.yml
name: pr-test

# PRで何らかのイベントが発生した際に発動する
on:
  pull_request:

jobs:
  pr-docker:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
     # インストール等のステップなしでdocker-composeが使える
      - name: Build docker image
        env:
          DOCKER_BUILDKIT: 1
          COMPOSE_DOCKER_CLI_BUILD: 1
        run: docker-compose build --no-cache

実際のコード

別リポジトリへ差分を反映する

メインのリポジトリ ( nanashi-san/main-repo とします) での差分を関連するリポジトリ ( nanashi-san/related-repo とします) に手動で反映するという作業が発生しており、それを以下のようなCIで自動化しました。

  • nanashi-san/main-repo 側CI: developにpushされた差分を関連するリポジトリの pr-copy ブランチへpushする
  • nanashi-san/related-repo 側CI: pr-copy ブランチがpushされたらPRを立てる

CIの作り方

  1. 秘密鍵と公開鍵のペアを生成する。
  2. 公開鍵を nanashi-san/related-repo のdeploy keysに設定する。
  3. 秘密鍵を nanashi-san/main-repo のsecretsに RELATED_REPO_PRIVATE_KEY という名前で設定する。
  4. nanashi-san/main-repo 側で以下のようなCIを組む。

    github/workflows/pr-copy.yml
    name: pr-copy
    
    # developにpushされたら発動する
    on:
        push:
            branches:
                - develop
    
    jobs:
        pr-copy:
            runs-on: ubuntu-latest
    
            steps:
                # nanashi-san/main-repo 取得
                - uses: actions/checkout@v2
                  with:
                    fetch-depth: 0
                    # 『作業ディレクトリ/main-repo』にmain-repoをcloneする
                    path: main-repo
                # nanashi-san/related-repo 取得
                - uses: actions/checkout@v2
                  with:
                    fetch-depth: 0
                    repository: nanashi-san/related-repo
                    # 『作業ディレクトリ/related-repo』にrelated-repoをcloneする
                    path: related-repo
                # nanashi-san/related-repo のファイルを nanashi-san/related-repo にコピー
                - name: Copy
                  run: |
                    cp main-repo/path/to/dir/file related-repo/path/to/dir/
                # nanashi-san/related-repo における差分を取得
                - name: Set diff
                  id: set_diff
                  run: |
                    cd related-repo
                    echo "::set-output name=diff::$(git diff)"
                # nanashi-san/related-repo で差分が生じている場合、それを nanashi-san/related-repo のpr-copyブランチにpushする
                - name: Push
                  if: steps.set_diff.outputs.diff != ''
                  run: |
                    cd related-repo
                    git config user.name "nanashi-san"
                    git config user.email "[email protected]"
                    git add -u
                    git commit -m "nanashi-san/main-repo の差分を反映"
    
                    # nanashi-san/related-repo の秘密鍵取得
                    echo "${{secrets.RELATED_REPO_PRIVATE_KEY}}" > deploy_key.pem
                    chmod 600 deploy_key.pem
    
                    # nanashi-san/related-repo にpush
                    GIT_SSH_COMMAND="ssh -i deploy_key.pem -o StrictHostKeyChecking=no -F /dev/null" git push -f "[email protected]:nanashi-san/related-repo.git" HEAD:refs/heads/pr-copy
    
  5. nanashi-san/related-repo 側で以下のようなCIを組む。

    github/workflows/pr-copy.yml
    name: pr-copy
    
    # pr-copy ブランチがpushされたら発動する
    on:
        push:
            branches:
                - pr-copy
    
    jobs:
        pr-copy:
            runs-on: ubuntu-latest
    
            steps:
                - name: Create PullRequest
                  # actions/github-scriptを使うと、octokit/rest.js ( https://octokit.github.io/rest.js/v18 ) 経由でGitHub APIを利用できる
                  # octokit/rest.jsを使用する際はドキュメントの『oktokit.~』を『github.~』と読み替える
                  uses: actions/github-script@v3
                  with:
                    # 自リポジトリのトークンは予めsecretsにセットされているので、それを以下のようにセットすると、自リポジトリに対する操作を行える
                    github-token: ${{secrets.GITHUB_TOKEN}}
                  script: |
                    const common_params = {
                        owner: context.repo.owner,
                        repo: context.repo.repo
                    }
                    const pull_params = {
                        head: "ref/head/pr-copy",
                        base: "master",
                        ...common_params
                    }
                    const pulls_list_params = {
                        state: "open",
                        ...pull_params
                    }
                    console.log("call pulls.list:")
                    console.log(pulls_list_params)
    
                    // pr-copy ブランチをheadとするPRの一覧を取得する
                    github.pulls.list(pulls_list_params).then(list_res => {
                        // 該当するPRがなければPRを作成する
                        // 既にPRが立てられている場合はpushした時点でPRに反映されるので何もしなくて良い
                        if (list_res.data.length === 0) {
                            const pulls_create_params = {
                                title: "nanashi-san/main-repo の差分を反映",
                                ...pull_params
                            }
                            console.log("call pulls.create:")
                            console.log(pulls_create_params)
                            github.pulls.create(pulls_create_params)
                        }
                    })
    

実際のコード

コードのフォーマットを直すPRを自動的に作成する

hato-botの開発に参加している @Goryudyuma さんによる記事があるので、こちらをご覧ください。
https://qiita.com/Goryudyuma/items/18b89b2c279a75d4b309