[Python] 本番・試験・製品 設定ファイルでコード変更なしに環境を切り替える方法 (discord.pyを使ったbotの例)

この記事の内容

Python、discord.pyを使ってdiscordのbotを開発しています。
このbotはすでにユーザに使っていただいているので、開発者(=筆者)の都合でたびたび止めることはできません。
そこで、以下のように複数の環境を用意し、開発作業を行っています。

バージョン 用途 提供先(ユーザ)
開発版 開発中に動かす。カンタンな動作確認をする 筆者のみ
試験版 実際と同じように運用し、全試験を実施する 筆者と限られた友人
製品版 実際にユーザに提供する 不特定多数

これらをどのように切り替えているのか、筆者のケースを紹介します。

ディレクトリ構造

以下のような構成になっています。各フォルダそれぞれのファイル構成は同じです。

Develop/ # 開発版
  ├── .git/
  ├── config.py #1 
  ├── init.py #2
  ├── .gitignore #3
  ├── config.py.sample #4
  └── ...
Testing/ # 試験版
  └── ... # Developと同じ
Product/ # 製品版
  └── ... # Developと同じ

#1 config.py

それぞれのディレクトリにconfig.pyというファイルを配置します。
これが環境切り替えのキモとなるファイルです。
それぞれの環境用に個別のconfig.pyを作成することで、全環境で共通のソースコード本体を使いながら、パラメータを環境ごとに切り替えることができます。
内容の設定例を以下に示します。

Testing/config.py

# これは試験版の設定例です。
DISCORD_TOKEN = "test_discord_token.XXXXXXXXXXXXXXXXXXX"
DB_USER = "test_user"
DB_PASSWORD = "test_user_password"
DB_NAME = "test_db"
DB_HOST = "localhost"
DB_PORT = 12345
IS_DEBUG = True

Product/config.py

# これは製品版の設定例です。
DISCORD_TOKEN = "product_discord_token.XXXXXXXXXXXXXXXXXXX"
DB_USER = "product_user"
DB_PASSWORD = "product_user_password"
DB_NAME = "product_db"
DB_HOST = "sample.com"
DB_PORT = 54321
IS_DEBUG = False

discord botを作る場合の補足

開発用・試験用・製品用に、合計3つのApplicationを作成しましょう。
Bot userを作成し、config.pyのDISCORD_TOKENにそれぞれのBotのトークンを記入します。

#2 Testing/init.py, Product/init.py(同じ内容)

以下のようなinit.pyを記述し、前項のようにconfig.pyを配置することで、ソースは共通でありながら、開発版のみで"This is debug mode app!"の文言が出力されます。
これは単純な例ですが、データベースの接続先やユーザ名・パスワードなども同一の方法でパラメータ化できます。

import config
if config.IS_DEBUG:
    print("This is debug mode app!")

#3 .gitignore

config.pyには、環境によって切り替えるパラメータや、トークンやデータベースパスワードなどの非公開にすべき文字列が含まれます。
これらはバージョン管理ツールのリポジトリに登録すべきでない情報です。
そのため、.gitignoreファイルにconfig.pyを記入しておきます。

しかし、このままでは、config.pyというファイルが必要であることや、どのように書けばいいかの情報がリポジトリに登録されません。
そこで、config.py.sampleを用意します。

#4 config.py.sample

config.pyのテンプレートとなるファイルです。これをリポジトリに登録しておくことで、ファイルの項目を管理することが可能となります。
項目の追加・削除があった場合、コードの変更にあわせて、config.pyの項目の変更も同時に履歴に残るので安心ですね。

DISCORD_TOKEN = "discord_bot_token"
DB_USER = "username"
DB_PASSWORD = "password"
DB_NAME = "table_name"
DB_HOST = "db_bost"
DB_PORT = 00000
IS_DEBUG = False

運用方法

開発、試験、運用を行う手順を紹介します。

ポイントは以下です。

  • コードは、主にDevelop/ディレクトリで編集する。
  • 各フォルダ間のソースコードは、リモートリポジトリを介して同期する。
  • Product/ディレクトリでは、直接ファイル操作を行わない。
    • git pullのみ。ブランチ切り替えもしない。

branchやmergeをしたくない場合、とりあえずすべてmasterブランチで実施してもいいかと思います。

開発

Develop/ディレクトリで開発作業を行う。

---> 開発作業
$ git branch add_beautiful_method
$ git checkout add_beautiful_method
$ vim init.py ...
---> ざっくり動作確認など
$ python3.6 init.py
---> リモートリポジトリにpush
$ git add .
$ git commit -m "[update] add beautiful method"
$ git push origin add_beautiful_method

試験

Testing/フォルダにて変更を取り込み、試験を実施します。
必要があればコードを修正します。
試験に通ったら、masterブランチにマージして、リモートリポジトリにpushしましょう。

---> リモートリポジトリからソース取り込み
$ git fetch 
$ git checkout -b add_beautiful_method remote/add_beautiful_method
---> 動作確認(試験)
$ python3.6 init.py
---> 誤りがある場合、修正
$ vim init.py
$ git add .
$ git commit -m "[fix] fix too beautiful"
$ git push origin add_beautiful_method
---> 再試験
$ python3.6 init.py
---> 合格の場合、masterにマージしてpush。またはプルリクエストによるマージ(お好みで)
$ git checkout master
$ git merge --no-ff add_beautiful_method
$ git push origin master

実運用

Product/フォルダに変更を取り込み

---> 実行中のpythonプロセスを停止
$ ./stop.sh
---> リモートリポジトリからソース取り込み
$ git pull origin master
---> 実行
$ python3.6 init.py

おまけ:リポジトリ

GitHub Privateリポジトリ

2019年2月現在、GitHubでは一般ユーザもプライベートリポジトリを扱うことができます。
筆者のプロジェクトではこれを利用し、タスク管理もGitHubで行っています。
hubコマンドと組み合わせるとissue管理がとても便利なので重宝しています。
(参考)[Github] hubを導入してissueをコマンドラインから操作する