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

#背景
一つの親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に含まれない可能性が存在します[^fat-jar]。

```xml
<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に追加することです。

```yaml
#...#
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](https://qiita-image-store.s3.amazonaws.com/0/129176/84d38e20-9e7b-61e8-e263-bbefd515e8b0.png)


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

![circleci-add-environment-variables.PNG](https://qiita-image-store.s3.amazonaws.com/0/129176/210d9597-736f-04e3-1f69-1ba33d079b0a.png)


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

```bash
#!/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`を付けなければ、トークンがコンソールに出力される恐れがありますので、必ずつけて下さい[^silent-fetch]。
＊使用しているCircleCIのAPIは[こちら](https://circleci.com/docs/api/#build-artifacts-latest)

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

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

##チ　プロジェクトAをコミットし、ビルド成功を確認
待望の画面を迎えましょう！
![circleci-success.PNG](https://qiita-image-store.s3.amazonaws.com/0/129176/1fdfabb7-d981-3b69-0c75-67e1d8d9c501.png)


#ご参考
[^fat-jar]: http://stackoverflow.com/questions/32170664/running-jar-built-using-maven-causes-java-lang-noclassdeffounderror-org-rosuda/32170738#32170738
[^silent-fetch]: https://www.mattcutts.com/blog/how-to-fetch-a-url-with-curl-or-wget-silently/
[^jq-lib]: https://stedolan.github.io/jq/