Trying to write a plugin to set version strings in a standard format

(Chris Warren) #1

I’m going to be working with an Ivy repository, and in my tests, you can’t upload the same-versioned binary to an Ivy repository twice, because you’d be overwriting the previous artifact. The right way to handle this, as I understand it, is to append a build number to the version string, so you would end up with something like “1.0.0+456” for build 456 of version 1.0.0. Because I want to use this approach over a bunch of different build scripts, I think the right approach is to write a Gradle plugin that encapsulates this logic.

The documentation for writing plugins (chapter 58) is all about adding custom tasks to a build, but I believe what I need to do is just set the project.version value based on an initial version string that the user would provide. I’m thinking I will use example 58.2 as a starting point, so that I’ll have something like this:

apply plugin: MyVersionPlugin
  myversion.base = '1.0.0'
  class MyVersionPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create("myversion", MyVersionPluginExtension)
        project.version = project.myversion.base + '+' + System.getenv("BUILD_NUMBER")
  class MyVersionPluginExtension {
    def String base = '0.0.0'
  task printversion << {
    println "here's the version: " + version

Although when I run “gradle printversion”, I get “0.0.0+123” instead of “1.0.0+123”, which I was expecting.

I apologize for the cargo-cult approach, but could someone explain to me where I’ve gone wrong?

Thank you very much.

(Benjamin Muschko) #2

Your logic is executed as follows:

  1. Apply plugin to your project. That means executing the plugin’s apply method. 2. Within the apply method of the plugin set the project version with the help of the extension property base (at this point of time it’s the default value ‘0.0.0’). 3. Set the extension property value for base to ‘1.0.0’.

Basically, setting the value happens too late. One way to resolve this issue is to wrap the code that sets the project version with an afterEvaluate call:

project.afterEvaluate {
    project.version = project.myversion.base + '+' + System.getenv("BUILD_NUMBER")

(Chris Warren) #3

Thank you; that’s cleared things up. I didn’t have a proper understanding of the order that things were happening in.

(Chris Warren) #4

I hope a second, related question isn’t a faux pas. I’m now trying to write a test for this plugin.

class MyVersionPluginTest {
    public void myversionPluginChangesProjectVersion() {
        Project project = ProjectBuilder.builder().build()
        println "initial version: " + project.version
        project.apply plugin: 'myversion'
        println "after plugin applied version: " + project.version
          assertTrue(project.version != 'unspecified')

Both times project.version is printed out, the value is “unspecified”. This is because the project hasn’t been evaluated, correct? How do I trigger that evaluation so that I can test whether or not my plugin had the desired effect?


(Benjamin Muschko) #5

The project built with ProjectBuilder doesn’t fully behave like the real-world Gradle project. For example the afterEvaluate code is not executed. You could use the tooling API to test your specific use case. We want to support better testing capabilities in the future. You can find a workaround in this posting.