Gradle concurrency issues with project.version

I have a task (lets call it firstTask) which sets project.version and another task (fourthTask) which reads project.version.
These tasks have a transitive mustRunAfter dependency:

secondTask.mustRunAfter(firstTask)
thirdTask.mustRunAfter(secondTask)
fourthTask.mustRunAfter(thirdTask)

However, sometimes fourthTask does not see the version change. In fact, it seems like it is run with a completely different project object.

I’ve also tried to force task order using a BuildService, and I’ve tried storing the version in this buildService, to no avail.

I can’t provide a build scan, as the issue goes away with --scan. So I assume it has something to do with parallel execution, which is probably disabled for build scans.

How do I do this correctly? Where do I store a value which needs to be accessed from different tasks?

I’d do

tasks.all { task ->
   if (task.name!='setVersion') task.dependsOn 'setVersion'
} 

That did not help sadly. The tasks are already executed one after the other, but they don’t share the project state.

I’m guessing some of your tasks are requiring the version in the configuration phase but you are calculating it in the execution phase

You can use a custom object for your version, you just need to implement toString().

Eg build.gradle

version = new MyVersion() 

class MyVersion {
   String version
   String calculateVersion() {
      // do some work 
   } 
   String toString() {
      if (!version) version = calculateVersion() 
      return version 
   } 
} 
1 Like

That won’t help as the project object is not the same (verified by object hash)

I’m not following, pls explain

System.identityHashCode(project) sometimes returns different values in different tasks, which means the project objects aren’t the same. Which also means setting anything on the project object in one task won’t set it on the project object of the other task.

Correct, each module has its own project instance. You could do

def myVersion = new MyVersion() 
allprojects {
   version = myVersion
} 

I’m running this with a single build.gradle, no modules involved. All tasks run in the same project and same build and yet they do not always share the project instance.
I don’t know why and I don’t know how to work around it. That is my issue.

Sorry, but I don’t believe you

I’ve figured it out. I’ve been using several GradleBuild tasks in my build, which actually reevaluate build.gradle and that causes a new project instance to be created. I’ve replaced the GradleBuild task with other concepts (dependsOn and a taskGraph listener) to make it work.

Ah, that would explain a lot

GradleBuild task is for invoking tasks in an external build, not the current build. If you invoke GradleBuild on the current build.gradle it will result in two (or more) project instances for a single build.gradle