今回は Python を使って、Redmine CLI (コマンドラインインターフェイス) ツールを作ってみたい と思います。
以下のリポジトリに設置したサンプルコードを使って、解説を進めていきたいと思います。
CLI のベースには Click パッケージを、Redmine API へのアクセスには Python-Redmine パッケージを使用します。
目次
- 目次
- 必要な環境
- 簡単な流れ
- サンプルコードの取得
- サンプルコードの解説
- 実際に、サンプル Redmine CLI ツールを試してみる!
- 後始末
- 注意書き
- まとめ
必要な環境
本記事の内容をトレースする場合は、「 Docker 」 と 「 Docker Compose 」 が必要になります。
Redmine 環境や、Python 環境は サンプルコード中の docker-compose.yml
を使ってセットアップするので、インストールする必要はありません。
簡単な流れ
本記事では、以下のような流れで解説を進めていきます。
- サンプルコードを取得
- サンプルコードの中身を簡単に解説
- 実際に、サンプル Redmine CLI ツールを使ってみる
- まとめ
それでは、早速、Python を使って、Redmine CLI ツールを作っていきたいと思います!
サンプルコードの取得
サンプルコードを以下のリポジトリに設置しています。
以下のコマンドで、サンプルコードをクローンしてください。
git clone https://github.com/mm0202/template_python-redmine-cli.git
※ サンプルコードはテンプレートリポジトリとして公開しています。テンプレートとしても使用可能です。自由に使ってください。
サンプルコードの解説
サンプルコードの主な構成ファイルは以下の5つです。
.env.template
Dockerfile
docker-compose.yml
app/setup.py
app/packages/redmine.py
.env.template
必要な環境変数をまとめてあります。
.env.template
の中身は以下の通り
# For redmine-cli(python) container API_ACCESS_KEY=[APIアクセスキー] REDMINE_API=redmine:3000 # For redmine container REDMINE_DB_MYSQL=db REDMINE_DB_PASSWORD=example REDMINE_SECRET_KEY_BASE=supersecretkey # For db container MYSQL_ROOT_PASSWORD=example MYSQL_DATABASE=redmine
ファイル名を .env
に変更するか、コピーして名前を変更してください。
[APIアクセスキー]
の部分は、後ほど、Redmine からアクセスキーを取得して置き換えます。
Dockerfile
redmine-cli コンテナ用のビルドファイル です。
FROM python:3 WORKDIR /usr/src/app # 使用するパッケージをインストール RUN pip install click python-redmine # ソースコードのインストール (作成コマンドを有効化) COPY src /usr/src/app RUN pip install --editable . # 自動補完を有効化 RUN echo 'eval "$(_REDMINE_COMPLETE=source_bash redmine)"' >> ~/.bashrc CMD [ "bash" ]
基本設定
python
イメージをベースにしています。
WORKDIR
には /usr/src/app
を指定しています。
後述の docker-compose.yml
で、この WORKDIR
にソースコードをマウントします。
redmine-cli コンテナ内のプロジェクトルートは /usr/src/app
になります。
パッケージのインストール
Click パッケージと Python-Redmine パッケージを使用するため、pip install click python-redmine
でインストールしています。
ソースコードをインストール
以下の部分で、作成したソースコードをインストール しています。
COPY src /usr/src/app
RUN pip install --editable .
ソースコードのインストールにより、作成コマンドが使用可能となります。
--editable
オプションを使用しているので、ソースを変更するとビルドなしで変更が適用されます。
コマンドの自動補完を有効化
echo 'eval "$(_REDMINE_COMPLETE=source_bash redmine)"' >> ~/.bashrc
の部分で、コマンドに自動補完機能を追加 しています。
自動補完の設定についての詳細は、以下のページを参照してください。
Activation | Shell Completion | Click Documentation
docker-compose.yml
トライアル用に使用するコンテナの、起動設定です。
作成したコマンドを試すための redmine-cli コンテナと、redmine コンテナ、Redmine 用の db コンテナを起動 します。
version: "3" services: redmine-cli: build: . env_file: - .env volumes: - ./app/packages:/usr/src/app/packages redmine: image: redmine restart: always ports: - 53000:3000 env_file: - .env db: image: mariadb restart: always command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci env_file: - .env
構成は以下のような感じになります。
redmine-cli コンテナは、先ほどの Dockerfile をビルドして使用 します。
すでに Dockerfile で、作成コードをインストールのために、イメージ内にソースコードをコピーしていますが、app/packages
ディレクトリをコンテナ側の /usr/src/app/packages
にマウント してイメージ内のコードを上書きしています。
これにより、コードの変更がリアルタイムに適用されます。
※ 開発時の利便性用の設定なので、本番環境ではやめた方がいいと思います(>ω<;)
各コンテナの env_file
で指定している .env
は、.env.template
を元に作成します。
コンテナを起動した後、Redmine コンテナには http://localhost:53000 からアクセスできるようになります。
※ ホストが localhost 以外の場合は、「 localhost 」の部分を変更してアクセスしてください。
app/setup.py
パッケージのセットアップ設定ファイルです。
setup.py
の中身は以下の通り。
from setuptools import setup, find_packages setup( name='redmine', version='0.0.1', packages=find_packages(), include_package_data=True, install_requires=[ 'Click', ], entry_points=''' [console_scripts] redmine=packages.redmine:cli ''', )
entry_ponts
の redmine=packages.redmine:cli
の部分がコマンドの設定部分 です。
=
の左側の redmine
がコマンド名 になります。
=
の右側の packages.redmine:cli
がコマンドのパス指定 になります。
上記の設定の場合は、コマンド redmine
を実行すると、setup.py
のあるディレクトリからの相対パスで packages/redmine.py
の cli
関数が実行されます。
setup.py
の設定のより詳細な内容は、以下のページを参考にしてください。
app/packages/redmine.py
コマンドの実装ファイルです。
redmine.py
の中身は以下の通りです。
import click import os from redminelib import Redmine # リクエスト設定 redmine = Redmine('http://' + os.environ.get('REDMINE_API'), key=os.environ.get('API_ACCESS_KEY')) # プロジェクトの作成コマンド @click.command(help="create project") @click.option('--indentifier', '-i', help=u'project identifier', required=True) @click.option('--production', '-p', is_flag=True, help=u'add production project') @click.option('--prototype', '-pt', is_flag=True, help=u'add prototype project') @click.option('--sandbox', '-sb', is_flag=True, help=u'add sandbox project') def create(indentifier, production, prototype, sandbox): if production: redmine.project.create(name=indentifier, identifier=indentifier) print('production project created') if prototype: redmine.project.create( name=indentifier + '-prototype', identifier=indentifier + '-prototype') print('prototype project created') if sandbox: redmine.project.create( name=indentifier + '-sandbox', identifier=indentifier + '-sandbox') print('sandbox project created') # プロジェクトのリスト表示コマンド @click.command(help="list projects") def list(): projects = redmine.project.all() for project in projects: print(project.identifier) # プロジェクトの削除コマンド @click.command(help="delete project") @click.option('--indentifier', '-i', help=u'project identifier', required=True) @click.option('--production', '-p', is_flag=True, help=u'delete production project') @click.option('--prototype', '-pt', is_flag=True, help=u'delete prototype project') @click.option('--sandbox', '-sb', is_flag=True, help=u'delete sandbox project') def delete(indentifier, production, prototype, sandbox): if production: redmine.project.get(indentifier).delete() print('production project deleted') if prototype: redmine.project.get(indentifier + '-prototype').delete() print('prototype project deleted') if sandbox: redmine.project.get(indentifier + '-sandbox').delete() print('sandbox project deleted') # コマンド構成 @click.group(help="command for project") def project(): pass project.add_command(create) project.add_command(list) project.add_command(delete) @click.group(help="command for redmine") def cli(): pass cli.add_command(project) if __name__ == "__main__": cli()
コードの内容は大きくわけて、以下の3つです。
- API リクエストに必要な情報を設定 ( Redmine パス、認証 )
- プロジェクト操作コマンド群を定義 ( create、list、delete、delete-all )
- コマンドの構成
API リクエストに必要な情報を設定 ( Redmine パス、認証 )
以下の部分で、Redmine API の使用に必要なの API の URL とAPIアクセスキーを設定しています
redmine = Redmine('http://' + os.environ.get('REDMINE_API'), key=os.environ.get('API_ACCESS_KEY'))
ここで使用している 環境変数 REDMINE_API
と API_ACCESS_KEY
には .env
ファイルで指定した REDMINE_API
と API_ACCESS_KEY
の値を使用されます。
プロジェクト操作コマンド群を定義 ( create、list、delete、delete-all )
プロジェクト作成コマンド : create
以下の部分で、コマンドのオプションを設定しています。
@click.command() @click.option('--indentifier', '-i', help=u'project identifier', required=True) @click.option('--production', '-p', is_flag=True, help=u'add production project') @click.option('--prototype', '-pt', is_flag=True, help=u'add prototype project') @click.option('--sandbox', '-sb', is_flag=True, help=u'add sandbox project')
identifier
オプションでは、作成するプロジェクトの「 識別子 」を指定します。
identifier
オプションは、指定必須に設定しています。
production
、prototype
、sandbox
オプションでは、それぞれ追加するプロジェクトのタイプを指定しています。
例えば、オプションを -i apple -p -pt -sb
のように指定してプロジェクト作成コマンドを実行した場合、以下の3つのプロジェクトが作成されます。
- apple
- apple-prototype
- apple-sandbox
プロジェクト作成関数では、各プロジェクトのタイプごとにプロジェクトを作成しています。
例えば、prototype
フラグが True
の場合は、以下のコードが実行され、プロジェクト名と識別子が「 xxx-prototype 」のような文字列のプロジェクトが作成されます。
redmine.project.create( name=indentifier + '-prototype', identifier=indentifier + '-prototype')
プロジェクトのリスト表示コマンド : list
プロジェクトを全て表示するコマンドです。
プロジェクトの識別子がリスト表示されます。
他のコマンドの実行結果の確認に使用します。
プロジェクト削除コマンド : delete
プロジェクトの個別削除コマンドです。
オプションは create
コマンドと同様で、削除対象は identifier
とプロジェクトタイプごとのフラグで指定します。
例えば、オプションを -i apple -pt -sb
のように指定して、プロジェクト削除コマンドを実行した場合、以下の2つのプロジェクトが削除されます。
- apple-prototype
- apple-sandbox
この例の場合は、「 production 」プロジェクトはフラグで指定していないので、production用プロジェクトの「 apple 」は削除されません。
コマンド構成
以下の部分で、コマンド全体を構成している部分です。
@click.group(help="command for project") def project(): pass project.add_command(create) project.add_command(list) project.add_command(delete) @click.group(help="command for redmine") def cli(): pass cli.add_command(project)
project
コマンドグループにここまでに定義したコマンド群を追加し、最後に、コマンドルートcli
にproject
を追加しています。
前述のsetup.py
の設定により、ルートコマンドはredmine
に置きかわります。
例えば、list
コマンドの場合は、以下のようなコマンドになります。
redmine project list
使用しているパッケージについて
CLI の構成には、Click パッケージを使用 しています。
Click パッケージの詳細については、以下の公式ページを参照してください。
また、Redmine API へのアクセスには Python-Redmine パッケージを使用 しています。
Python-Redmine パッケージの詳細については、以下の公式ページを参照してください。
実際に、サンプル Redmine CLI ツールを試してみる!
まずは、サンプルコードのルートディレクトリへ移動してください。
cd template_python-redmine-cli
環境変数ファイルの設置
以下のコマンドを実行して、.env
ファイルを追加してください。
cp .env.template .env
コンテナの起動
次に、コンテナを起動します。
以下のコマンドでコンテナを起動してください。
docker-compose up -d
http://localhost:53000 ( Redmine ) にアクセスして、コンテナが起動しているか確認してください。
Redmine のログイン画面が表示されれば起動成功です。
※ Redmine コンテナは起動に少し時間がかかります。
APIアクセスキーを取得&設定
「APIアクセスキー」を起動した Redmine から取得して、.env
ファイル内の [APIアクセスキー]
の部分を取得したアクセスキーと置き換えます。
「APIアクセスキー」は、以下のリンク先を参考にして、取得してください。
Redmine API を試してみる【 curl 編 】 - API アクセスキーの確認
サンプル Redmine CLI ツール を使ってみる
コマンドの自動補完を、せっかく有効にしているので、活用するためにコンテナ内でコマンドを実行していきます。
ホスト環境からコマンドを実行する場合は、以降で解説するコマンドの前に docker-compose run redmine-cli
を付け加えて実行してください。
※ ホスト環境で使用する場合は、コマンドの自動補完は使用できません。
以下のコマンドを実行して、コンテナ内へ入ってください。
docker-compose run redmine-cli
Dockerfile
で CMD
に bash
を指定しているので、サービス名を指定するだけで、bash
が起動します。
ヘルプをチェックしてみる
まずは、ヘルプを表示してみます。
以下のコマンドを実行してください。
$ redmine --help Usage: redmine [OPTIONS] COMMAND [ARGS]... command for redmine Options: --help Show this message and exit. Commands: project command for project
サブコマンド project
が表示されていれば、設定どおりです。
ホスト環境から実行する場合は、以下のようにコマンドになります。
docker-compose run redmine-cli redmine --help
コマンドリストをチェック
サブコマンド project
のヘルプで、追加したコマンドのリストを確認します。
以下のようにコマンドを実行してください。
$ redmine project --help Usage: redmine project [OPTIONS] COMMAND [ARGS]... command for project Options: --help Show this message and exit. Commands: create create project delete delete project delete-all delete all project list list projects
※ コマンドの入力途中で、Tab キーを押すとコマンドが自動補完されます。 候補が複数ある場合は、候補リストが表示されます。
追加した4つのコマンドが表示されていれば、設定の通りです。
続いて、ここで確認したコマンドを使用して、プロジェクトを操作していきたいと思います!
プロジェクトの作成
まずは、プロジェクトを作成します。
とりあえず、オプションなしで実行してみます。
$ redmine project create Usage: redmine project create [OPTIONS] Try 'redmine project create --help' for help. Error: Missing option '--indentifier' / '-i'.
必須に指定していた indentifier
を指定していなかったため、エラーとなりました。
ヘルプでオプションを確認しておきます。
$ redmine project create --help Usage: redmine project create [OPTIONS] create project Options: -i, --indentifier TEXT project identifier [required] -p, --production add production project -pt, --prototype add prototype project -sb, --sandbox add sandbox project --help Show this message and exit.
ヘルプを参考にして、まずは、production、prototype、sandboxタイプの「 apple 」プロジェクトを作成します 。
以下のようにコマンドを実行してください。
$ redmine project create -i apple -p -pt -sb production project created prototype project created sandbox project created
※ オプションについても自動補完が利用できます。
このあとの解説のために、「 orange 」プロジェクトも追加しておきます。
以下のコマンドを実行して、production、sandbox タイプの「 orange 」プロジェクトを追加 してください。
$ redmine project create -i orange -p -sb production project created sandbox project created
プロジェクトが追加されているか、確認しておきます。
http://localhost:53000/projects にアクセスして、プロジェクトが作成されているか確認してください。
以下のように、プロジェクトが5つ表示されていれば、プロジェクトの追加は成功です!
念のためlist
コマンドでも、プロジェクトが追加されているか確認しておきます。
以下のようにコマンドを実行してください。
$ redmine project list apple apple-prototype apple-sandbox orange orange-sandbox
上記のように、追加した5つのプロジェクトが表示されればOKです。
指定プロジェクトの削除
続いて、削除コマンドを試してみたいと思います。
「 apple 」プロジェクトのprototype、sandboxプロジェクトの2つを削除 したいと思います。
まずは、ヘルプを表示してオプションを確認しておきます。
$ redmine project delete --help Usage: redmine project delete [OPTIONS] delete project Options: -i, --indentifier TEXT project identifier [required] -p, --production delete production project -pt, --prototype delete prototype project -sb, --sandbox delete sandbox project --help Show this message and exit.
ヘルプの内容を参考に、「 apple-prototype 」と「 apple-sandbox 」プロジェクトを削除します。
以下のようにコマンドを実行してください。
$ redmine project delete -i apple -pt -sb prototype project deleted sandbox project deleted
プロジェクトが削除されているか、確認しておきます。
http://localhost:53000/projects にアクセスして、プロジェクトが削除されているか確認してください。
以下のように、「 apple-prototype 」と「 apple-sandbox 」プロジェクトが消えていれば、削除成功です!
list
コマンドでもプロジェクトが削除されているか、確認しておきます。
以下のようにコマンドを実行してください。
$ redmine project list apple orange orange-sandbox
「 apple-prototype 」と「 apple-sandbox 」プロジェクトが消えていればOKです。
残りのプロジェクトも削除しておきます。
$ redmine project delete -i apple -p production project deleted $ redmine project delete -i orange -p -sb production project deleted sandbox project deleted
http://localhost:53000/projects と redmine project list
コマンドで、全てのプロジェクトが削除されているか、確認してください。
後始末
最後に、起動したコンテナを停止しておきます。
以下のコマンドで、起動したコンテナを停止してください。
docker-compose down
※ データの永続化設定はしていないので、再起動したときは、再度、APIアクセスキーの設定が必要になります。 注意してください。
注意書き
あくまで、お試しサンプルなので、例外処理などは記述していません。
重複するプロジェクトの追加や、存在しないプロジェクトを削除を行うとエラーになります。
まとめ
今回は、Python で Redmine CLI ツールを作成 してみました!
Python-Redmine が非常に便利でした!
Redmine API、Python-Redmine ともに、さらっと見た程度なので、はっきりとは言えませんが、API をそのままメソッドにしてあるだけでなく、よく使うような機能は API を組み合わせて実装されているような気がします。
公式ツールというわけではないようですが、Redmine 公式の Wiki で紹介されています。
Using the REST API with Python
別記事で、Node.js を使って、Redmine にカスタム API を実装してみましたが、カスタム API を実装する場合も、Python-Redmine を使って Python でやった方がいいような気がします(*´Д`)
Python はあまり使ったことがないので、サーバプログラム向けのおすすめのフレームワークなどがあれば、コメントなどから教えてもらえるとありがたいです(*´▽`*)
おすすめのテストツールとかもあれば、ぜひ!
最後に、今回の内容について、簡単にまとめてみたいと思います。
- Python-Redmine が便利!
- カスタム API も Python で良くね?
- Python の便利なツールとか教えてほしい |д<)