言語ガイド: Java

このガイドでは、CircleCI で Gradle を使用して Java アプリケーションをビルドする方法について説明します。

概要

お急ぎの場合は、後述の設定ファイルの例をプロジェクトのルート ディレクトリにある .circleci/config.yml に貼り付け、ビルドを開始してください。

ここでは、以下を前提としています。

  • You are using Gradle. Gradle を使用している (Maven 版のガイドはこちら)
  • Java 11 を使用している
  • You are using the Spring Framework. 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
      - store_artifacts:
          path: build/libs
      # See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
workflows:
  version: 2
  workflow:
    jobs:
    - build

コードの取得

常にバージョンの指定から始めます。

このデモ アプリケーションには、https://github.com/CircleCI-Public/circleci-demo-java-spring からアクセスできます。

ご自身でコード全体を確認する場合は、GitHub でプロジェクトをフォークし、ローカル マシンにダウンロードします。 CircleCI で [Add Projects (プロジェクトの追加)] ページにアクセスし、プロジェクトの横にある [Build Project (プロジェクトのビルド)] ボタンをクリックします。 最後に .circleci/config.yml の内容をすべて削除します。

また、environment キーを使用して、OOM エラーを回避するように JVM と Gradle を構成しています。

設定ファイルの詳細

バージョン 11.0.3-jdk-stretch のタグが付いた CircleCI OpenJDK コンビニエンス イメージを使用します。

この build ジョブ内にいくつかの steps を追加します。

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 に指定しています。

We also use the environment key to configure the JVM and Gradle to avoid OOM errors. We disable the Gradle daemon to let the Gradle process terminate after it is done. This helps to conserve memory and reduce the chance of OOM errors.

version: 2
...
    docker:
      - image: circleci/openjdk:11.0.3-jdk-stretch
      - image: circleci/postgres:12-alpine
        environment:
          POSTGRES_USER: postgres
          POSTGRES_DB: circle_test

We use the CircleCI OpenJDK Convenience images tagged to version 11.0.3-jdk-stretch.

最後に、ワークフロー内の唯一のジョブとして build ジョブによって実行される workflow というワークフローを定義します。

コードベースで作業できるように、最初に checkout を置きます。

次に、Gradle ラッパーと依存関係のキャッシュをプル ダウンします (存在する場合)。 初回実行時、または gradle/wrapper/gradle-wrapper.propertiesbuild.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_resultsbuild/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
      - store_artifacts:
          path: build/libs

Lastly, we define a workflow named workflow which the build job will execute as the only job in the workflow.

...
workflows:
  version: 2
  workflow:
    jobs:

    - build

完了です。 これで Gradle と Spring を使用する Java アプリケーション用に CircleCI をセットアップできました。

関連項目



Help make this document better

This guide, as well as the rest of our docs, are open-source and available on GitHub. We welcome your contributions.