CircleCI
テストの準備ができたので、次はこのテストを継続的インテグレーション(CI)に組み込んでみましょう。テストを自動化することで、意図していないバグを早期に発見できる可能性が高まります。
本連載ではCIサービスとして、CircleCIを利用します。CircleCI 1.0では、2種類の仮想マシンから実行環境を選ぶしくみになっていましたが、2.0からは任意のDockerイメージを指定できるようになりました。このおかげで、設定の柔軟性が増し処理の高速化にもつながりました。
1コンテナまでは無料で使用できるので、業務だけでなく個人利用でも人気のあるCIサービスです。
CircleCIの設定
それではCircleCIを使い始めるための設定を行います。CircleCIの説明に従って、以下の流れで進めていきましょう。
- https://circleci.com/signup/からサインアップ
- ダッシュボード左サイドバー「ADD PROJECTS」から、CircleCIと連携したいリポジトリを選択
- OSと開発言語を選択をして、設定ファイルのひな型を取得
-
リポジトリルートの
.circleci/config.ymlに設定ファイルを配置
OSにLinux、開発言語にPythonを選択すると、以下のようなひな型を取得できます。
# Python CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-python/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
# use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers`
- image: circleci/python:3.6.1
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/postgres:9.4
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "requirements.txt" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install -r requirements.txt
- save_cache:
paths:
- ./venv
key: v1-dependencies-{{ checksum "requirements.txt" }}
# run tests!
# this example uses Django's built-in test-runner
# other common Python testing frameworks include pytest and nose
# https://pytest.org
# https://nose.readthedocs.io
- run:
name: run tests
command: |
. venv/bin/activate
python manage.py test
- store_artifacts:
path: test-reports
destination: test-reports
この設定ファイルで使われている設定項目について、いくつか紹介します。
- version: CircleCIのバージョンを指定
-
jobs: 実行単位である
jobを束ねるセクション -
build: リポジトリへのPushがトリガーとなって実行されるデフォルトの
job -
docker:
stepsを実行するDocker環境を指定 -
working_directory:
stepsを実行するディレクトリ - steps: ビルドステップを束ねるセクション
-
checkout:
working_directoryにソースコードをチェックアウト - run: 実行するコマンドを指定
-
restore_cache:
keyをもとにキャッシュを取得 -
save_cache:
keyを指定してキャッシュを保存 -
store_artifacts: カバレッジレポートやバイナリなど
jobの成果物を保存
設定ファイルに関してより詳しく知りたい方は、公式ドキュメントConfiguring CircleCIを参照してください。
それではこのひな型をもとに、先ほど実装したテストを実行するために以下のように編集しましょう。
version: 2
jobs:
build:
docker:
- image: circleci/python:3.6
working_directory: ~/repo
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "requirements/base.txt" }}-{{ checksum "requirements/test.txt" }}
- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install -r requirements/test.txt
- save_cache:
paths:
- ./venv
key: v1-dependencies-{{ checksum "requirements/base.txt" }}-{{ checksum "requirements/test.txt" }}
- run:
name: run migrate
command: |
. venv/bin/activate
python manage.py migrate
- run:
name: run tests
command: |
. venv/bin/activate
python -Wd manage.py test
主な変更は以下の3つです。
-
キャッシュのkeyに、
requirements/base.txtとrequirements/test.txtのチェックサム値を記述 - migrationを実行するためのstepを追加
-
python manage.py testに、前回紹介した-Wdオプションを追加
あとはリポジトリにPushして、CircleCIのプロジェクト設定画面で「Start building」ボタンをクリックすれば、ビルドが実行できます。
しかし現状のコードだと、ModuleNotFoundError: No module named 'django_extensions'というエラーが発生してビルドが失敗してしまいます。
これはrequirements/local.txtのrequirementsを、CI環境でインストールしていないために起きているエラーです。しかしローカルでの開発だけで使用するrequirementsに各環境が依存するのは避けたいので、settingsについて見直しましょう。
問題となっているのはmanage.pyの6行目os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")というコードで、ここでローカル用のsettingsがDJANGO_SETTINGS_MODULEにセットされています。普段の開発では問題ないのですが、CI環境ではローカル用の設定が含まれていないconfig.settings.baseを使うようにしましょう。
manage.pyコマンドに--settingsオプションを付与することで、settingsの参照先を自由に変更できます。.circleci/config.ymlの最後の部分を以下のように編集します。
- run:
name: run migrate
command: |
. venv/bin/activate
python manage.py migrate --settings=config.settings.base
- run:
name: run tests
command: |
. venv/bin/activate
python -Wd manage.py test --settings=config.settings.base
この変更をPushして再度ビルドが実行されると、無事成功することが確認できました。
今回は便宜上--settingsオプションで解決しましたが、次回の連載では環境変数を用いた設定ファイルの管理方法を紹介する予定です。
ここまで解説したソースコードは以下から見ることができます。
