Java
Maven
CircleCI

CircleCIで別プロジェクトをMavenライブラリとして追加し、ビルドに使わせる方法

More than 1 year has passed since last update.

背景

一つの親Mavenプロジェクトの元にプロジェクトAとプロジェクトBという二つの子Mavenプロジェクトがあります。プロジェクトAとプロジェクトBは個別にGitHubに通じてCircleCIへ追加されていますので、無関係なプロジェクトとして見なされています(即ち、リポジトリは別々)。しかし、プロジェクトAはプロジェクトBの機能を使っている為、プロジェクトBへの依存性が存在します。

課題

ローカル環境では、プロジェクトAとBの兄弟関係が親Mavenプロジェクト経由で確認できる為、プロジェクトAのpom.xmlにプロジェクトBをdependencyとして追加するだけで、ビルドが可能になります。しかし、CircleCI上では無関係なプロジェクトとして見なされていますので、Could not resolve dependencies for projectが発生し得ます。プロジェクトAのpom.xmlを汚さずにディペンデンシーの依存解消を果たしたいです。

解決法

様々なやり方で試行錯誤を重ねた末に、下記の方法が一番単純で行いやすいんじゃないかと思います。

  1. プロジェクトBのビルド成果物をartifactとして出力
  2. プロジェクトA側ではCircleCIのAPIに通してBのパッケージをダウンロード
  3. CircleCIがディペンデンシー解消を行う前にMavenインストールに通してBを外部ライブラリとして導入

詳細手順

イ プロジェクトBにMaven Assembly Pluginを導入

以下のコードをプロジェクトBのpom.xmlに入れます。これを使用しなければ、プロジェクトBが使用しているライブラリがjarに含まれない可能性が存在します1

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- ... -->
  <build>
    <plugins>
      <!-- ... -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.5.5</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>assemble-all</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- ... -->
    </plugins>
  </build>
  <!-- ... -->
</project>

ロ プロジェクトBに成果物をartifactとして指定

CircleCIに出力したいファイルをartifactに指定する必要があります。やり方は以下のコードをcircle.ymlに追加することです。

#...#
general:
    #...#
    artifacts:
        #このファイル名はmaven-assembly-pluginのデフォルトのようです
        - "target/<ファイル名>-<バージョン>-jar-with-dependencies.jar"
    #...#
#...#

ハ プロジェクトBをコミットし、ビルド成功を確認

特に変なことが発生しなければ、成功するはずです。
ちなみに、成果物をartifactに指定すれば、CircleCIのビルドページからもダウンロード可能になります。(artifacts項目内)

ニ アクセストークンを発行

プライベートプロジェクトであれば、artifactをダウンロードするのにアクセス用のトークンが必要になります。
アクセストークンはCircleCIの「ACCOUNT SETTINGS」→「Personal API Tokens」→「Create New Token」にて発行できます。

circleci-access-token.PNG

ホ アクセストークンをプロジェクトAの環境変数に追加

プロジェクトAのビルドでAPIを使ったり、ダウンロードを行ったりする為、トークンが発行できたら、プロジェクトAの環境変数にそれを入れます。
場所は「PROJECT SETTINGS(歯車記号)」→「Environment Variables」→「Add Variable」です。

circleci-add-environment-variables.PNG

ヘ ディペンデンシー追加用スクリプトを作成

add_dependencies.shというファイルを作成し、以下の内容を入れます(プロジェクト名をproject_bとしています、<>で囲まれている部分は適切な値に置き換えてください)。
一行目で追加したjqというライブラリはCircleCIから返されてきたJsonレスポンスを解読する為に使用されます2

#!/bin/sh
sudo apt-get install jq
currentDirectory=$(pwd)
echo $currentDirectory
downloadUrl=$(curl -sS "https://circleci.com/api/v1.1/project/github/<ユーザ/組織名>/project_b/latest/artifacts?circle-token=$MY_ACCESS_TOKEN&branch=<ブランチ名>" | jq '.[] | .url' | grep project_b.*with-dependencies\.jar | sed -e "s/\"//g")
echo $downloadUrl
sudo wget $downloadUrl?circle-token=$MY_ACCESS_TOKEN -O project_b.jar --quiet
mvn install:install-file -Dfile=$currentDirectory/project_b.jar -DgroupId=<グループID> -DartifactId=project_b -Dversion=<バージョン> -Dpackaging=jar -DgeneratePom=true

*注意:wgetに--quite-qを付けなければ、トークンがコンソールに出力される恐れがありますので、必ずつけて下さい3
*使用しているCircleCIのAPIはこちら

ト CircleCIの実行手順にスクリプトを追加

スクリプトが完成できたら、プロジェクトAのcircle.ymlにそれを実行させるコマンドを追加します。実行のタイミングはCircleCIがディペンデンシーを解消する前です。

# ... #
dependencies:
    pre:
        - sudo chmod a+x add_dependencies.sh
        - ./add_dependencies.sh
# ... #

チ プロジェクトAをコミットし、ビルド成功を確認

待望の画面を迎えましょう!
circleci-success.PNG

ご参考