言語ガイド: Java
このガイドでは、CircleCI で Gradle を使用して Java アプリケーションをビルドする方法について説明します。
概要
お急ぎの場合は、後述の設定ファイルの例をプロジェクトのルート ディレクトリにある .circleci/config.yml
に貼り付け、ビルドを開始してください。
ここでは、以下を前提としています。
- Gradle を使用している (Maven 版のガイドはこちら)
- Java 11 を使用している
- Spring Framework を使用している (このプロジェクトは Spring Initializr を使用して生成されています)
- アプリケーションをオールインワン uberjar として配布できる
設定ファイルの例
version: 2 # CircleCI 2.0 を使用します
jobs: # 一連のステップ
build:
# 並列処理が必要ない場合は削除します
parallelism: 2
environment:
# OOM (メモリ不足) エラーを回避するように JVM と Gradle を構成します
_JAVA_OPTIONS: "-Xmx3g"
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2"
docker: # Docker でステップを実行します
- image: circleci/openjdk:11.0.3-jdk-stretch # このイメージをすべての `steps` が実行されるプライマリ コンテナとして使用します
- image: circleci/postgres:12-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_DB: circle_test
steps: # 実行可能コマンドの集合
- checkout # ソース コードを作業ディレクトリにチェックアウトします
# 依存関係キャッシュについては https://circleci.com/ja/docs/2.0/caching/ をお読みください
- restore_cache:
key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
- restore_cache:
key: v1-gradle-cache-{{ checksum "build.gradle" }}
- run:
name: テストの並列実行 # https://circleci.com/ja/docs/2.0/parallelism-faster-jobs/ を参照してください
# テストを並列に実行しない場合は、代わりに「./gradlew test」を使用します
command: |
cd src/test/java
# このノードで実行する必要があるテストのクラス名のリストを取得します
CLASSNAMES=$(circleci tests glob "**/*.java" \
| cut -c 1- | sed 's@/@.@g' \
| sed 's/.\{5\}$//' \
| circleci tests split --split-by=timings --timings-type=classname)
cd ../../..
# 引数を「./gradlew test」にフォーマットします
GRADLE_ARGS=$(echo $CLASSNAMES | awk '{for (i=1; i<=NF; i++) print "--tests",$i}')
echo "Prepared arguments for Gradle: $GRADLE_ARGS"
./gradlew test $GRADLE_ARGS
- save_cache:
paths:
- ~/.gradle/wrapper
key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
- save_cache:
paths:
- ~/.gradle/caches
key: v1-gradle-cache-{{ checksum "build.gradle" }}
- store_test_results:
# テスト サマリー (https://circleci.com/ja/docs/2.0/collect-test-data/) に表示するテスト結果をアップロードします
path: build/test-results/test
- store_artifacts: # アーティファクト (https://circleci.com/ja/docs/2.0/artifacts/) に表示するテスト結果をアップロードします
path: build/test-results/test
when: always
- run:
name: JAR の収集
command: |
# 他のノードでは以下をスキップします
if [ "$CIRCLE_NODE_INDEX" == 0 ]; then
./gradlew assemble
fi
# JAR は最初のビルド コンテナでのみ収集されるため、他のすべてのビルド コンテナでは build/libs が空になります
- store_artifacts:
path: build/libs
# デプロイ例については https://circleci.com/ja/docs/2.0/deployment-integrations/ を参照してください
workflows:
version: 2
workflow:
jobs:
- build
コードの取得
上記は Java デモ アプリケーションの設定ファイルの抜粋です。このデモ アプリケーションには、https://github.com/CircleCI-Public/circleci-demo-java-spring からアクセスできます。
ご自身でコード全体を確認する場合は、GitHub でプロジェクトをフォークし、ローカル マシンにダウンロードします。 CircleCI で [Add Projects (プロジェクトの追加)] ページにアクセスし、プロジェクトの横にある [Build Project (プロジェクトのビルド)] ボタンをクリックします。 最後に .circleci/config.yml
の内容をすべて削除します。
これで config.yml
を最初からビルドする準備ができました。
設定ファイルの詳細
常にバージョンの指定から始めます。
version: 2
次に、jobs
キーを記述します。 1 つひとつのジョブが、ビルド、テスト、デプロイのプロセス内の各段階を表します。 このサンプル アプリケーションでは 1 つの build
ジョブのみが必要なので、他の要素はそのキーの下に置きます。
version: 2
jobs:
build:
# 並列処理が必要ない場合は削除します
parallelism: 2
environment:
# OOM (メモリ不足) エラーを回避するように JVM と Gradle を構成します
_JAVA_OPTIONS: "-Xmx3g"
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2"
テストを並列に実行してジョブを高速化するために、オプションの parallelism
値を 2 に指定しています。
また、environment
キーを使用して、OOM エラーを回避するように JVM と Gradle を構成しています。
version: 2
...
docker:
- image: circleci/openjdk:11.0.3-jdk-stretch
- image: circleci/postgres:12-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_DB: circle_test
バージョン 11.0.3-jdk-stretch
のタグが付いた CircleCI OpenJDK コンビニエンス イメージを使用します。
この build
ジョブ内にいくつかの steps
を追加します。
コードベースで作業できるように、最初に checkout
を置きます。
次に、Gradle ラッパーと依存関係のキャッシュをプル ダウンします (存在する場合)。 初回実行時、または gradle/wrapper/gradle-wrapper.properties
と build.gradle
を変更した場合、これは実行されません。
...
steps:
- checkout
- restore_cache:
key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
- restore_cache:
key: v1-gradle-cache-{{ checksum "build.gradle" }}
追加の引数を使用して ./gradlew test
を実行します。これにより、キャッシュが空だった場合、Gradle やプロジェクトの依存関係がプル ダウンされ、テストのサブセットが各ビルド コンテナで実行されます。 各並列ビルド コンテナで実行されるテストのサブセットは、組み込みの circleci tests split
コマンドを使用して決定されます。
...
steps:
- run:
name: Run tests in parallel # https://circleci.com/ja/docs/2.0/parallelism-faster-jobs/ を参照してください
# テストを並列に実行しない場合は、代わりに「./gradlew test」を使用します
command: |
cd src/test/java
# このノードで実行する必要があるテストのクラス名のリストを取得します
CLASSNAMES=$(circleci tests glob "**/*.java" \
| cut -c 1- | sed 's@/@.@g' \
| sed 's/.\{5\}$//' \
| circleci tests split --split-by=timings --timings-type=classname)
cd ../../..
# 引数を「./gradlew test」にフォーマットします
GRADLE_ARGS=$(echo $CLASSNAMES | awk '{for (i=1; i<=NF; i++) print "--tests",$i}')
echo "Prepared arguments for Gradle: $GRADLE_ARGS"
./gradlew test $GRADLE_ARGS
次回の処理を高速化するために、save_cache
ステップを使用して Gradle ラッパーと依存関係を保存します。
...
- save_cache:
paths:
- ~/.gradle/wrapper
key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
- save_cache:
paths:
- ~/.gradle/caches
key: v1-gradle-cache-{{ checksum "build.gradle" }}
続けて、CircleCI ダッシュボードにテスト メタデータを表示できるように、store_test_results
が build/test-results/test
ディレクトリから JUnit テスト メタデータを取得してアップロードします。 また、テスト メタデータを調べる必要がある場合は、store_artifacts
を介してテスト メタデータをアーティファクトとしてアップロードします。
...
- store_test_results:
path: build/test-results/test
- store_artifacts:
path: build/test-results/test
when: always
./gradlew assemble
コマンドを使用して、”uberjar” ファイルを作成します。このファイルには、コンパイルされたアプリケーションと共にそのアプリケーションのすべての依存関係が含まれます。 uberjar のコピーは 1 つだけあればよいので、これは、並列に実行しているすべてのビルド コンテナではなく最初のビルド コンテナでだけ実行されます。
その後、store_artifacts
ステップを使用して、uberjar をアーティファクトとして保存します。 そこから、これを目的の継続的デプロイ スキームに結び付けることができます。
...
- run:
name: Assemble JAR
command: |
# 他のノードでは以下をスキップします
if [ "$CIRCLE_NODE_INDEX" == 0 ]; then
./gradlew assemble
fi
# JAR は最初のビルド コンテナでのみ収集されるため、他のすべてのビルド コンテナでは build/libs が空になります
- store_artifacts:
path: build/libs
最後に、ワークフロー内の唯一のジョブとして build
ジョブによって実行される workflow
というワークフローを定義します。
...
workflows:
version: 2
workflow:
jobs:
- build
完了です。 これで Gradle と Spring を使用する Java アプリケーション用に CircleCI をセットアップできました。
関連項目
- デプロイ ターゲットの構成例については、「デプロイの構成」を参照してください。
- Java のメモリの問題に対処する方法については、「Java メモリ エラーの回避とデバッグ」を参照してください。