背景
一つの親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を汚さずにディペンデンシーの依存解消を果たしたいです。
解決法
様々なやり方で試行錯誤を重ねた末に、下記の方法が一番単純で行いやすいんじゃないかと思います。
- プロジェクトBのビルド成果物をartifactとして出力
- プロジェクトA側ではCircleCIのAPIに通してBのパッケージをダウンロード
- 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」にて発行できます。
ホ アクセストークンをプロジェクトAの環境変数に追加
プロジェクトAのビルドでAPIを使ったり、ダウンロードを行ったりする為、トークンが発行できたら、プロジェクトAの環境変数にそれを入れます。
場所は「PROJECT SETTINGS(歯車記号)」→「Environment Variables」→「Add Variable」です。
ヘ ディペンデンシー追加用スクリプトを作成
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
# ... #