はじめに
勉強とアウトプットを兼ねて、Webアプリ開発の記録を記事にしてみます。
個人のメモ的な側面が強いです。
Web開発初心者すぎて至らぬところだらけだと思いますが、暖かい目で見ていただければ幸いです。
↓ これまでの内容 ↓
【Day0】アプリが完成するまで毎日投稿
【Day1】開発環境を考える
【Day2】開発環境を構築する、、、はずでした
【Day3】まずはフロントだけ開発環境を構築する
【Day4】バックエンドの開発環境を整えつつ、マルチコンテナ対応のDevcontainerにする
【Day5】お試し実装!ファイルをアップロードしてバックエンドで処理する
【Day6】Docker Desktopが起動しなくなり泣きながら原因調査する
【Day7】画像にフレームとExif情報を付けてみる
【Day8】フロントに表示する画像のサイズを小さくする
【Day9】フロントエンドとバックエンドをそれぞれデプロイする
【Day10】結局コンテナ1つで開発する方が楽かもしれない
【Day11】アプリが一通り完成!!
【Day12】FastAPIのコードをリファクタリングする
【Day13】機能実装!フレームに記載するExif情報を編集できるようにする(前編)
【Day14】ReactのリファクタリングとUI変更を同時にやった
【Day15】機能実装!フレームに記載するExif情報を編集できるようにする(後編)
【Day16】インスタ用のキャプションを生成する(前編)
【Day17】インスタ用のキャプションを生成する(中編)
【Day18】インスタ用のキャプションを生成する(後編)
【Day19】自動テストを実装する(全体の構想&APIユニットテスト編)
前回やったこと
今作っているWebアプリにはどんな種類のテストコードが必要なのかを検討して、PythonのFastAPIで作ったAPIのユニットテストを作成しました!
今回やったこと
前回作成したAPIユニットテストをPR作成時に自動で実行させる仕組みを作りました。
また、masterブランチにはdevelopブランチからしかPRを出せないようにする仕組みも併せて作りました。(理由は後述)
どちらもGitHub Actionsを用意しました。
現在のブランチ構成
そもそもなんですが、今は以下のようなブランチ構成で開発してます。
master // 確実に動く状態のソースを格納する
└ develop // developで全部の動作確認をしてからmasterにマージ
├ feature1 // 機能追加はdevelopからトピックブランチを切る
├ feature2
:
└ featureX
機能開発はdevelopをベースに行い、最終的に上手くいったらmasterにマージするような運用です。
APIユニットテスト
以下のymlを.github/workflowsに記載することでmasterブランチとdevelopブランチへのPR作成時にpytestを実行するGitHub Actionsを追加しました。
name: Run Pytest on PR
on:
pull_request:
branches:
- master
- develop
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout code
uses: actions/checkout@v3
- name: 🐍 Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: 📦 Install dependencies
working-directory: backend
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- name: 🧪 Run pytest
working-directory: backend
env:
PYTHONPATH: .
run: |
source venv/bin/activate
pytest
また、このユニットテストが成功しないとPRがマージできないような設定も作りました。
GitHubのSettings > BranchesからAdd ruleでBranch protection ruleを作りました。
Branch name patternにdevelopを入れて、Protect matching branchesにはRequire status checks to pass before mergingとRequire branches to be up to date before mergingにチェックを入れて、Status checkの対象に今回作成したユニットテストを追加しました。
Status checkの対象に作成したGitHub Actionsを表示させるためには一度実行する必要があります。
ダミーのブランチでPRを作って動作することを確認してから設定しましょう。
ブランチ保護
masterブランチを保護するために、masterブランチへのPRはdevelopブランチからしか出せないという制約を付けるGitHub Actionsを作成しました。
name: Restrict PR to master from develop only
on:
pull_request:
branches:
- master
jobs:
restrict_pr_source:
runs-on: ubuntu-latest
steps:
- name: Fail if PR is not from develop
run: |
echo "PR from ${{ github.head_ref }} to ${{ github.base_ref }}"
if [ "${{ github.head_ref }}" != "develop" ]; then
echo "❌ PR to master must come from develop branch only."
exit 1
fi
こちらも上記同様にBranch protection ruleを設定しました。
masterブランチを保護する理由
ブランチ構成を再掲しますが、基本的にmasterブランチはdevelopブランチからしかPRを出さない予定でした。
master // 確実に動く状態のソースを格納する
└ develop // developで全部の動作確認をしてからmasterにマージ
├ feature1 // 機能追加はdevelopからトピックブランチを切る
├ feature2
:
└ featureX
しかし、どこかのタイミングで間違えたのかfeatureブランチをそのままmasterブランチにマージしてしまい、そのまま気づかず開発を進めていたら、masterブランチとdevelopブランチに謎の差分が出てしまいました。
しかもmasterとdevelop間でPRを作っても差分がないことになるし、git diffでは差分があるけどgit logでコミットログを見てもどれが原因のコミットかわからず、何日も唸っていました。
masterにfeatureをマージするのは1回やったことがあり、そのときはrevertしたのですが、その後ももう一度気づかない間にやってしまったみたいです。
おわりに
今回はGitHub Actionsを使ってユニットテストの自動実行とブランチ保護設定を作成しました。
ヒューマンエラーを防ぐためにブランチ保護設定を作ったのですが、やはりこういったことはシステム的に解決していきたいですね。
今は個人開発ですが、今後もし複数人で開発することになったらこの辺りは絶対設定したいと思いました。
