3 minute read

When you use the version project property and it yields to the unspecified value although you expected it to be something else the reason may be:

  • you are in a multi project scenario and you’re querying a sub-project version property instead of the root projects
  • you have applied as a project plugin instead of a settings plugin

unspecified is the default value for the version standard Gradle property so it’s what you get unless it is set to any other value either statically or dinamically.

Here are solutions to these issues.

Use the right version property or propagate

Let’s assume you have a multi-project hierarchy like:

rootProject
|- subProjectA
|  \- subProjectA1
\- subProjectB

When you get the right version in the rootProject but not in the sub projects that simply means that you need to replace the project.version expressions in your build scripts to rootProject.version. Do this for all the projects in the hierarchy you want the same project version for.

If you want all the projects in the hierarchy to have the same version you may go the other way so, in order to propagate the version from the root project to children, add the following to your root project build script:

subprojects {
    version = rootProject.version
}

If you have applied as a project plugin instead of a settings plugin you may prefer the afterEvaluate version, like:

subprojects {
    afterEvaluate {
        version = rootProject.version
    }
}

Remember that even with this, when using the project plugin version, some properties may still be unspecified, as illustrated below.

Apply the plugin at the settings level

You can apply the plugin as a project plugin or a settings plugin, and here are the differences:

  1. the project plugin is applied in the build.gradle file while the settings plugin is applied in the settings.gradle file. You can use the same plugin DSL to apply and the same grammar to configure
  2. the project plugin should be applied to the root project only, the settings plugin must be applied to the root project only as Gradle restricts the settings.gradle file to appear at the root level only
  3. the project plugin defines tasks for you to use at any time in your build script, the settings plugin does that too, but also triggers inference during the initialization of the Gradle project, before the configuration and execution take place (which is where you need properties like the project version)

This last point is what makes the real difference as inferred properties, including the project version, are evaluated in advance and made available to the build scripts as if they were statically defined.

What Nyx does behind the scenes is running the nyxInfer task in the early initialization phase, before build scripts are evaluated and project plugins applied. While you still have these tasks (along with others) available for you to invoke at any time during the build process, invoking them again won’t change the value of the inferred properties (as long as the Git repository contents don’t change).

Let’s take a common example of using the Maven Publish Plugin. The plugin uses the project version to define the version of the artifacts that will be published and it does so in the evaluation phase. For example:

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'com.example.library'
            artifactId = 'library'
            version = project.version

            ...
        }
    }
}

In this example the version = project.version assignment is superfluous as it’s the default, but helps making the example clearer. What’s important is that if you apply the Nyx plugin as a project plugin the Maven artifacts will have their version set as unspecified, while if you apply as a settings plugin the version will be what is inferred by nyxInfer. That’s because the settings plugin kicks in before the Maven publications are evaluated.