簡単にできるJenkinsによるtox環境

# 初めに
みなさん、テストしていますか？
Pythonでの単体テストを複数の環境で実行してくれる「tox」。便利ですよね。
JenkinsでCI環境を作っておけば、一発で複数のバージョンでの動作確認ができちゃいます。

けど、pyenvをインストールしたり、複数のpython環境を用意したりと、意外と手間がかかります。
そこで、Jenkinsでtoxを使用する環境を簡単に構築する方法になります。

手順としては次の通りです。

1. DockerでJenkinsを構築する
1. Pyenvをインストールしたコンテナ用のDockerFileを作る
1. DockerFileを使用するJenkinsfileを作る
1. ユニットテストとカバレッジレポートを取得するtox.iniを作る
1. リポジトリのトップにDockerFile,Jenkinsfile,tox.iniを配置する
1. JenkinsにPiplineジョブを作る
1. ビルド実行

# 事前準備
今回Jenkisfileを使って、CI環境を動的に生成する部分をメインとして解説します。
ですので、Docker環境の構築、Jenkinsの構築については省略します。
__ただ、必ずDocker環境下でJenkinsを構築してください。__

# DockerでJenkinsを構築する

Windows環境の方は下記のページを参考に構築するとよいと思います
https://qiita.com/sh1928kd/items/b248a8d48d16eaab9617

1点、Ubuntu環境などで、Dockerソケットを共有する際、ホスト側のソケットのソケットの権限を気を付けてください。
Jenkins側からの実行権限がないと、エラーとなります。

記事を書いているときのJenkinsのバージョンは「Jenkins 2.255」になります。

## プラグイン
お好きなものを入れましょう。
今回はUnittestの結果とカバレッジリポートを表示したいので「JUnit」と「Cobertura」をインストールしておきます。

- https://plugins.jenkins.io/junit/
- https://plugins.jenkins.io/cobertura/


# Pyenvをインストールしたコンテナ用のDockerFileを作る
環境構築についてはJenkinsfileだけでも行えるはずなのですが、
複数のPython環境を構築する際にpyenvを使用しようとするとうまくいきませんでした。
そこで、複数のPython環境を構築するところまでDockerFileで行います。

```Dockerfile
FROM python:3.8

USER root
ENV HOME /root
ENV PYENV_ROOT $HOME/.pyenv
ENV PATH $PYENV_ROOT/bin:$PATH
# ENV HTTP_PROXY '{プロキシサーバのアドレス}'
# ENV HTTPS_PROXY '{プロキシサーバのアドレス'
# ENV FTP_PROXY '{プロキシサーバのアドレス}'

# RUN echo 'Acquire::http::Proxy "{プロキシサーバのアドレス}";' >> /etc/apt/apt.conf
# RUN echo 'Acquire::https::Proxy "{プロキシサーバのアドレス}";' >> /etc/apt/apt.conf
RUN apt-get update && apt-get upgrade -y \
 && apt-get install -y \
    git \
    make \
    build-essential \
    libssl-dev \
    zlib1g-dev \
    libbz2-dev \
    libreadline-dev \
    libsqlite3-dev \
    wget \
    curl \
    llvm \
    libncurses5-dev \
    libncursesw5-dev \
    xz-utils \
    tk-dev \
    libffi-dev \
    liblzma-dev \
 && git clone https://github.com/pyenv/pyenv.git $PYENV_ROOT

RUN echo 'eval "$(pyenv init -)"' >> ~/.bashrc && \
     eval "$(pyenv init -)"

RUN pyenv install 3.5.9
RUN pyenv install 3.6.2
RUN pyenv install 3.7.2
RUN pyenv install 3.8.2

RUN echo '3.5.9' >> .python-version
RUN echo '3.6.2' >> .python-version
RUN echo '3.7.2' >> .python-version
RUN echo '3.8.2' >> .python-version

```

# Dockerfileを使用するJenkinsfileを作る

Dockerfileで環境構築してしまえばJenkinsfileは難しくありません

```jenkinsfile
pipeline {
    agent { 
        dockerfile {
            filename 'Dockerfile'
            args '-u root:sudo'
        }
    }
    stages {
        stage('setup') {
            steps {
                sh 'pip install flake8'
                sh 'pip install tox'
                sh 'pip install tox-pyenv'
            }
        }
        stage('test') {
            steps {
                sh 'tox'
                // カバレッジを取得
                cobertura coberturaReportFile: 'coverage.xml'
                // テスト結果を取得　
                junit 'junit_reports/*.xml'
            }
        }
    }
}
```
setupの内容についてもDockerFileに記載してしまってもよかったかもしれません。

# ユニットテストとカバレッジレポートを取得するtox.iniを作る

tox.iniを書きます。
今回はテストレポートとカバレッジレポートを取得するので、それぞれのレポートを出力する設定にしてあります

```tox.ini
[tox]
envlist = py35, py36, py37, py38, flake8

[travis]
python =
    3.8: py38
    3.7: py37
    3.6: py36
    3.5: py35

[testenv:flake8]
basepython = python
deps = flake8
commands = flake8 {解析するモジュール名} tests

[flake8]
exclude = tests/*

[testenv]
setenv =
    PYTHONPATH = {toxinidir}
deps = 
    coverage
    unittest-xml-reporting
commands =
    rm -rf junit_reports
    python -m xmlrunner discover -o junit_reports
    coverage erase
    coverage run --append setup.py test
    coverage report --omit='.tox/*'
    coverage xml --omit='.tox/*'

```

# リポジトリのトップにDockerFile,Jenkinsfile,tox.iniを配置する

基本的にはPYPI形式のプロジェクトであれば次のような構成になると思います。

```
-project
    |-module_dir/
        |-main.py
    |-tests/
        |-test_main.py
    |-setup.py
    |-Dockerfile
    |-Jenkinsfile
    |-tox.ini
```

# JenkinsにPiplineジョブを作る

出来上がったスクリプトをGithubなどにPushします。

![jenkins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13360/922d3c41-394f-ee19-3906-46bddc0cc3ce.png)

新規ジョブの作成を選択し、
1. item nameにジョブ名を入力
2. パイプラインを選択

![jenkins2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13360/a95f158e-ef91-859a-427b-277b2340255a.png)



設定画面で
1. 定義に「Pipline script from SCM」を選択
2. SCMに「Git」を選択
3. リポジトリURLにリポジトリのパスを入力

# ビルド実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13360/1a90b4d5-0fe4-0a2c-4b14-51941c10e9cd.png)

Jenkinsのジョブ画面から、「ビルド実行」をすれば、Dockerfileから環境を構築して、
toxを実行した結果をJenkinsが取得してくれます。


# まとめ

Jenkinsで簡単にtoxを実行する環境について紹介しました。
本当はJenkinsfileだけで構築したかったのですが、PATH周りの挙動が良くわからなかったので、
Dockerfileを使いました。

PyPI形式のプロジェクト構成であれば、この方法でほぼほぼ使いまわせるので、テスト環境構築がらくちんになりました。
また、素の環境が出来上がりますので、モジュールの登録漏れや依存ライブラリに気が付けるという利点があります。