JavaによるCI導入ガイドも最終回の第6回目となる。これまで Spock によるユニットテストや jacoco によるカバレッジ計測、Checkstyle によるコードスタイル検証の紹介をした。紹介した継続的インテグレーション(CI)のツールを GitLabに導入する。
目次
- 第1回 導入と概要
- 第2回 Spock によるユニットテストとjacocoによるカバレッジ計測
- 第3回 Checkstyle によるコードスタイル検証
- 第4回 さまざまなジョブ(2) その他のツールの紹介
- 第5回 End to End (e2e) テスト
- 第6回 CI設定
1. Gitlab 設置と初期設定
Gitlab の説明は既存の記事にて。 記事 を参考に Gitlab を導入する。 実行環境の保存, Runner の登録 は操作が異なるので説明する。
実行環境の保存
今回のアプリケーションのビルドと検証に必要な環境を Docker で作成する。 Gitlab のホスト上で空のディレクトリを作り、以下の Dockerfile を保存する。
Dockerfile(on Gitlab)
FROM openjdk:10.0.2-slim
ENV DEBCONF_NOWARNINGS yes
# 必要なパッケージのインストール
RUN echo "deb http://httpredir.debian.org/debian jessie-backports main contrib non-free" >> /etc/apt/sources.list && \
apt-get update && \
mkdir -p /usr/share/man/man1 && \
apt-get install --yes --no-install-recommends \
postgresql-client-10 docker.io curl python2.7 psmisc wget firefox
# Docker compose のインストール
RUN curl -L "https://github.com/docker/compose/releases/download/1.12.0/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/bin/docker-compose && \
chmod +x /usr/bin/docker-compose
# Chrome のインストール
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
apt-get install --yes --no-install-recommends \
fonts-liberation libappindicator3-1 libasound2 libxss1 lsb-release xdg-utils && \
dpkg -i google-chrome-stable_current_amd64.deb && \
rm -f google-chrome-stable_current_amd64.deb
# Infer のインストール
# ダウンロードが遅いので、何回も実行する場合は
# 以下のようにあらかじめダウンロードしたものを使うほうが良いかも
#
# COPY infer-linux64-v0.15.0.tar.xz /opt
# RUN cd /opt && \
# tar xJf infer-linux64-v0.15.0.tar.xz && \
# ...
RUN cd /opt && \
curl -sL \
https://github.com/facebook/infer/releases/download/v0.15.0/infer-linux64-v0.15.0.tar.xz | \
tar xJ && \
rm -f /infer && \
ln -s ${PWD}/infer-linux64-v0.15.0 /infer && \
rm -f /opt/infer-linux64-v0.15.0.tar.xz
ENV INFER_HOME /infer
ENV PATH ${INFER_HOME}/bin:${PATH}
CMD '/bin/bash'
Dockerfile を作ったディレクトリで、以下のコマンドを発行し。イメージをビルドする。
sudo docker build . -t jdk-infer-browser
jdk-infer-browser
というタグでイメージが保存される。
Dockerfile のコメントにもあるが、infer のイメージの取得に時間がかかるため、上記のビルドには結構な時間がかかる。 必要なら、予め infer のビルド済みファイルを取得して Dockerfile のあるディレクトリに置いておき、 コメントの指示のようにコマンドを書き換えるのが良いだろう。
Runner の登録
上記記事と行うことは殆ど変わらないが、以下の点を読み替える。
<環境に付けるタグ名> -> jdk,infer,browser
<実行するDockerのイメージ> -> jdk-infer-browser
プロジェクトの作成
GitLab のトップページに移動し、‘Create a projec’ から新しいプロジェクトを作る。
2. Gitlab ジョブの設定
開発環境に戻り、Gitlab のジョブファイルを作成していく。
以下のファイルを作成する。Infer の実行方法のみ開発環境と異なる。 (ビルド時にビルド処理を Infer にキャプチャさせておくようにする。解析時にはキャプチャしたビルド情報をもとに解析を行わせる)
.gitlab-ci.yml
# 利用する Docker image
image: jdk-infer-browser
# Runner 上の環境変数
variables:
# ストレージドライバの指定
DOCKER_DRIVER: overlay2
# 以下データベース接続設定
POSTGRES_HOST: messageboard-ci-postgres
POSTGRES_DB: java_ci
POSTGRES_USER: java_ci
POSTGRES_PASSWORD: "password"
POSTGRES_PORT: 5432
# タスクステージの設定
stages:
- build
- cleanup_build
- unit_test
- code_check
- e2e_test
- deploy
# 各タスクの処理前に実行するコマンド
# gradle のキャッシュを gitlab にキャッシュさせる
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
# プロジェクト全体のキャッシュの設定
cache:
paths:
- build/
- infer-out/
- .gradle
# データベースが必要なタスクのための
# サービスの設定を YAML エイリアスにする
.services:
- &postgres-service
name: postgres:9.6
alias: messageboard-ci-postgres
# データベースの初期化処理を
# YAML エイリアスにする
.scripts:
- &init-postgres >
PGHOST=$POSTGRES_HOST
PGPORT=$POSTGRES_PORT
PGUSER=$POSTGRES_USER
PGPASSWORD=$POSTGRES_PASSWORD
psql $POSTGRES_DB < ./sql/scheme.sql
# 各タスクのタグは同じにするので
# YAML エイリアスにする
.tags:
- &runner-tags
- jdk
- infer
- browser
# ここからタスクの登録
# ビルドタスク
build:
stage: build
tags: *runner-tags
script:
# ビルド処理コマンド
# この時点で infer にキャプチャをさせておく
- infer capture -a checkers --eradicate -- ./gradlew build -x check
# ビルド生成物の指定
artifacts:
when: on_success
paths:
- build/libs
# ビルドが失敗したときのクリーンアップタスク
cleanup_build_job:
stage: cleanup_build
tags: *runner-tags
script:
- ./gradlew clean
- rm -fr ./infer-out
when: on_failure
# ユニットテスト実行タスク
unit_test:
stage: unit_test
tags: *runner-tags
services:
# データベースサービスを起動する
- *postgres-service
before_script:
# 初期化スクリプトを実行する
- *init-postgres
script:
# データベース環境を指定してユニットテストを走らせる
- >
./gradlew
-Pdburl=jdbc:postgresql://$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB
-Pdbuser=$POSTGRES_USER
-Pdbpass=$POSTGRES_PASSWORD
test --info
artifacts:
when: always
paths:
- build/reports/tests/test
- build/jacoco
# build タスクに依存させる
dependencies:
- build
# スタイル解析処理タスク
checkstyle:
stage: code_check
tags: *runner-tags
script:
- ./gradlew checkstyleMain --info
artifacts:
when: always
paths:
- build/reports/checkstyle
# build タスクに依存させる
dependencies:
- build
# カバレッジ解析タスク
coverage:
stage: code_check
tags: *runner-tags
script:
- ./gradlew jacocoTestReport --info
artifacts:
when: always
paths:
- build/jacocoHtml
dependencies:
# unit_test タスクに依存させる
- unit_test
# バグ解析タスク
infer:
stage: code_check
tags: *runner-tags
script:
# キャプチャの結果をもとに解析する
- infer analyze --fail-on-issue --eradicate
after_script:
# HTML レポートを出力させる
- infer explore --html
artifacts:
when: always
paths:
- infer-out/report.html
dependencies:
- build
# e2e テストタスク
e2e_test:
stage: e2e_test
tags: *runner-tags
# Spring のテストが起動するため
# DB を容易しておく
services:
- *postgres-service
before_script:
# DB 初期化
- *init-postgres
# アプリケーションサーバをバックグラウンドで起動させる
- >
/usr/bin/java
-Dspring.datasource.url=jdbc:postgresql://$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB
-Dspring.datasource.username=$POSTGRES_USER
-Dspring.datasource.password=$POSTGRES_PASSWORD
-jar ./build/libs/message-board-0.1.0.jar &
script:
# e2e テストを実行させる
- >
./gradlew
-Pdburl=jdbc:postgresql://$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB
-Pdbuser=$POSTGRES_USER
-Pdbpass=$POSTGRES_PASSWORD
-Pci=yes e2e:e2eTest --info
after_script:
# アプリケーションサーバを止める
- fuser 8080/tcp -k || true
artifacts:
when: always
paths:
- e2e/build/reports/tests
# build タスクに依存させる
dependencies:
- build
# 各タスクの成果物(レポートなど)をまとめて
# ブラウザからのアクセスができるようにする
pages:
stage: deploy
tags: *runner-tags
script:
- mkdir -p public
- cp -r build/reports/checkstyle public/checkstyle
- cp -r build/reports/tests/test public/unit_test
- cp -r build/jacocoHtml public/coverage
- cp -r infer-out/report.html public/infer
artifacts:
paths:
- public
これで CI を回す準備ができた。 先程作ったプロジェクトに git push
を行う。 自動的に CI の処理が開始される。 すると、Gitlab の当該プロジェクト内 ‘CI/CD’ 画面で、以下のようにタスクの状態を確認できるようになる。
しばらくすると、以下のように実行が完了する。
終わりに
これでCIを回すことができた。このあとは、アプリケーションを改良していきながら CI の良さを実感しよう。
改良したい点
- リファクタリング
- POJO クラスを Lombok を使ってスッキリさせる
- MessageForm クラスは Immutable にできる
- MessageBoardController にビジネスロジックが入っているので、Facade クラスを作ってそちらに追い出す
- コマンドのパースをもう少しマシにする
- セキュリティ対策
- CSRF 対策
- 機能の追加
- 日付の表示、ハンドル名、削除機能…
- API化
- フロントエンドをリッチにする
- and something you wants.
本ブログは、Git / Subversionのクラウド型ホスティングサービス「tracpath(トラックパス)」を提供している株式会社オープングルーヴが運営しています。
エンタープライズ向け Git / Subversion 導入や DevOps による開発の効率化を検討している法人様必見!
「tracpath(トラックパス)」は、企業内の情報システム部門や、ソフトウェア開発・アプリケーション開発チームに対して、開発の効率化を支援し、品質向上を実現します。
さらに、システム運用の効率化・自動化支援サービスも提供しています。
”つくる情熱を支えるサービス”を提供し、まるで専属のインフラエンジニアのように、あなたのチームを支えていきます。
No Comments