Quarkus update in a gradle multi-module project
I’m ‘chalant’ about this, but it was the least worst option
The experimental quarkus update
(or gradle quarkusUpdate
) seems like a cool feature that really should graduate out of experimental. I’ve been happily using it in my personal projects and it works quite nicely under Linux conditions; Windows not so much. Sadly though, openrewrite the underlying plugin that is used by quarkus to do its thing doesn’t support gradle multi modules very well. I am, by no means, a gradle expert (who among us really is) and it seems that init scripts in a multi-module don’t run under the same conditions as a single module project (relentless banging on keys like a demented monkey hoping for a Shakespeare-esque moment ended in failure).
The reality here is that I have a java monorepo which is built using gradle; some of the parts are Quarkus based, some aren’t. I still wanted to use quarkus update since it isn’t always a simple edit of gradle.properties
when doing the upgrade. This isn’t exciting work yet it might reduce toil for someone so here’s my solution. It’s usable and I’ve used it in to upgrade Quarkus from 3.10 to 3.12.x
- First of all, write a wrapper script that runs
quarkus update --dry-run
and capture the recipe that it’s generated by parsing stdout- It will fail because something something “rewrite not defined as a configuration” (life is too short)
- This relies on gradle not deleting the recipe when it fails (which seems brittle)
WARNING : apt does not have a stable CLI interface. Use with caution in scripts.
springs to mind here.
set -eo pipefail
quarkus_args=()
if ! builtin type -f quarkus >/dev/null 2>&1; then
echo "No Quarkus; nothing to do"
exit 2
fi
if [[ -n "$1" ]]; then
quarkus_args+=("--platform-version=$1")
fi
# This will fail with a exitcode=1, but we capture the recipe.
recipe=$(quarkus update --dry-run "${quarkus_args[@]}" 2>/dev/null | grep "OpenRewrite recipe generated" | cut -f 2 -d':' | sed -e "s/^[[:blank:]]*//" -e "s/[[:blank:]]*$//") || true
if [[ -n "$recipe" ]]; then
if [[ "$DRY_RUN" != "true" ]]; then
./gradlew -Dorg.gradle.daemon=false -PquarkusUpdateConfig="$(realpath "$recipe")" rewriteRun
else
echo "Generated $recipe to update quarkus to $1"
fi
fi
- Now we can modify our root gradle project to apply the openrewrite plugin if
-PquarkusUpdateConfig
is set.- Most of the specifics are copied from the Qute template that quarkus itself uses to generate the initialisation script that fails to execute.
plugins{
id 'org.openrewrite.rewrite' version '6.16.4' apply false
}
ext {
quarkusUpdateConfig = project.findProperty('quarkusUpdateConfig') ?: ''
}
if (quarkusUpdateConfig != "") {
apply plugin: "org.openrewrite.rewrite"
repositories {
mavenCentral()
}
dependencies {
rewrite("org.openrewrite:rewrite-java")
rewrite("io.quarkus:quarkus-update-recipes:1.0.18")
}
rewrite {
configFile = quarkusUpdateConfig
activeRecipe("io.quarkus.openrewrite.Quarkus")
plainTextMask("**/*.adoc", "**/src/test/resources/__snapshots__/**/*.java", "**/*.kt", "**/*.md", "**/src/main/codestarts/**/*.java", "**/*.txt", "**/META-INF/services/**")
}
}
Bonus Chatter
You might be wondering about the parsing of the arguments because quarkusUpdate doesn’t have to pay much attention to that if you’re always updating to the latest release. Also what’s all this DRY_RUN
about? The answer is that of course we’re going to bind this into updatecli and into our preferred CI/CD environment to raise PRs and the like.
name: Update Quarkus
# Use maven repo rather than github-release to avoid the requirement for GITHUB_TOKEN
sources:
quarkus:
name: maven artifact release for quarkus
kind: maven
spec:
repositories:
- "repo1.maven.org/maven2"
groupid: "io.quarkus.platform"
artifactid: "quarkus-bom-quarkus-platform-descriptor"
versionfilter:
kind: semver
pattern: "*"
targets:
quarkusUpdate:
name: Update Quarkus to ${{ source "quarkus" }}
kind: shell
sourceid: quarkus
spec:
shell: bash
command: ./.ci/scripts/quarkus-update.sh
environments:
- name: PATH