DEV Community

Sualeh Fatehi
Sualeh Fatehi

Posted on

How to Create Platform-Specific Installers for Your Java Applications from GitHub Actions

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)
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
adriens profile image
adriens

Awesome, you finally did it