Working With Gradle - MegaMek/megamek GitHub Wiki

Gradle is a build automation tool used for managing dependencies and packaging releases.

Getting Started

When setting up a workspace managed by Gradle you will need to set up your IDE to work with it. IntelliJ IDEA has robust Gradle support, and will ask whether you want to import Gradle support. Eclipse Photon includes Gradle support, but older versions of Eclipse require the user to download the Buildship plugin. With the plugin installed, right-click on the project in the package explorer and choose Configure > Add Gradle Nature.

The first time it is run as a Gradle project it will take some time as Gradle sources and downloads the dependencies and stores them locally. Gradle handles setting the build and runtime class paths.

Gradle Tasks

Most users will not need to be concerned with the Gradle tasks. In IntelliJ IDEA they can be found on the right sidebar. In Eclipse they are found in the Gradle Tasks view. They can be run from the command line using the gradle wrapper script found in the root directory of the project: gradlew for unix-like systems and gradle.bat for Windows. Running the script by itself will give you a list of basic commands.

Dependencies Between Projects

We have custom repository for maven artifacts set up on GitHub. This is not meant to be checked out, but provides a source for the MegaMek jar used by MegaMekLab and MekHQ, the MegaMekLab jar used by MekHQ, and the MekHQ jar that can be used when developing MekHQ plugins. When working on changes in one project that require changes in one that it depends on, there are two approaches: publishing the dependency locally or configuring the projects as a composite build.

Publishing a Branch Locally

The changes in the dependency can be made available by running the publishToMavenLocal task. It will create an artifact with the branch name appended to the module name (e.g. megamek-branchName). You will need to change the root build.gradle file in the dependent project by updating the relevant property.

Working example: Feature: Large naval support vehicle construction in MegaMekLab. This requires changes in MegaMek to support this unit type. So you create a large_naval_support branch in MegaMek, and run the publishToMavenLocal task, which will create a megamek-large_naval_support artifact in your local repository cache. You also create a large_naval_construction branch in MegaMekLab (The branches don't have to have separate names, but that is done here for clarity). You edit the build.gradle file to change the mmBranch property from master to large_naval_support, which will make it depend on the megamek-large_naval_support module. Any time you need work on the MegMek branch to be available to MegaMekLab, you run the publishToMavenLocal task. There is no need to have that branch checked out in MegaMek in order to use it in MegaMekLab. When the changes are finished and approved, the MML gradle.build file will need to have the mmBranch property changed back to master. The maven repository on GitHub will also need to be updated so that when others pull the updates on the MegaMekLab master branch they will also get the new version of the MegaMek dependency with the necessary support.

Setting up a Composite Build

Publishing a local branch artifact can be convenient because it allows work on the dependent project without needing to check out any particular branch of the parent. But it can be very tedious when needing to make changes in the dependency to test in the child project, and does not allow live swapping of code under a debugger. Gradle allows substitution of projects on the local hard drive for the binary jar dependency. Because users can store projects in varying locations, the user will need to tell gradle where to find the project dependency in the settings.gradle file for the project that has the dependency. For the user's convenience, the settings.gradle file checks for a file name settings_local.gradle and includes it. This file is not tracked by git, so each user can have their own copy of the file that does not interfere with anyone else's. Each project dependency is identified with the line includeBuild '/path/to/project'. For example, if the user has the three project repositories in the same parent folder, and they are named megamek_, megameklab, and mekhq, adding the following to a settings_local.gradle in the mekhq directory would create a composite build of all three projects:

includeBuild '../megamek'
includeBuild '../megameklab'

Important note: Composite builds cannot be nested. If MML is set up as a composite build with MM as its dependency, it cannot be used as a project dependency for MekHQ. To configure both MML and MekHQ as composite builds it is necessary to check whether MML is part of a composite build before including the MM dependency:

if (gradle.parent == null) {
    includeBuild '../megamek'
}

Publishing Artifacts to GitHub

Artifacts need to be published to GitHub when producing a release and when there are changes in one of the projects that depend on changes also made to another project, in which case the latter needs to be published. Publishing should only be done after merging into the master branch. Ongoing work in other branches should fulfill the dependency through the local maven repository. Publishing to the GitHub repository requires commit permissions. The output of the publish task will be found in the build/mavenrepo directory, which can be committed to the root directory of the mavenrepo repository on GitHub using the upload files button on the web interface, then dragging and dropping the top-level org directory into the window. The default commit message will be fine.

Release Procedure

The procedure for generating a release is nearly the same for each project.

  1. Change the version number to the release version by removing -SNAPSHOT from the end. This is done in the docs/history.txt document, the build.gradle file in the root project directory, and in the following location for each project:
  • MegaMek: src/megamek/MegaMek.java
  • MegaMekLab: src/megameklab/com/MegaMekLab.java
  • MekHQ: resources/mekhq.resources/MekHQ.properties
  1. Commit the changes. If not using the clone-from-local option (see below), push the changes.
  2. Run the release task. If building releases for all packages at once, you can run the releaseAll task in MekHQ to build all of them at once. The packages will be found in build/distributions.
  3. Run the publish task in each project and upload to the mavenrepo repository on GitHub as above.
  4. For each project, go to https://github.com/MegaMek/(projectname)/releases/new, set the tag version to the version number, add the release name, copy the change log for that version from the history.txt file, and drop the release packages in the upload window, and click Publish Release.
  5. Increment the version numbers and add -SNAPSHOT to the end and change them as in step 1, adding a new section to the docs/history.txt files. Commit and push.

Cloning from local

The release task clones the repository to get a clean copy. By default it will clone it from GitHub, but if your local copy is up to date you can save time by having it clone from your local copy. If you have a file in the project's root directory named properties_local.gradle, Gradle will load custom options from it but git will ignore it. An example of how to do this for MekHQ, assuming that you have the three project repositories in the same parent directory:

rootProject.ext.hqGitRoot = "${rootDir}/.git"
rootProject.ext.mmGitRoot = "${rootDir}/../megamek/.git"
rootProject.ext.mmlGitRoot = "${rootDir}/../megameklab/.git"