Key Takeaways
- JReleaser intends to streamline the release and publishing process of Java binaries in such a way that these binaries may be consumed by platform-specific package managers (ZIP, TAR or JAR file).
- JReleaser lets you publish binaries to Homebrew, Scoop, Snapcraft, Chocolatey, among others.
- Publishing with JReleaser will ensure the creation of the changelog from the most recent tag, checksums calculation, PGP signature if signing is enabled, Docker image creation and publishing based on the Dockerfile created following the provided templates.
- JReleaser may be used out-of-the-box with Maven, Gradle, Bach, and Ant. For those using custom build tools, JReleaser exposes a ToolProvider interface of its own, making it simple to integrate. This is exactly what the Bach build tool does today.
Regardless of the type of project you are writing, be it a microservices application, mobile application or even native applications, you need to ensure that your code is properly packaged and distributed via the appropriate channels to reach its audience. Currently, services are pushing to have development times as short as possible and to reach an audience as broad as possible.
Andres Almiray, principal product manager at Oracle, had a quest to learn the Go programming language. This led him to discover GoReleaser, a release automation tool for Go projects, and the impact it was having on the Go ecosystem. Almiray was also inspired by a discussion with Max Raydahl Andersen, distinguished engineer at Red Hat, about the manner in which JBang handled its releases. These experiences led to the concept of JReleaser, a build and distribution tool for the Java ecosystem similar to what GoReleaser has been doing for the Go ecosystem. After only a couple of months of development, Almiray introduced JReleaser to the Java community in April 2021. Since then, Almiray has released three versions (one every other week and managed by JReleaser itself) that currently stands at version 0.4.0. More recent versions helped make JReleaser even more versatile by ensuring Java Runtime support for MacOS, Windows, Linux (glibc) and Linux (musl) commonly known as Alpine Linux. JReleaser currently integrates with 14 CI tools and it provides the option to upload artifacts to JFrog’s Artifactory repository manager and custom HTTP servers.
To get a better understanding of JReleaser’s mission and how it can make life easier for software developers, InfoQ reached out to Almiray for a closer look at what it is and how it can provide an easier way to manage Java projects.
InfoQ: Thank you for taking the time to answer the questions for our readers. What are your current day-to-day responsibilities? Is there a connection between your daily job and JReleaser?
Almiray: Thank you for having me. I’m a senior principal product manager at Oracle’s Database group, which may be shocking news to some as I’ve got a track record working with Java for the past 25 years; I even became a member of the Java Champions program in 2010. The reason for joining the Database group is to continue building bridges between the Oracle database products and the Java community, and as such, I make a point of keeping tabs on popular open-source projects, talk to developers, and bring back that valuable feedback to our internal teams. As an aside, I also continue working on open-source projects which I’ve been involved in for years before joining Oracle for a second time. JReleaser happens to be one of those open-source projects born out of necessity to keep other projects up to date. That being said, there is no direct relationship between my current day job and JReleaser other than it’s written in Java and I use Java at work.
InfoQ: What was the inspiration for JReleaser and how did you get started?
Almiray: Years ago, I published an open source project called Ikonli that happens to be quite popular in the JavaFX space. This project provides icons that can be embedded in a Swing or JavaFX application. As time passed by, the number of icon packs grew, which made it difficult to figure out which icons could be added to an application. Ikonli provides HTML documentation with icon cheatsheets, but I longed for an application that would do the same, an icon browser, if you will. Building such an application with JavaFX is fairly straightforward, however making it available to anyone for consumption is the tricky part. How do you package and publish an application that requires platform-specific binaries? Do you assume the user will have the correct version of Java to run the application? Do you bundle a Java Runtime with the binaries? Is it enough to publish ZIP files or are platform package managers a better fit? I kept looking for answers to these questions when I stumbled upon two other projects: JBang and GoReleaser.
JBang is a Java-based project that is packaged for several distribution channels such as Homebrew, Scoop, Chocolatey, Docker, and more. It kind of solves most of the questions I had with Ikonli, but the build automation requires some work as the setup requires a lot of effort to be applied to another project. In other words, the setup is unique to JBang’s needs. GoReleaser, on the other hand, provides exactly what I was looking for except that it only works for Golang projects.
One afternoon, Max Andersen (creator of JBang) and I were chatting about build setup, releases, and other geeky stuff when it dawned on us: what if there was a Java-friendly version of GoReleaser? That is, a tool that would let you package, release, and publish Java projects in a similar manner as GoReleaser does for Golang, but instead support Java? What if this tool were to leverage the lessons learned by JBang to get to where it is today? And that’s how JReleaser came to be.
InfoQ: What is its mission? What type of projects is it built for?
Almiray: The original mission of JReleaser is to streamline the release and publishing process of Java binaries in such a way that these binaries may be consumed by platform-specific package managers, that is, provide a ZIP, TAR, or JAR file. JReleaser will figure out the rest, letting you publish binaries to Homebrew, Scoop, Snapcraft, Chocolatey, and more. In other words, JReleaser shortens the distance between your binaries and your consumers by meeting them where they prefer to manage their packages and binaries.
Early in JReleaser’s design, it became apparent that splitting the work into several steps that could be invoked, individually or as one single unit, would be a better approach than what GoReleaser offers today. This design choice allows developers to micromanage every step as needed to hook-in JReleaser at a specific point of their release process without having to rewrite everything. For example, you can fire up JReleaser and have it create a Git release (GitHub, GitLab, or Gitea) along with an automatically formatted changelog, or you can tell JReleaser to append assets to an existing Git release that was created by other means, or perhaps you’re only interested in packaging and publishing a package to Homebrew regardless of how the Git release was created.
The ability to invoke steps, individually or as a whole, gives you plenty of elbow room to play with. And not only that, it also gives you the option to apply JReleaser to any type of project, not just Java projects. For example, you can use it to craft Git releases no matter if the project is Java-based or not; you can also configure JReleaser to run on any CI software that exists out there.
Of course, if the project happens to be Java-based, you get additional benefits as the package management is currently specialized for this kind of project. It goes without saying that if the project happens to be Golang based, then it’s better to stick with GoReleaser as it delivers Golang specific features that JReleaser does not.
In summary, any project that would like to create and announce Git releases will benefit from JReleaser. If it happens to be a Java project, then it gains additional benefits. CLI applications such as those implemented with PicoCLI, Micronaut, Quarkus, or Spring Boot can certainly take advantage of those added benefits. It also goes without saying that JavaFX applications get a boost as well.
InfoQ: You can easily imagine how JReleaser could be used for open-source projects. What would be different in private projects?
Almiray: Glad you asked. I’m happy to say that there’s no difference at all. JReleaser may be customized to support enterprise versions of the Git release software of your choice. Its documentation suggests the use of OSI-approved licenses and SPDX identifiers because those are required by specific package managers, however JReleaser does not validate those licenses. You may use any licensing scheme the project may require. JReleaser also supports a wide range of CI services, making no distinction between their free and paid offerings.
InfoQ: Does JReleaser rely on itself to manage its own releases?
Almiray: Yes! Since the first release, JReleaser has been released using a snapshot version of itself. As a matter of fact, JReleaser’s build is set up in such a way that it produces early-access releases on every push to its Git repository. These early-access releases are created with the previous snapshot version of JReleaser, Inception.
InfoQ: Would you recommend developers adopting JReleaser? Or should we proceed with care?
Almiray: JReleaser builds on top of the lessons learned by GoReleaser, JBang, and every other open-source project I worked with in the past. There’s a lot of history in there despite the codebase being relatively young in comparison. Because JReleaser uses itself for releasing, every so often it means we can catch problems early on during development. Of course, other projects have different needs and that’s where we get inspiration for new features and behavior. I certainly encourage others to give it a try. Don’t be fooled by its current version number, JReleaser packs a punch!
InfoQ: Can you give us some tips for quickly getting started?
Almiray: Perhaps the best place to start is to have a look at the Quick Start guides, then proceed with DSL configuration, and some of the examples found in the guide. I’m fond of convention over configuration thus I like it when a tool makes most choices for me. However, I also like when I can make my own choices and conventions. For this reason, JReleaser supports several ways to configure itself: you may use external DSLs with YAML, TOML, or JSON formats when running on CLI mode; or you may use the Maven DSL paired with the jreleaser-maven-plugin; or the Gradle DSL paired with the jreleaser-gradle-plugin.
InfoQ: Are there any limitations with JReleaser?
Almiray: Yes, specifically when it comes to multiple platform support. Some packagers, such as Snapcraft and Chocolatey, must run on very specific environments; Linux for the former and Windows for the latter. This means you can’t package for both on the same node. The same goes for GraalVM Native Image binaries, a type of distribution JReleaser also supports, as there’s no current way to generate cross-platform binaries. JReleaser is capable of generating cross-platform Java Runtimes with Jlink as long as there are no platform-specific modules. This puts a dent on creating such runtimes for JavaFX applications as they require macOS, Linux or Windows modules.
The current workaround is to build platform-specific packages and distributions in different CI nodes, collect the results and release them from a single node. Thus, depending on your setup, you may create releases both locally and remotely with the same configuration (no platform-specific packagers, for example) or you may need additional configuration and build servers to build the binaries, losing the option of creating releases locally.
InfoQ: Can you give us a quick tour of what is happening under the hood?
Almiray: Surprisingly, what drives the JReleaser engine is a file template processor. A developer supplies the project configuration as input (the model) which gets processed by each step of the release workflow. Most steps take that input and generate files based on templates, which in turn are also used as inputs for the current step or the next one. For example, the model defines a distribution of type JAVA_BINARY (typically a ZIP file with JAR files and an executable launcher) and activates the Docker packager. Invoking the publish step will perform the following tasks:
- Create a changelog from the most recent tag up to the current HEAD.
- Calculate checksums on the input distribution.
- Create PGP signatures if signing is active.
- Create a Dockerfile based on the supplied templates.
- Create a Docker image based on the resolved Dockerfile.
- Publish the Docker image to the configured server(s).
The model delivers a good number of sensible defaults and requires you to tweak the generated files. But in case that is not enough, you can also supply your own templates, overriding or complementing the default ones.
InfoQ: What was the biggest technical challenge you faced while developing JReleaser?
Almiray: I believe that would be keeping the number of dependencies as low as possible, as well as establishing Java 8 as the minimum supported Java version. Why is that? This is to support running JReleaser as Ant, Maven, and Gradle plugins. I would love to switch to Java 11, fully embrace the Java Module System, and gain access to more recent features added to the Java language. However, playing nice with all build tools requires compromises.
InfoQ: How does it integrate in CI pipelines?
Almiray: Currently there are two easy ways to make it happen. You can either launch JReleaser as a Java process or use its Docker image.
The first form is what the jreleaser/release-action GitHub Action does. It downloads a (configurable) version of JReleaser as a single überjar and executes its main class. This requires a Java Runtime on the target node, in this case a Java 11 Runtime to be precise, as the überjar launches an instance of ToolProvider.
The second form packages a Java Runtime and the JReleaser binaries as a Docker image, allowing you to use it with any CI server that can leverage container images.
The third way, if you really want to make it, is to use a custom download strategy to grab the ZIP or TAR file from the releases page, unpack and execute. Or you could also use SDKMAN! to install it which, at this point, should be no surprise that JReleaser can publish and announce packages to SDKMAN! as well.
InfoQ: Is there a way to customize JReleaser’s usage for custom-built tools? Or some kind of extension mechanism?
Almiray: Right now, JReleaser may be used out-of-the-box with Maven, Gradle, Bach, and Ant. These integrations require a small abstraction over the execution engine. If the build tool relies on Java 9’s ToolProvider interface to customize its behavior then I’ve got news: JReleaser already exposes a ToolProvider of its own, making it really simple to integrate. This is exactly what the Bach build tool does today.
The engine is written in such a way that it’s easy to integrate with any other build tool if the need arises. If that were to be the case, I’d highly encourage those interested in a new integration to join our Discussions page and pitch the idea.
Regardless of the type of project you build, regardless of its complexity or the way it is written, all software projects need a way to manage their releases. Most often than not, the release procedures and processes are either lists of chores that need to be executed automatically, by hand, or with custom-made tools or scripts used inside different companies. With the ever-growing complexity of software products and projects, these are even harder to stitch together in a coherent product or project.
InfoQ: Can you give us an overview about the future of JReleaser? Is there a defined roadmap?
Almiray: The project supports a wide variety of integrations, ranging from: posting releases to GitHub, GitLab, and Gitea; packaging with Homebrew, Scoop, Chocolatey, Snapcraft, JBang, Docker; announcing releases to SDKMAN!, Twitter, Gitter, Discord, Zulip, e-mail, Slack, Microsoft Teams; supporting distribution types such as Java binary, single JAR, Jlink, and GraalVM Native Image.
There are other services that may be integrated in the future, another Git platform perhaps, or maybe yet another platform-specific packager, or an announcement service. Here is where we count on getting feedback from users to let us know which services they may need to integrate with in their projects.
Java 16 added jpackage as an option to create platform-specific installers. That could also be another type of distribution that may be added in the future. After all, some of the outputs produced by jpackage may be distributed with Homebrew (.dmg and .pkg as casks), for example.
Recently, the ability to create a formatted changelog was added, however it does so by only looking at the local commits at the moment. This means we miss metadata that’s available remotely such as pull requests, issue labels, and other data. It may be possible in the future to configure JReleaser to fetch that data before generating the changelog.
InfoQ: April was an important month for JReleaser. It had its initial launch and 0.2.0 followed two weeks later. What are the most significant features so far?
Almiray: Indeed. The project progressed slowly in stealth mode since September 2020 as the contributing team were still bouncing back ideas and testing out hypotheses. By March 2021, we knew we had a sound core and laid out the roadmap for the first release.
Perhaps its most significant feature is its flexibility: JReleaser can decide a lot of things for you if you follow the conventions. You just sit back and let JReleaser drive the release process. But at the same time, you can take the driving wheel and decide how and where you want to go with the release. One size does not fit all in this case, JReleaser strives to support as many use cases as make sense.
This flexibility also translates to its implementation for integrating a new service, packager or announcing tool, which are all quite straightforward tasks.
InfoQ: Currently it looks like a one-man show. Are there any plans to develop a community? Any advice for developers who would like to contribute?
Almiray: It certainly looks like that, doesn’t it? However, the project has had a small set of contributors since the beginning. What I like about JReleaser is that it provides a unified model for creating and publishing binaries regardless of the build tool of choice, the Git hosting service or the CI solution. I’d expect other developers to come to the same conclusion and take the project for a spin, with the likelihood of feedback, feature requests, and patches as a result. We welcome all kinds of contributions, be it issue triaging, documentation, patches, or others.
A good place to start is by participating at our Discussions page and posting a question, or have a look at our issue tracker and provide feedback on an issue or even a patch. It’s always a good idea to start a conversation before working on code, that way we can help you with getting the feature or fix in shape for a speedy merge.
Conclusion
Regardless of the tool you use for organising your project, Maven, Gradle or even Ant, and the channels you use for publishing or announcing your releases, JReleaser’s mission is to glue them together in a cohesive manner and to ensure that everything is operating as expected. With a consistent release cadence once every second week, JReleaser is following on its mission to become the facto tool for release management in the Java world.
About the Interviewee
Andres Almiray is a Java/Groovy developer and a Java Champion with more than 20 years of experience in software design and development. He has been involved in web and desktop application development since the early days of Java. Andres is a true believer in open source and has participated on popular projects like Groovy, Griffon, and DbUnit, as well as starting his own projects (Json-lib, EZMorph, GraphicsBuilder, JideBuilder). Founding member of the Griffon framework and Hackergarten community event.