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-browserjdk-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