みなさんこんにちは。この秋はiPhone14発売を皮切りにAMD Ryzen7000、Nvidia RTX4000、Google Pixel7、さらにはiPad Pro第6世代発売の噂と注目の新製品が目白押しです。私もそろそろガジェットの更新時期かなと思ってはいたものの、これだけのものが一気に押し寄せてくると懐(と家族の目)が厳しいのでどうしようかと悩み中です。いっそ、空からガジェットが降ってこないものでしょうかね~。

JenkinsでのCI環境を構築する
前回はJenkinsの環境構築と映像関連の現場で必要になる設定をみていきました。今回も引き続き、Jenkinsを使った自動ビルド/テスト環境構築を進めていきます。
WindowsでコマンドラインからURLにアクセスする
WindowsでコマンドラインからURLにアクセスするときにはcurlを使います。Windows10では、2018年のバージョン1803からcurlを標準で使えるようになっています。試しにcurlを使ってJenkinsにアクセスしてみます。
C:\Users\chiyama>curl http://localhost:8080/job/Notepad/build?token=JENKINS_BUILD_TRIGGER
<html><head><meta http-equiv='refresh' content='1;url=/login?from=%2Fjob%2FNotepad%2Fbuild%3Ftoken%3DJENKINS_BUILD_TRIGGER'/><script>window.location.replace('/login?from=%2Fjob%2FNotepad%2Fbuild%3Ftoken%3DJENKINS_BUILD_TRIGGER');</script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
-->
</body></html>
C:\Users\chiyama>
アクセスできたものの、"Authentication required" と言われてしまいました。Jenkinsにアクセスするためには認証が必要なので、この準備をします。
JenkinsのAPIトークンを作成する
curlやgitからJenkinsのAPIにアクセスする場合、APIトークンを使用して認証します。APIトークンは、ユーザーアカウントの設定から作成できます。

トークン新規追加ボタンを押して名前を指定し、生成を押します。

これでトークンが作成されました。

作成されたトークンはこのときにしか確認できないので、コピーしておきます。トークンを忘れてしまった場合は、もう一度、同じ手順でトークンを新規作成します。
作成したトークンを使用してJenkinsにアクセスしてみます。アクセスするURLは
http://(Jenkinsアカウント名):(APIトークン)@(JenkinsのURL)
です。
C:\Users\chiyama>curl -X POST http://chiyama:11543de84b1ed83bc95e635d514727645d@localhost:8080/job/Notepad/build?token=JENKINS_BUILD_TRIGGER
C:\Users\chiyama>

無事にcurl経由でビルドを開始できました。
リポジトリの設定
curl経由でビルドが開始できるようになったので、Jenkinisとgitリポジトリの連携をしていきます。まず、Jenkins上に新たにalrorithmジョブを作成し、Notepadジョブと同様にビルド・トリガの設定をします。続いて、Jenkinsからアクセスするリポジトリを指定します。今回はサーバを立ち上げたり複雑な設定をしたりせず、手軽に環境を立ち上げることを目標としているため、ローカルにあるフォルダ、ないしはWindowsの共有フォルダにあるリポジトリを使います。幸い、gitはそのようなケースも想定されています。
手元にgitのリポジトリを2つ用意します。
- メインのリポジトリ
- ローカルで作業するためのリポジトリ(作業者ごとに作成されるものと同様)
メインのリポジトリが C:\repo\algorithm にあるものとして話を進めます。このリポジトリは作業用リポジトリからpushされるので、bareリポジトリとして作成される必要があります。普段は作業用リポジトリ上でコードの編集とcommitを行い、キリの良いタイミングでメインのリポジトリにpushします。すると、メインのリポジトリからcurl経由でJenkinsのAPIが呼ばれ、ビルドが実行されるようになります。
まず、Jenkins上でリポジトリを指定します。

フォルダを直接扱うので、file:/// を使用してリポジトリを指定します。
Jenkinsでローカルリポジトリを扱えるようにする
Jenkinsでローカルリポジトリを扱うことは、セキュリティの関係上デフォルトでは許可されていないので、許可する必要があります。起動時の引数で指定できるので、起動用batを書き換えます。
@echo off
set JAVA_HOME=C:\Program Files\Java\jdk-11.0.15.1
set PATH=%PATH%;%JAVA_HOME%\bin
java -Dhudson.plugins.git.GitSCM.ALLOW_LOCAL_CHECKOUT=true -jar Jenkins.war --httpPort=8080
設定を変更したらJenkinsを再起動します。
リポジトリの指定ができたところで、ブラウザからビルド実行をしてみます。設定が上手くいっていれば、結果が緑色になってビルドが成功します。

