この記事はfreee Developers Advent Calendar 2021 15日目の記事です。
中部支社のチームのエンジニアの okoshi です。
みなさんいかがお過ごしですか。めっきり寒くなってまいりましたね。外部イベントでLTするときは下手うまな絵をスライドに差し込むのが好きなんですが、最近LTに出てないので所属しているチームのメンバーを絵にしてみました。
いつ書いても惚れ惚れする絵のタッチ。
それはさておき
今回は中部支社のエンジニアが裁量を以て仕事をしていることの一例としてGitHub Actionsで日々の開発運用を楽にしている取り組みを紹介します。
この記事に辿り着いていただいた方はGitHub Actionsに関する記事を期待している方も多いと思うので後半ではどういった設定をしたかも紹介します。
そして、こちらで紹介する内容はチームのメンバー全員で取り組んだものなので、尽力いただいた方々に心から敬意と感謝の意を表します。
中部支社は独立したGitHubリポジトリーを運用している
freeeでは本社に限らず支社でも開発を行っています。もちろん独立した機能の開発を担当させてもらっていて、我々のチームではGitHubで独立したリポジトリをもっています。
エンジニアが触るリポジトリなので、当然プログラムが格納されています。そうなると、当然のごとくCIをしたくなるわけです。
そこでGitHub Actionsですよ。
GitHub Actionsを選んだのは必然的だった
CIツールにはCircleCIだとかTravisCIだとか他にも使えるツールはありますが、我々はGitHub Actionsを選びました。
我々の開発のミッションの一つに、すばやい開発の実現をかかげています。 そのため、調達に時間がかかるものはできるだけ排除したいと考えており、CircleCIやTravisCIはそもそも検討することなく手元ですぐに使えるツールとしてGitHub Actionsを選択しました。
選ぶにあったっては学習コストも意識しましたが、以下の二点から問題ないと考えました。
- 社内に知見が多くあった安心感
- メンバーが知見を持っていた
例えば私、過去にGitHub Actionsに関する記事をQiitaに書いていたりして、実はGitHub Actionsが好きだったりします。
GitHub Actions+Firebase App DistributionでiOSアプリをAd hoc配布するための構成例 - Qiita
Firebase hosting preview channels
ワークフローが解決した課題
我々は日々、テストを行っています。静的コードチェックも行っています。しかし、これらを手で行うのは面倒です。 今時それらをCIで実現するのは当たり前だと思いますが、それらもGitHub Actionsで実現しています。
加えて、DependabotによるOSSのバージョンアップ通知のプルリクエスト対応があります。OSSのバージョンアップには大規模な修正もあれば小さな修正もあります。 新しいバージョンがあれば適用したいと思ってはいるものの、大きな修正が加わっている場合は破壊的変更が加わっている可能性があるので慎重にバージョンアップをしなければなりません。しかし我々の使っているOSSは毎日のように軽微な修正が入り、Dependabotからのプルリクエストが発生し適用しなければならないのはかなりの手間です。 そこで、パッチバージョンが上がっただけのプルリクエストは自動でマージしてしまうことにしました。
改めて、GitHub Actionsで実現していることは以下になります。
- 単体・結合テスト
- 静的コードチェック
- E2Eテスト
- Dependabotの作成するPRの自動マージ
我々が扱っているリポジトリーはフロントエンドに特化しています。
GitHub Actionsはプルリクエストの作成や更新に対して反応するように設定してあります。
ワークフローのジョブは以下のように動かしています。
それぞれのジョブがやっていることは後述しますが、ちょっと複雑に見えるかもしれませんがこのワークフローは、日々の開発運用で作られるプルリクエストとDependabotが作るプルリクエストのどちらにも反応するようになっています。
人が作るプルリクエストには、tests、E2E、dangerが反応し、Dependabotが作るプルリクエストには、tests、E2E、dependabotが反応します。dependabotはtestsとE2Eが成功した場合にのみ動作します。
ワークフローの設定ファイル
せっかくこの記事に辿り着いていただいたので、どういった設定をワークフローのyamlファイルに書いたかを可能な範囲で公開します。 一部にはなりますが、十分に参考になると思います。
prepare
yarn install
をした結果をキャッシュしています。キャッシュは後続のジョブと、次回のワークフローの実行に使用します。
prepare: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: $NODE_VERSION - name: Install Yarn run: npm install -g yarn@$YARN_VERSION - name: Cache node_modules id: node_modules_cache_id uses: actions/cache@v2 with: path: | node_modules src/*/node_modules /home/runner/.cache/Cypress key: node-v$NODE_VERSION-v1-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} - name: Install npm modules run: yarn install if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
tests
単体・結合テストとLintを使った静的コードチェックを行います。
tests: runs-on: ubuntu-latest needs: - prepare steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: $NODE_VERSION - name: Cache node_modules id: node_modules_cache_id uses: actions/cache@v2 with: path: | node_modules src/*/node_modules /home/runner/.cache/Cypress key: node-v$NODE_VERSION-v1-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} - name: eslint run: yarn lint - name: Test run: yarn test
E2E
Cypressを使ったE2Eテストを行います。
yarn start
ではアプリが実行されるようになっています。
E2E: runs-on: ubuntu-latest needs: - prepare steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: $NODE_VERSION - name: Cache node_modules id: node_modules_cache_id uses: actions/cache@v2 with: path: | node_modules src/*/node_modules /home/runner/.cache/Cypress key: node-v$NODE_VERSION-v1-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} - uses: cypress-io/github-action@v2 with: working-directory: src/foo start: yarn start wait-on: 'http://localhost:3000' headless: true install: false
dependabot
Dependabotの作成するPRのうちパッチバージョンが上がっただけのものだけマージを行います。
我々の管理しているリポジトリのプルリクエストでは、レビューアがApproveしないとマージできないようになっています。
ジョブの定義にgh pr merge --auto --merge
があるのは、Approveしたときに自動でマージするようにするためです。
dependabot: runs-on: ubuntu-latest needs: - tests - E2E if: ${{ github.actor == 'dependabot[bot]' && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }} steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v1.1.1 with: github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Enable auto-merge for Dependabot PRs if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }} run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - uses: actions/checkout@v2 - name: Approve for Dependabot PRs if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }} run: gh pr review $NUMBER --approve env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} NUMBER: ${{ github.event.number }}
danger
Dangerを使った静的コードチェックを行います。 Dependabotの作ったプルリクエストには不要と考えて、Dependabotが作成したプルリクエストに対しては実行しません。
uses: danger/danger-js@x.x.x
を使うこともできますが、こちらはDockerコンテナのビルドを行うため多少時間がかかります。せっかくyarn install
済みのキャッシュがあるのでyarn danger ci
を実行しています。
danger: runs-on: ubuntu-latest needs: - prepare if: ${{ github.actor != 'dependabot[bot]' }} steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: $NODE_VERSION - name: Cache node_modules id: node_modules_cache_id uses: actions/cache@v2 with: path: | node_modules src/*/node_modules /home/runner/.cache/Cypress key: node-v$NODE_VERSION-v1-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} - name: Run danger run: yarn danger ci env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
まとめ
今回は裁量を持って開発環境が作れているということの一例を紹介させていただきました。この他にも中部支社では、社内初のアーキテクチャの採用するといったことも行っており、支社にも高いスキルとモチベーションを持ったメンバーがいます。
freeeは中部支社でも本社に劣らない仕事ができます。面白い開発が待っています。是非freeeの中部支社も視野にいれて転職や就職を検討してください。待ってます!
明日のAdvent Calendarは、Tak H. さんです!お楽しみに!