Upgrading build environments from prior versions of Niagara

Overview

Starting with Niagara 4.13, the build environment for building your Niagara 4 modules has significantly changed, including a major Gradle update from Gradle 4 to Gradle 7. Unfortunately, these changes are not backwards-compatible and will require you to make changes to your existing build environments for them to continue working. These changes have been made with future stability in mind, and this document will be updated as needed to reflect any future breaking changes in the build environment.

This document will walk you through the process of upgrading your build environment from Gradle 4 to Gradle 7 to build against Niagara 4.13.

Breaking changes

While it is not necessary, it is recommended to also consult the Gradle Upgrade Guide as many of the changes there are also applicable here. While the highlights are presented here, you may need to consult the Gradle updating guide if you have done any custom steps outside of the typical Niagara Gradle environment.

Removal of ‘compile’ and ‘runtime’ configurations

Gradle has removed the compile and runtime configurations in Gradle 7, as well as any derived configurations (for Niagara, this includes niagaraModuleTestCompile and niagaraModuleTestRuntime) Their recommended replacements are not quite applicable for building a Niagara module. A table of replacements is given below:

Gradle 4 Gradle 7
compile(project(“:…”)) api(project(“:…”))
runtime(project(“:…”)) runtimeOnly(project(“:…”))
niagaraModuleTestCompile(project(“:…”)) moduleTestImplementation(project(“:…”))

Note that depending on external dependencies has not changed as the Niagara build environment requires all external dependencies to be declared as uberjar or testUberjar.

If you have previously used compile or runtime to pull in dependencies that are provided by the Niagara Runtime Environment in !bin/ext, such as BouncyCastle, you should replace those with nre or testNre, respectively. For Niagara modules, api dependencies can only be on other Niagara modules.

Replacement of ‘niagaraModule’ extension

The niagaraModule extension has been replaced with a more specific set of extensions: the moduleManifest extension, which controls the contents of the module.xml manifest for your module; and the niagaraSigning extension for configuring module signing, replacing certAlias in the old niagaraModule extension. For the most part, you can replace niagaraModule with moduleManifest in your existing build scripts, as the vast majority of the methods on this extension have not changed.

Additionally, some information about the module parts of a single module has been moved into a separate niagara-module.xml file. This file contains information about what parts a module has, as well as some shared metadata that must be consistent between module parts. It replaces the moduleParts { } block of niagaraModule, as well as the preferredSymbol field. This will make misconfigurations (e.g, declaring a module part without a matching Gradle project) fail the build immediately rather than allow them to be runtime issues once your module is deployed.

Removal of ‘environment.gradle’

The environment.gradle file used to configure the location of Niagara for building against has been removed. Its functionality has been replaced with Gradle properties, which can be specified in a gradle.properties file at the root of your build.

Removal of ‘vendor.gradle’

The vendor.gradle file used to configure vendor-specific information has been replaced with a vendor extension in the root build.gradle.kts file.

Deprecated support for most tags in ‘module-include.xml’

module-include.xml and moduleTest-include.xml should only contain <types>, and with few exception should be generated by the build process and not edited manually. Support for defs, lexicons, installation, and finer-grained dependencies has been added to the new moduleManifest {} extension instead. You can see all the supported options in the relevant section of Building Niagara

New Features

While there are some major breaking changes as outlined above, there are also several new features and improvements available in Gradle 7.

Manage signing profile entirely within Gradle

There are now Gradle tasks for managing signing profiles, including generating new profiles, creating new certificates, and importing signed certificates from commercial vendors. It is no longer necessary to use keytool to manage profiles. The Code Signing Guide has been updated to reflect the new commands; you can read that for more information.

Full support for parallel Gradle builds

All plugins used to build Niagara modules are now parallel-safe. This allows you to run Gradle with the --parallel flag, which can result in a significantly faster build, especially for larger projects.

Support for JaCoCo code coverage

Niagara test modules can now be run via Gradle to get JaCoCo test coverage reports. Once you have set up a new environment using the upgrade guide, you can run the following commands to test your module with coverage and generate an HTML report.

gradlew :my-module-rt:niagaraTest
gradlew :my-module-rt:jacocoNiagaraTestReport

This will output a report in my-module/build/reports/jacoco that you can load in any web browser.

Declare brand dependencies for modules

It is now possible to declare a brand dependency for your modules, which will prevent them from being installed on any platform which is not of the same brand. While it is generally preferable to use license checks to enforce this, you do now have the option by adding the following to the moduleManifest block in any module build script:

moduleManifest {
  ...
  (dependencies) {
    create("brand") {
      dependency {
        name.set("Acme")
      }
    }
  }
  ...
}

Upgrading from Gradle 7.3 to 7.6 (Niagara 4.13 to 4.14)

