Java 14 and above ship with the Packaging Tool, jpackage
for packaging self-contained Java applications. This new tool is surprisingly easy to use, and bundles together all the jars for your application, and dependencies into an operating system specific installer. You can create .deb
files on Linux, .MSI
files on Windows, and dmg
on macOS. The Packaging Tool leverages the underlying operating system tools to build the packagers, and you need to have those tools installed. The good news is that GitHub Actions runners come with these tools preinstalled, making it a breeze to use GitHub Actions to generate and publish installers for your application. You do not even have to create launcher shell scripts - this is done on your behalf.
So roughly, here are the steps to get to this level of automation going - first, make sure your build generates a Java jar file from your code, and collects dependencies in one place. Then create GitHub Actions workflows that install Java 14 or better, to checkout your code, build it, run the packager, and publish the installer. Let us get into some details. To follow along, you can take a look at the sample GitHub project, sualeh/build-jpackage which has everything in place.
If you use Gradle, you can collect dependencies pretty easily - just add something like the following to extend your build task to collect dependencies in the build/libs
folder.
task copyToLib(type: Copy) {
into "${buildDir}/libs"
from configurations.runtimeClasspath
}
build.dependsOn(copyToLib)
The next time you run gradle build
, you will see a lot of jars in build/libs
. If you use Apache Maven or Apache Ant, you can do something similar to collect all your dependencies in one place.
Next, set up a GitHub Actions workflow for your project. You need to create a YAML file in .github/workflows
, and check out code, and install Java 14 or better. Checkout and compile your project there, and make sure that it succeeds. The details of how to do this are readily available, so I am not going through them - and in any case you can look at the workflows in the example project. (Please star the project if you find it useful!)
After you study the jpackage
tool command-line options, you can put the options down in a command-line file, such as jpackage.cfg, and create platform specific ones too, such as jpackage-linux.cfg. You will need these in your workflow. If you have jpackage
installed locally, try them out locally too.
After you have made sure that jpackage
runs, add a call to it right after your build.
- id: build
name: Build distribution
run: |
gradle build
jpackage --verbose "@jpackage.cfg" "@jpackage-linux.cfg"
And finally, you are ready to publish. You have a few options here - you can publish it as a build artifact using actions/upload-artifact
, or as a release using actions/create-release
and actions/upload-release-asset
. If you want to publish somewhere else, you can do that too.
Take a look at the complete example workflow, and see how easy it all is, really. If you have been following along, and have this down, then here is a challenge for you. It is always nice to have your application's logo on the installer. However, jpackage
expects you to create this in a platform specific format, for example as an .ico
file on Windows and a .png
file on Linux. As a challenge, create your logo in SVG format, and use Image Magick in GitHub Actions to convert it into an appropriate format for your installer to use. I am still working on this, so if you get there first, please put a comment on this article.
And be sure to star sualeh/build-jpackage!
Top comments (1)
Awesome, you finally did it