Gradle公式ドキュメントを読む-Running Gradle Builds(4)

#この記事について
Gradleをより理解するために公式ドキュメントを読んでメモ代わりとして私なりに訳していきます。
読んでいるドキュメントのバージョンは7.3.3です。
この記事で訳している章はRunning Gradle Builds>Executing Multi-Project Buildsとなります。
必要な章から読んでいるため、一連の記事は公式ドキュメントの章立て通りの順にはなっていません。

##Running Gradle Builds>Executing Multi-Project Builds
大規模なモノリス的アプリケーションでない限りは、単独のビルドファイルとファイルツリーを持つプロジェクトは最小のものに限られます。相互に依存関係を持つ小さく分割されたプロジェクトは理解と習熟が容易になります。相互的依存関係という言葉が重要で、モジュールをひとまとめにリンクしてビルドしてしまう典型的な理由でもあります。

Gradleはこのシナリオを*マルチプロジェクト*ビルドとしてサポートします。
マルチプロジェクトビルドの詳細については[Authoring Multi-Project Builds](https://docs.gradle.org/current/userguide/multi_project_builds.html#multi_project_builds)の節を参照してください。

###[Identifying project structure](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html#sec:identifying_project_structure)
プロジェクトの構造を確認するには`gradle projects`コマンドを使用します。例として、下記のような構造のプロジェクトを扱います。

```shell-session
> gradle -q projects

------------------------------------------------------------
Root project 'multiproject'
------------------------------------------------------------

Root project 'multiproject'
+--- Project ':api'
+--- Project ':services'
|    +--- Project ':services:shared'
|    \--- Project ':services:webservice'
\--- Project ':shared'
```
*タスクのリストを表示するには*`gradle <project-path>:tasks`を実行してください。この例では`gradle :api:tasks`を実行してみてください。

ユーザーの視点では、マルチプロジェクトのビルドは実行可能なタスクの集合であることに変わりはありません。異なっているのはどのプロジェクトのタスクを実行するかを制御できる点です。以下の節でマルチプロジェクトビルドでのタスクの実行に2つの選択肢があることを説明します。

###[Executing tasks by name](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html#sec:executing_tasks_by_name)
`gradle test`コマンドは現在の作業ディレクトリからのサブプロジェクトがもつ`test`タスクを実行します。もしプロジェクトのルートディレクトリで`test`を実行すると、api,shared,services:shared,servieces:webserviceの`test`が実行されます。servicesプロジェクトディレクトリでコマンドを実行した場合、services:sharedとservices:webserviceのみが実行されます。

Gradleの挙動の背後にある基本ルールは階層下にある指定された名前のタスクを実行することです。サブプロジェクトを巡回してそのようなタスクが見つからなかった場合のみ文句をつけます。

:::note
`like`や`dependencies`のようなタスクセレクタはすべてのサブプロジェクトではなく起動されたプロジェクトでのみ実行されることがあります。これはこれらのタスクが、すべてのプロジェクトでの実行結果を統合すると処理が難しい情報を出力するからです。
:::
Gradleは現在のディレクトリから階層を下って、与えられた名前のタスクを探して実行します。Gradleは常にマルチプロジェクトビルドの個々のプロジェクトを評価しながら、存在するタスクオブジェクトを作成します。そして、現在のディレクトリとタスク名の引数に従って、実行するべきタスクをフィルタリングします。なぜなら、[cross project configuration](https://docs.gradle.org/current/userguide/sharing_build_logic_between_subprojects.html#sec:convention_plugins_vs_cross_configuration)のため、すべてのプロジェクトはあるタスクが実行される前に表かれていなければなりません。

Gradle Wrapperを使用している場合、サブプロジェクトのディレクトリからGradleを起動して特定のサブプロジェクトのタスクを実行すると動作しません。プロジェクトのルートにいない限りはラッパースクリプトのパスを指定する必要があるからです。例では、webserviceサブプロジェクトに居てwevserviceサブプロジェクトの`build`タスクを実行したい場合には、`../../gradlew build`とコマンドを実行する必要があります。次の節ではこれをプロジェクトルートから実行する方法を説明します。

###[Executing tasks by fully qualified name](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html#sec:executing_tasks_by_fully_qualified_name)
特定のサブプロジェクトの特定のタスクを完全修飾名を使って実行することができます。例では`gradle :services:webservice:build`でwebserviceサブプロジェクトの`build`タスクを実行できます。完全修飾名は単にプロジェクトパスとタスク名を結合したものです。

プロジェクトパスは下記の形式を持ちます。

+ ルートプロジェクトを意味するオプションのコロンから始まる。ルートプロジェクトはプロジェクト内で唯一、パスの中で名前を指定されません。
+ コロンで区切られたプロジェクト名の順列。次のプロジェクトは前のプロジェクトのサブプロジェクトです。

この手法はどのタスクでも動作します。特定のサブプロジェクトのタスクを知りたい場合、そのプロジェクトの`task`タスクを実行すればよいのです。例えば`gradle :services:webservice:tasks`となります。

どのような手法でタスクを実行する場合でも、Gradleはターゲットとなるサブプロジェクトの依存関係を解決します。相互的な依存関係を憂慮する必要はありません。もしもこれについての構成方法に興味があるなら、[この後のユーザーマニュアル](https://docs.gradle.org/current/userguide/multi_project_builds.html#multi_project_builds "Creating a multi-project build")で読むことができます。

###[Multi-Project Building and Testing](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html#sec:multiproject_build_and_test)
Javaプラグインの`build`タスクは通常、単一のプロジェクトのコンパイル、テスト、（コード品質管理のプラグインを使用していれば）スタイルチェックに使用されます。マルチプロジェクトのビルドではこれらのタスクを様々な範囲のプロジェクトで行いたいと思うことがあります。`buildNeeded`タスクと`buildDependents`タスクがこれらを支援します。

[この例](https://docs.gradle.org/current/userguide/declaring_dependencies_between_subprojects.html#javadependencies_2)では:services:person-serviceプロジェクトは:apiプロジェクトと:sharedプロジェクトの双方に依存しています。

:apiプロジェクト単体で作業をしているとします。変更を行いましたが、cleanを行った後、プロジェクト全体のビルドは行っていません。必要なjarのビルドは行いますが、コード品質管理とユニットテストは変更したプロジェクトだけで実行したいと考えています。`build`タスクはこのように実行されます。

####単体プロジェクトのビルドとテスト
**`gradle :api:build`の実行結果**

```shell-session:
> gradle :api:build
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build

BUILD SUCCESSFUL in 0s
```

:apiプロジェクトが依存する他のプロジェクトの変更を含む最新バージョンをバージョン管理システムから取得した場合、あなたのプロジェクトが依存しているプロジェクトのビルドだけではなく、それらのテストも行いたいと思うかもしれません。`buildNeeded`タスクはtestRuntime構成に含まれる依存しているプロジェクトのテストも行います。

####依存しているプロジェクトのビルドとテスト
**`gradle :api:buildNeeded`の実行結果**

```shell_session
> gradle :api:buildNeeded
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :shared:assemble
> Task :shared:compileTestJava
> Task :shared:processTestResources
> Task :shared:testClasses
> Task :shared:test
> Task :shared:check
> Task :shared:build
> Task :shared:buildNeeded
> Task :api:buildNeeded

BUILD SUCCESSFUL in 0s
```

また、他のプロジェクトで使用されている:apiプロジェクトの一部をリファクタリングしたいと思うこともあるでしょう。このような変更を行う場合、:apiプロジェクトのテストを行うだけでは不十分で、:apiプロジェクトに依存しているすべてのプロジェクトをテストする必要があります。`buildDependents`タスクは特定のプロジェクトの（testRuntime構成上の）依存関係にあるすべてのプロジェクトのテストも行います。

####依存関係のあるプロジェクトのビルドとテスト
**`gradle :api:buildDependents`の実行結果**

```shell-session
> gradle :api:buildDependents
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :services:person-service:compileJava
> Task :services:person-service:processResources
> Task :services:person-service:classes
> Task :services:person-service:jar
> Task :services:person-service:assemble
> Task :services:person-service:compileTestJava
> Task :services:person-service:processTestResources
> Task :services:person-service:testClasses
> Task :services:person-service:test
> Task :services:person-service:check
> Task :services:person-service:build
> Task :services:person-service:buildDependents
> Task :api:buildDependents

BUILD SUCCESSFUL in 0s
```

最後に、全てのプロジェクトのすべてのビルドとテストをしたいと考えました。あるタスクをプロジェクトのルートフォルダで実行すると、全ての子どもで同じ名前のタスクが実行されます。そのため、`gradle build`を実行するだけですべてのプロジェクトのビルドとテストが行われます。