The upgrade from 7.3 to 7.6 is straightforward: You only need to update your settings.gradle.kts file with the new plugin versions. Change the following:

  val gradlePluginVersion: String = "7.3.40"
  val settingsPluginVersion: String = "7.3.0"

to this:

  val gradlePluginVersion: String = "7.6.17"
  val settingsPluginVersion: String = "7.6.3"

Additionally, starting with Gradle 7.6 in 4.14, it is no longer required to specify any “vendor” when depending on modules outside of your build. See the Dependencies section for more details.

Upgrading the easy way: the New Module Wizard

By far the most straightforward approach to migration is to generate an empty shell using the New Module Wizard in Workbench. Once you have created the shell of a project, you can just copy your entire src and srcTest folders to the new module directory. You will also need to copy any module.palette, module.lexicon, and module-permissions.xml files. You should not need to copy module-include.xml as that will be automatically generated when your module is compiled, but you will need to copy any manual changes to that file.

For modules containing JavaScript, you can follow the same general steps of ‘create a new module part and copy your existing source into it’ by following the instructions at Building JavaScript Applications for Niagara. Be sure to pay attention to any changes you need to make to package.json and Gruntfile.js in addition to the other files outlined above.

Once you have moved your source, you can edit the newly-generated gradle.kts file to specify your module’s dependencies. Be sure to consult the major changes section above – specifically regarding the removal of compile – when you do so.

Upgrading from Gradle 4 (Niagara 4.6 though 4.12)

Again, the recommended approach is to start fresh and copy files from your existing builds as needed. These steps outline the full process for manually updating your environment, and can be used as a reference if you run into any issues.

Replace ‘environment.gradle’ with ‘gradle.properties’

First, you’ll need to replace ‘environment.gradle’ with a ‘gradle.properties’ file. This will tell the Gradle build where your Niagara installation is located, among other things. If you already have a ‘gradle.properties’ to configure Gradle options, you can just add the needed properties to your existing file.

At a bare minimum, you must define the niagara_home, niagara_user_home, and org.gradle.java.installations.paths properties, pointing to your Niagara installation. You can find the values appropriate to your installation by running nre -version from a Niagara Console; they are niagara.home, niagara.user.home, and java.home. Be sure to escape "" as “\” if you’re building on Windows:

#The path of the Gradle plugins if they are not in niagara_home
#NOTE: Be sure to escape '\' as '\\' in paths
#gradlePluginHome=C:\\path\\to\\gradlePlugins

#The path to the installation of Niagara you are building against
#NOTE: Be sure to escape '\' as '\\' in paths
niagara_home=

#The path to niagara_user_home for the installation of Niagara you are building against
#NOTE: Be sure to escape '\' as '\\' in paths
niagara_user_home=

#Uncomment and set to the path to your node install if it is not available on your PATH
#NOTE: Be sure to escape '\' as '\\' in paths
#nodeHome=


#NOTE: Most Niagara module builds will require a full JDK, not just the minimal
#toolchain available as part of your Niagara install. The configuration below sets
#up that toolchain, but if you find this is not sufficient you will need to configure
#a valid JDK. You can see what toolchains Gradle can find automatically by running
#
#  "gradlew -q javaToolchains -Porg.gradle.java.installations.auto-detect=true".
#
#If that list includes a valid Java 8 JDK, you can comment out the following three
#properties and let Gradle select a JDK automatically. If it does not, you can set
#the 'org.gradle.java.installations.paths' property to the full path to a Java 8 JDK
org.gradle.java.installations.auto-detect=false
org.gradle.java.installations.auto-download=false

#Set this to the path of the "jre" folder in your Niagara installation, or to a Java
#8 JDK as discussed above
#NOTE: Be sure to escape '\' as '\\' in paths
org.gradle.java.installations.paths=

You can use gradlePluginHome to specify a different path to look for the Niagara Gradle plugins; this can be used to leverage the newer Gradle build environment in building against older Niagara modules. The Gradle build environment shipped with Niagara 4.13 can build modules for Niagara 4.10 and newer; see the appendix for more details.

You will need to set nodeHome if you are developing JavaScript UI components. Consult the grunt-niagara documentation for more details.

Replace settings.gradle

Next, we need to replace ‘settings.gradle’ with an updated ‘settings.gradle.kts’.

Note: If you have lots of projects, you may want to migrate them one at a time. You can do this by replacing the single findProjects() call in settings.gradle.kts with several, each referencing a folder containing projects. For example, if you have 3 modules ‘moduleA’, ‘moduleB’, and ‘moduleC’, you can just work on ‘moduleA’ by calling findProjects("moduleA") – this will only search the ‘moduleA’ folder when discovering projects.

Replace build.gradle

We also need to replace ‘build.gradle’ with an updated ‘build.gradle.kts’. For the most part, ‘build.gradle.kts’ has been greatly simplified; most of the previous contents are handled automatically by plugins.

