NOTE: You can open this sample inside an IDE using the https://www.jetbrains.com/help/idea/gradle.html#gradle_import_project_start[IntelliJ native importer] or https://projects.eclipse.org/projects/tools.buildship[Eclipse Buildship].

This sample shows how build logic in a multi-project build can be organized into reusable plugins.

== Use case

As an example, let's say a project with three subprojects produces two public Java libraries that use the third subproject as an internal shared library.
This is the project structure:

====
[.multi-language-sample]
=====
.Project structure
[source, kotlin]
----
├── internal-module
│   └── build.gradle.kts
├── library-a
│   ├── build.gradle.kts
│   └── README.md
├── library-b
│   ├── build.gradle.kts
│   └── README.md
└── settings.gradle.kts
----
=====
[.multi-language-sample]
=====
.Project structure
[source, groovy]
----
├── internal-module
│   └── build.gradle
├── library-a
│   ├── build.gradle
│   └── README.md
├── library-b
│   ├── build.gradle
│   └── README.md
└── settings.gradle
----
=====
====

Let's say that all our projects will be Java projects.
In this case we want to apply a common set of rules to all of them, such as source directory layout, compiler flags,
code style conventions, code quality checks and so on.

Two out of three projects are more than just Java projects - they are libraries that we perhaps want to publish to an
external repository. Publishing configuration, such as a common group name for the libraries as well as the repository coordinates
might be a cross-cutting concern that both libraries need to share. For this example let's also say that we want to enforce that
our libraries expose some documentation with a common structure.

== Organizing build logic

From the use case above, we have identified that we have two types of projects - generic Java projects and public libraries.
We can model this use case by layering two separate plugins that each define the type of project that applies them:

====
[.multi-language-sample]
=====
.Build logic layout
[source, kotlin]
----
├── buildSrc
│   ├── build.gradle.kts
│   ├── settings.gradle.kts
│   ├── src
│   │   ├── main
│   │   │   └── kotlin
│   │   │       ├── myproject.java-conventions.gradle.kts
│   │   │       └── myproject.library-conventions.gradle.kts
...
----
=====
[.multi-language-sample]
=====
.Build logic layout
[source, groovy]
----
├── buildSrc
│   ├── build.gradle
│   ├── settings.gradle
│   ├── src
│   │   ├── main
│   │   │   └── groovy
│   │   │       ├── myproject.java-conventions.gradle
│   │   │       └── myproject.library-conventions.gradle
...
----
=====
====

* `myproject.java-conventions` - configures conventions that are generic for any Java project in the organization.
It applies the core `java` and `checkstyle` plugins as well as an external `com.github.spotbugs` plugin, configures common
compiler options as well as code quality checks.
* `myproject.library-conventions` - adds publishing configuration to publish to the organization's repository and checks for mandatory content in a README.
It applies `java-library` and `maven-publish` plugins as well as the `myproject.java-conventions` plugin.

The internal library subproject applies `myproject.java-conventions` plugin:
====
include::sample[dir="kotlin",files="internal-module/build.gradle.kts[]"]
include::sample[dir="groovy",files="internal-module/build.gradle[]"]
====

The two public library subprojects apply `myproject.library-conventions` plugin.
====
include::sample[dir="kotlin",files="library-a/build.gradle.kts[];library-b/build.gradle.kts[]"]
include::sample[dir="groovy",files="library-a/build.gradle[];library-b/build.gradle[]"]
====

Note how applying a convention plugin to a subproject effectively declares its type.
By applying `myproject.java-conventions` plugin we state: this is a "Java" project.
By applying `myproject.library-conventions` plugin we state: this is a "Library" project.

All plugins created in this sample contain functional tests that use link:{userManualPath}/test_kit.html[TestKit] to verify their behavior.

This sample does not have any project source code and only lays out a hypothetical project structure where two library subprojects depend on a shared internal subproject.


== Compiling convention plugins

In this sample, convention plugins are implemented as link:{userManualPath}/custom_plugins.html#sec:precompiled_plugins[precompiled script plugins] -
this is the simplest way to start out as you can use one of Gradle's DSLs directly to implement the build logic, just as if the plugin was
a regular build script.

[.multi-language-text.lang-kotlin]
In order for precompiled script plugins to be discovered, the `buildSrc` project needs to apply the `kotlin-dsl` plugin
in its `build.gradle.kts` file:


[.multi-language-text.lang-groovy]
In order for precompiled script plugins to be discovered, the `buildSrc` project needs to apply the `groovy-gradle-plugin` plugin
in its `build.gradle` file:

.Enabling precompiled script plugins
====
include::sample[dir="kotlin",files="buildSrc/build.gradle.kts[tags=apply]"]
include::sample[dir="groovy",files="buildSrc/build.gradle[tags=apply]"]
====


== Things to note

=== Applying an external plugin in precompiled script plugin

The `myproject.java-conventions` plugin uses SpotBugs plugin to perform static code analysis.

SpotBugs is an external plugin - external plugins link:{userManualPath}/custom_plugins.html#applying_external_plugins_in_precompiled_script_plugins[need to be added as implementation dependencies] before they can be applied in a precompiled script plugin:
====
include::sample[dir="kotlin",files="buildSrc/build.gradle.kts[tags=repositories-and-dependencies]"]
include::sample[dir="groovy",files="buildSrc/build.gradle[tags=repositories-and-dependencies]"]
====

* The dependency artifact coordinates (GAV) for a plugin can be different from the plugin id.
* The Gradle Plugin Portal (`gradlePluginPortal()`) is added as a repository for plugin dependencies.
* The plugin version is determined from the dependency version.

Once the dependency is added, the external plugin can be applied in precompiled script plugin by id:
====
include::sample[dir="kotlin",files="buildSrc/src/main/kotlin/myproject.java-conventions.gradle.kts[tags=apply-external-plugin]"]
include::sample[dir="groovy",files="buildSrc/src/main/groovy/myproject.java-conventions.gradle[tags=apply-external-plugin]"]
====

=== Applying other precompiled script plugins

Precompiled script plugins can apply other precompiled script plugins.

The `myproject.library-conventions` plugin applies the `myproject.java-conventions` plugin:
====
include::sample[dir="kotlin",files="buildSrc/src/main/kotlin/myproject.library-conventions.gradle.kts[tags=plugins]"]
include::sample[dir="groovy",files="buildSrc/src/main/groovy/myproject.library-conventions.gradle[tags=plugins]"]
====

=== Using classes from the main source set

Precompiled script plugins can use classes defined in the main source set of the plugins project.

In this sample, `myproject.library-conventions` plugin uses a custom task class from `buildSrc/src/main/java` to configure library README checks:
====
include::sample[dir="kotlin",files="buildSrc/src/main/kotlin/myproject.library-conventions.gradle.kts[tags=use-java-class]"]
include::sample[dir="groovy",files="buildSrc/src/main/groovy/myproject.library-conventions.gradle[tags=use-java-class]"]
====

For more details on authoring custom Gradle plugins, consult the link:{userManualPath}/custom_plugins.html[user manual].
