-
Notifications
You must be signed in to change notification settings - Fork 14
Upgrade guide
This version of Micronaut Build is a major breaking version. It is intended to be used starting with Micronaut 4, in particular because it bumps the default Java version to 17, but it is possible to use it on older modules, granted that you change the defaults, following the instructions below.
Which version to choose?
- For Micronaut 3.x, select the latest 5.x version
- For Micronaut 4.x, select the latest 6.x version
The 6.5.x release line contains a number of (minor) breaking changes:
- the plugin is now built with Java 17 and Gradle 8. It will no longer work on builds which require Java 11 to build.
- there is no longer a default version for Logback. This used to create a conflict with newer Micronaut releases. You have 3 different options to set the logback version (which is used only in tests):
- (preferred) set
micronaut-logging
version in yourlibs.versions.toml
file. This will automatically import themnLogging
catalog and add logback to your test implementation dependencies. For other scopes,you can use themnLogging.logback.classic
dependency notation. - set
logbackVersion
in yourgradle.properties
file - set
logback
in the[versions]
section of yourlibs.versions.toml
file
This release supercedes the 6.3.x line. It contains a lot of bugfixes and minor changes. It is no longer maintained.
This release is superceded by the 6.5.x branch. It is no longer maintained.
This release is compatible with Gradle 8. It also provides for an optional breaking change known as "standardized project names". If you upgrade to this version, your project will emit warnings like these:
=========================================================
Standardized project names are disabled.
Consider enabling them with
micronautBuild.useStandardizedProjectNames=true
in settings.gradle.
Then you will need to replace project dependencies from
project(':foo')
to
project(':micronaut-foo')
in your build scripts
=========================================================
Standardized project names is a first step towards simplifying composite build support with Gradle. One of the issues we have today is that project names differ from their GAV coordinates, which makes it non trivial to support composite builds. By enabling standardized project names, the project names will change to match the GAV coordinates, which means that their short name will start with micronaut-
. This change is not applicable to test suite projects (projects starting with test-suite-
.
As soon as you enable this feature, you will need to rewrite project dependencies from project(':foo')
to project(':micronaut-foo')
.
This release is compatible with Gradle 7.
This release is not maintained anymore, please upgrade to 6.2.x.
The build now defaults to Java 17.
If you say nothing, the build will target Java 17 features and bytecode level.
Builds will also use Java toolchains by default.
It is possible to set a different language level for a project by changing the micronautBuild
configuration in a project's build.gradle
file:
micronautBuild {
javaVersion = 11 // override the default version to 11
}
Note that if a project was using the sourceCompatibility
or targetCompatibility
properties, a deprecation warning will be issued.
Instead of:
micronautBuild {
sourceCompatibility = "11"
targetCompatibility = "11"
}
you should write:
micronautBuild {
javaVersion = 11
}
The build now supports building against Groovy 4.
Before release 6.0, there was a resolution rule to force the Groovy version of the whole project to the version specified in the build (via a resolutionStrategy
rule).
This rule is now removed: in case of a conflict, each project needs to deal with the conflict appropriately.
The reason to avoid using a rule is that consumers do not inherit from the rule, so it could lead to runtime issues.
- build has been updated to remove deprecated Gradle API usages
- the PDF generation task has been removed
- builds should be compatible with the configuration cache (starting with Gradle 7.6)
- the dependency updates plugin has been removed (we use our own version catalog update task)
This version introduces 2 potentially breaking changes:
- a binary breaking change automated test: if a binary incompatible change is discovered, the build will fail, see below how to configure
- BOM validation is now stricter and will fail by default instead of warning
The check
phase now triggers API breaking change verification. If the plugin discovers an API breaking change, it must be accepted explicitly via the config/accepted-api-changes.json
file.
In addition, the plugin provides an extension which can be used to configure the location to the accepted changes file, to completely disable validation for a module, or explicitly set the baseline version instead of checking via GitHub releases:
micronautBuild {
binaryCompatibility {
enabled = true // this is the default
acceptedRegressionsFile = file("path/to/another/json.file")
baselineVersion = "1.0-explicit-version"
}
}
BOM validation is stricter and will make sure that:
- all dependencies which appear in a BOM are valid, in the sense that they exist in Maven Central for the specified version
- all imported BOMs only declare dependencies on the same group as they belong to, unless it's a Micronaut BOM
In some rare cases, it may be necessary to explicitly accept BOMs which break those rules. This can be done via the suppressions
block of the micronautBom
extension:
micronautBom {
suppressions {
dependencies.addAll([
"io.micronaut.kubernetes:micronaut-micronaut-kubernetes-operator:3.3.0",
"io.micronaut.oraclecloud:micronaut-oraclecloud-sdk-processor:2.0.4",
"io.micronaut.data:micronaut-data-document-tck:3.3.0-RC1",
"io.micronaut.data:micronaut-data-tck:3.3.0-RC1",
"io.micronaut.serde:micronaut-serde-tck:1.0.0-RC2",
"io.micronaut.servlet:micronaut-test-kotlin-jetty:3.2.0"
])
bomAuthorizedGroupIds.put("io.r2dbc:r2dbc-bom", ["com.google.cloud", "org.mariadb", "dev.miku"] as Set)
}
}
The dependencies
property lets you accept some dependencies which would have failed validation. The bomAuthorizedGroupIds
is used to declare, for a particular non-Micronaut BOM, what group ids it can specify. For example, the io.r2dbc:r2dbc-bom
would normally only be allowed to have dependencies on modules living in io.r2dbc
. In practice, it's not the case and we have no choice but accepting that it gives recommendations about other groups.
The most notable change of Micronaut Build 5.2 is the integration with Sonar Cloud via the SonarQube, JaCoCo and JaCoCo Report Aggregation plugins. It is all handled by 2 new internal plugins:
-
io.micronaut.build.internal.quality-checks
:- Applied automatically by the
common
plugin; configures Checkstyle, JaCoCo and Sonar.
- Applied automatically by the
-
io.micronaut.build.internal.quality-reporting
:- To be applied to the root project only; it consumes and aggregates the reports produced by the
quality-checks
plugin.
- To be applied to the root project only; it consumes and aggregates the reports produced by the
Note that Micronaut Build 5.2.x requires Gradle 7.4 or higher.
To use this version, simply add the io.micronaut.build.internal.quality-reporting
plugin to the root project:
plugins {
id "io.micronaut.build.internal.docs"
id "io.micronaut.build.internal.dependency-updates"
id "io.micronaut.build.internal.quality-reporting"
}
The 5.1 release of Micronaut Build plugin reworks how Javadocs are aggregated and adds support for the remote build cache. It should be straightforward to upgrade from 5.0.x but you should double check that the generated javadocs are ok.
Note that 5.1 also enables forked compilation by default. If, for some reason, memory limits are not appropriate for your project, you can tweak the maximum memory allocated to worker compilers in the project module convention plugin:
micronautBuild {
compileOptions {
maxMemory = "512m"
}
}
In order for the remote cache to be configured correctly, you will also have to upgrade to the latest GitHub workflows templates.
The 5.x release of the Micronaut Build plugins provides a number of improvements aimed at making builds faster, cacheable and more maintainable. As a consequence, it is a potential breaking change to upgrade to this release. This page is here to guide you through the upgrade process.
Last update: Micronaut Build 5.0.3
Notable changes include:
- removal of the cyclic dependency between
micronaut-build
andmicronaut-inject
- a reworked docs plugin which works in phases instead of tasks overwriting each other outputs
- a new bom plugin to greatly simplify generation of BOMs
Upgrading should be relatively straightforward if the project doesn't customize docs publication.
We're going to illustrate the changes with the Micronaut AWS project and you can look at the following pull requests for examples of upgrades:
The first thing to make sure is that you have the settings plugin applied in the settings.gradle
file:
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
plugins {
id 'io.micronaut.build.shared.settings' version '5.0.2'
}
then take a look at other build scripts. If you see references to micronaut-build
like this, remove the buildscript
block as we're going to rely on the plugins
block instead:
// Remove this `buildscript` block as it is redundant
buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath "io.micronaut.build.internal:micronaut-gradle-plugins:4.0.1"
}
}
Cross-configuration is the process of configuring different projects from a single one (typically the root project).
This is typically found in the root project, with an allprojects
or subprojects
block.
This pattern used to be popular but has a number of drawbacks:
- it is difficult to figure out, for a particular project, what plugins it applies
- multiple
allprojects
andsubprojects
blocks can be applied from any build script, making it hard to trace where a change comes from - it is inherently unsafe, in particular with regards to parallelism
- it doesn't properly decouple configuration of projects, leading to performance issues
- it leads to dirty workarounds like
if (project.name == 'docs')
which are hard to debug
The new pattern is to use convention plugins. Each project should tell what is is, which is best illustrated by having a plugins block on top of each module:
plugins {
id 'io.micronaut.build.internal.aws-module'
}
Which basically says "I'm a Micronaut AWS module": not a test suite, not a BOM, but a regular module.
The root build.gradle
file should in the end only apply the following plugins:
plugins {
id "io.micronaut.build.internal.docs"
id "io.micronaut.build.internal.dependency-updates"
}
The dependency-updates
plugin is a legacy plugin which will eventually be replaced with version catalog updates once modules migrate to version catalogs.
The docs
plugin is here to generate the documentation of a Micronaut project (aggregated javadocs, user manual, ...).
One drawback of getting rid of the allprojects
block is that for simple things like the group = "io.micronaut.aws"
statement, you'd now have to copy that into every build file.
We can avoid that: notice that this io.micronaut.build.aws-module
is a project local plugin declared in buildSrc
.
It's itself composed:
/**
* Plugin for AWS modules.
*/
plugins {
id "io.micronaut.build.internal.aws-base"
id "io.micronaut.build.internal.module"
}
This plugin says that an AWS module is nothing but a regular Micronaut module (something configured with our conventions for checkstyle, publication to Maven Central, ...) as well as another plugin called aws-base
.
What does that aws-base
plugin do? Let's see:
version projectVersion
group "io.micronaut.aws"
This is the plugin which actually sets the version and group of all modules, so that you don't have to repeat yourself. This is the composition over inheritance model.
Note: since 5.0.2 the alternative is actually to set the projectVersion
and projectGroup
in the root gradle.properties
file. The plugin will automatically take care of setting the group
and version
on all modules.
So we have this "aws module" plugin for libraries, but what about the BOM file?
This is where the new BOM plugin comes handy.
The Micronaut Build 5.0.0 release comes with a new BOM plugin called io.micronaut.build.internal.bom
.
It is responsible for generating a BOM file for your multi-project build.
By default, it is designed to aggregate all micronaut modules from your multi-project build, and will exclude by convention test modules (test-suite-xxx
).
Note that if your project uses a version catalog, then this plugin can generate a BOM in a similar way to what the micronaut-core
project does (with the convention for managed
dependencies).
So, here's what the aws-bom
build file looks like now:
plugins {
id 'io.micronaut.build.internal.aws-base'
id 'io.micronaut.build.internal.bom'
}
Note that it applies the BOM plugin, but it also applies the aws-base
plugin (which will set the group and version, if you remember).
Last but not least, we also have a number of test suites.
For now the micronaut-build
project doesn't define any particular plugin for declaring a test suite project, but we can do it.
This is the io.micronaut.build.internal.aws-test-suite
plugin:
/**
* Plugin for test suite projects.
*/
plugins {
id 'io.micronaut.build.internal.aws-base'
id 'java'
}
repositories {
mavenCentral()
}
This plugin again applies the base
plugin, but this time it's a simple java
project.
We also declare repositories here, so that we don't have to repeat in each build file.
The test-suite
project then only needs to tell what it is:
plugins {
id 'io.micronaut.build.internal.aws-test-suite'
}
dependencies {
...
}
The documentation generation process has been completely reworked in order to make it incremental and cacheable. Before the changes, the docs generation was very messy, with different tasks overwriting each other outputs, and lots of fragile explicit dependsOn declarations so that "things work" which were either redundant or incorrect.
The new process is cleaner and works in stages.
If you run the docs
task, then you will see in the build/docs
directory the result of all previous phases.
You must not have a task which touches the contents of the docs
directory, but you should have a task which creates intermediate contents instead.
The intermediate contents can be seen in the build/working
directory:
./build/working/00-api
./build/working/01-includes
./build/working/02-docs-raw
./build/working/03-property-ref
./build/working/04-assembled-docs
./build/working/05-dropdown
- the
00-api
directory contains the generated javadocs. - the
01-includes
directory contains the individualconfigurationProperties
files from subprojects - the
02-docs-raw
directory contains the result of theasciidoctor
generation for the project - the
03-property-ref
directory contains the generated property reference file generated from the includes - the
04-assembled-docs
directory contains the documentation for a single version, assembled with javadocs and configuration reference: this is a usable output which is used for the documentation zip - the
05-dropdown
directory contains the documentation with the single version replaced with the dropdown version selector
Long story short, if you have a task which used to patch the docs in some way, you should instead create an intermediate directory which takes one or more previous stages as an input, and generates its output in a separate directory. You can take a look at the implementation of the docs plugin for inspiration.
A good way to figure out if your project is doing something wrong is to run the docs
task twice in a row.
The 2d time, everything should be up-to-date and no task should be executed.
If there are tasks executed, best way to figure out what's going on is to generate a build scan (should be automatic if you are registered on ge.micronaut.io
, if you're not, ask @melix) which will tell you why things were re-executed.
It's a good idea to verify what is going to be published after upgrading. Execute:
rm -rf build/repo && ./gradlew pAPTBR
This should generate a Maven repository in build/repo
with the artifacts which would be published.
Make sure that all the artifacts are in the appropriate group and that all modules which should be published are present.
Execute:
rm -rf build/docs && ./gradlew docs
Then open the build/docs/index.html
page.
Check that the dropdown is present, that the javadocs are present as well as configuration property reference.
Some projects make use of the Micronaut Gradle plugin, the one we provide for end-users, for testing.
Starting from Micronaut Gradle Plugin 3.5, the plugins have been refactored in order not to depend from external plugins when not needed.
For example, the plugin would previously download the Kotlin plugin even if the user wouldn't use it.
In most cases, this should be transparent, but there are cases where the build may fail with ClassNotFoundException
, for example:
* What went wrong:
An exception occurred applying plugin request [id: 'io.micronaut.build.internal.docs']
> Failed to apply plugin class 'io.micronaut.build.docs.JavadocAggregatorPlugin'.
> A problem occurred configuring project ':oraclecloud-bom'.
> Failed to notify project evaluation listener.
> org/jetbrains/kotlin/gradle/dsl/KotlinCompile
This problem is caused by a restriction (bug?) in Gradle plugin classloading, happening if we apply the Micronaut Gradle plugin in a convention plugin and that the Kotlin plugins are applied directly in the build.gradle
file (because it would be loaded in a classloader which wouldn't have the Kotlin classes, applied in the build file).
The solution is to refactor the build to introduce convention plugins which will apply the Kotlin plugin and the Micronaut Gradle plugin. One can take a look at this PR for an example of refactoring.