Replace ‘vendor.gradle’

As mentioned, the ‘vendor.gradle’ script is no longer used. Instead, you will find the vendor extension in ‘build.gradle.kts’ where you can configure these options instead:

vendor {
  // defaultVendor sets the "vendor" attribute on module and dist files; it's
  // what's shown in Niagara when viewing a module or dist.
  defaultVendor("...")

  // defaultModuleVersion sets the "vendorVersion" attribute on all modules
  defaultModuleVersion("...")
}

defaultVendor should be set to the value of group in ‘vendor.gradle’, and defaultModuleVersion set to the value of moduleVersion. As the name implies, this just sets the default value of these; you can change both on a per-module basis using the moduleManifest extension if you need to. More complex options, such as managing versions automatically in a CI environment, or patch versions, are not provided by the Niagara plugins. Several options exist in the Gradle ecosystem for managing these and any one of them should work fine with your build.

Configure signing

All signing configuration can now be done in the root ‘build.gradle.kts’, and this is the recommended way going forward. You find more detail about how to configure this in the Code Signing Documentation

Update module build scripts

Fix dependency declarations

As mentioned, compile and runtime are no longer supported. runtime in general does not work with Niagara modules anyway, and it (and its replacements) should not be used. For other configurations:

Additionally, you can safely remove versions from module dependencies:

dependencies {
  // this
  api(":baja")
  // not this
  // api("Tridium:baja:4.13")
}

Specifying versions for dependencies on modules in !modules has never made sense, since regardless of the version specified, the version used is whatever is in !modules.

Replace ‘niagaraModule’

This should be straightforward – replace niagaraModule with moduleManifest. You will need to then remove the certAlias, preferredSymbol, and moduleParts sections and replace them as outlined below.

Configure signing

certAlias has been replaced with the options documented in the Code Signing Documentation. You can follow the steps there to configure the aliases your build uses, and configure per-module signing if that is required for your use case.

Generate niagara-module.xml

You need to create a ‘niagara-module.xml’ in your module’s folder (not your module parts’ folder – see the build layout documentation )

This file defines shared configuration for all parts of your module – the module’s name, its preferred symbol, and the list of parts it has. This must match the layout of your module on disk. Defining a module part that does not exist, or having a module part project that is not declared, will result in build errors.

<?xml version="1.0" encoding="UTF-8"?>
<niagara-module moduleName="myModule" preferredSymbol="mmod" runtimeProfiles="rt,ux,wb"/>

Build and test

At this point, your module should be ready to build with gradlew moduleTestJar. If you run into any issues, check that you’ve followed the steps above correctly, and consult the Gradle documentation for potential resolutions.

Upgrading from Gradle 1.6 or Gradle 2.13 (Niagara 4.0 through 4.4)

Niagara 4.4 and earlier used a very rudimentary build environment. You must start with a shell generated by the New Module Wizard to migrate these effectively.

Example Gradle Files

The building Niagara guide has a full set of example Gradle files you can use as templates if needed.

Appendix: Using the newer environment with older Niagara

It is possible to use the Gradle build environment shipped with Niagara 4.13 and newer to build against Niagara 4.10 and newer. This can be done by customizing ‘gradle.properties’. For this example, we’ll assume we want to build 4.10U3 modules against a Niagara installation at C:\Niagara\Niagara-4.10.3 using the toolchain shipped with C:\Niagara\Niagara-4.13.0. The following gradle.properties file will configure this setup:

#The path of the Gradle plugins if they are not in niagara_home
#NOTE: Be sure to escape '\' as '\\' in paths
gradlePluginHome=C:\\Niagara\\Niagara-4.13.0\\etc\\m2
#The path to the installation of Niagara you are building against
#NOTE: Be sure to escape '\' as '\\' in paths
niagara_home=C:\\Niagara\\Niagara-4.10.3
#The path to niagara_user_home for the installation of Niagara you are building against
#NOTE: Be sure to escape '\' as '\\' in paths
niagara_user_home=C:\\Users\\user\\Niagara4.10\\brand
#Uncomment and set to the path to your node install if it is not available on your PATH
#NOTE: Be sure to escape '\' as '\\' in paths
#nodeHome=
#AUTOMATICALLY GENERATED BY GRADLE -- DO NOT MODIFY
org.gradle.java.installations.auto-detect=false
#AUTOMATICALLY GENERATED BY GRADLE -- DO NOT MODIFY
org.gradle.java.installations.auto-download=false
#Set this to the path of the "jre" folder in your Niagara installation
#NOTE: Be sure to escape '\' as '\\' in paths
org.gradle.java.installations.paths=C:\\Niagara\\Niagara-4.10.3\\jre

Note that we use the 4.10U3 JRE, and not the 4.13 JRE, when building modules for 4.10U3.