また、C:\Users\(ユーザー名)\.jenkins\workspace\algorithm にリポジトリがチェックアウトされます。

Jenkins上でのテストの実行や成果物の作成は、これを使用して行われます。
ビルド手順の作成
リポジトリのチェックアウトができたので、テストやビルドを実行するための手順をつくります。今回、ビルドは以下の手順で実行します。
1. pythonのvenv作成
2. テスト実行
3. パッケージ作成
プロジェクト設定のビルドで、ビルド手順を追加します。選ぶのは "Windowsバッチコマンドの実行" です。Notepadプロジェクトでメモ帳を起動したときと同様に、pythonのvenvを作成するための処理を記入します。
ここでは以下のようにしました。パスは各自の環境に合わせて読み替えてください。
C:\Users\chiyama\AppData\Local\Programs\Python\Python310\python.exe -m venv C:\Users\chiyama\.jenkins\jobs\algorithm\venv
C:\Users\chiyama\.jenkins\jobs\algorithm\venv\Scripts\python.exe -m pip install pytest

再びブラウザからビルドを実行します。上手くいくと、venvが作成されます。

続けてpytestを実行するための設定を行います。この段階になると、設定しながらビルドを実行し、エラーになったら調整するというサイクルを、良い感じに動くまで繰り返します。最終的に以下のようになりました。
call C:\Users\chiyama\.jenkins\jobs\algorithm\venv\Scripts\activate.bat
pip install -e .
pytest

ビルドが正常に実行できたら、パッケージ作成用の設定をします。
call C:\Users\chiyama\.jenkins\jobs\algorithm\venv\Scripts\activate.bat
pip install wheel
python setup.py bdist_wheel
これを実行すると、パッケージが作成されます。

これでJenkins側の環境構築はひと通り完了です。

リポジトリにコードをpushしたタイミングで、Jenkinsのビルドが走るようにする
リポジトリにコードをpushしたタイミングでJenkinsのビルドが走るようにすれば、リポジトリが更新されるたびにテストとビルドが走るようになり、プログラムが壊れても即座に検出できるようになります。
gitでは、push後の処理を指定できるpost-updateフックが用意されているので、そこでJenkinsのジョブをcurl経由で実行すれば良いです。 C:\repo\algorithm\hooks\post-update として以下の内容を作成します。
#!/bin/sh
C:/Windows/System32/curl.exe -X POST http://chiyama:11543de84b1ed83bc95e635d514727645d@localhost:8080/job/algorithm/build?token=JENKINS_BUILD_TRIGGER
ここで注意が必要なのが、このファイルはWindowsのbatファイルとして実行されるのではなく、Cygwinのshスクリプトとして実行されるため、shスクリプトとして実行可能な形式で記述する必要があることです。
設定ができたら作業用リポジトリでコードを編集し、commitとpushをしてみます。pushをした際にpost-updateが実行されると、"remote: ...." という処理中のメッセージが表示されます。

Jenkinsでビルドの成功が確認できたら、環境構築は完了です。
まとめ
作成したコードをメインのリポジトリにpushすることで、自動的にテストの実行やパッケージの作成ができるようになりました。しかも、今回の方法であれば特別なサーバを立てる必要もないため、システム管理者がいなくても自分だけで手軽にCI環境を構築できます。とはいえ今回作成した環境は本当に最小限のものなので、内容に関してはそれぞれの環境や状況に合わせて調整していく必要があります。例えば事前に作成しておいたvenvを使いまわすか、ビルドごとに専用のvenvを作成して実行するかという点でも判断が分かれますし、テストを実行してからパッケージ化するか、パッケージ化してからテストをするかという点も議論の余地があります。それぞれ自分が必要とする内容に合わせて調整していく必要があります。
第47回の公開は、2022年10月を予定しております。

痴山紘史
日本CGサービス(JCGS) 代表
大学卒業後、株式会社IMAGICA入社。放送局向けリアルタイムCGシステムの構築・運用に携わる。その後、株式会社リンクス・デジワークスにて映画・ゲームなどの映像制作に携わる。2010年独立、現職。映像制作プロダクション向けのパイプラインの開発と提供を行なっている。新人パパ。娘かわいい。
TEXT_痴山紘史 / Hiroshi Chiyama(日本CGサービス)
EDIT_尾形美幸 / Miyuki Ogata(CGWORLD)