Best way of passing a custom object between tasks

Hi there,

I’m having a bunch of custom tasks and have to provide the calculated data between them.
For example:

Task A gathers Information in its execution phase.
Task B needs that Information (in its execution phase)

What I want to share, is a custom class with some properties in it, like this:

class GitInfo {
    boolean isWorkingCopyClean
    String commitHash
    String repoUrl
 }

as for now, I’m storing the data from TaskA using this:

TaskA {
  doLast {
    project.extensions.add(EXT_CONFIG_KEY, config)
  }
}

an retrieving it in TaskB using this :

TaskB {
  doLast {
    GitInfo cfg = project.properties.get(GitTask.EXT_CONFIG_KEY)
  }
}

Is there a better way ? I would prefer to set the output of TaskA in the configuration phase
of TaskB, so I would do something like:

tasks.register('consumer', ConsumerTask) {
   config = taskA.properties.config
}

but the problem is, that the config object isn’t there yet in the properties of taskA, because
it has not run yet. Is there a way using providers / lazy config ?

thanks for your help ! :slight_smile:

kind regards,
paddy

One way would be to write the result of A to a file and have it as output file.
Then have an input file in B that gets the output of A wired and can take the result from there.
This is for example helpful if A is expensive and can be cached or can be up-to-date.

If A anyway always needs to run and cannot be up-to-date, then you could e.g. have a Provider<GitInfo> in A that you wire to a Property<GitInfo> in B.

Another way would be to use s shared build service that holds the state that should be shared.

Thank you very much Björn for taking the time to read my post an suggest this options !
The file solution does not feel right in my case, because the calculations are very light weighted and don’t need to be cached.

I read about Providers before, do you have a simple example for that ? I’m only worked with providers
using for example:

@Input 
abstract Property<String> getProperty()

in my own Tasks which extend DefaultTask.
I dont know how to wire something from taskA to taskB.

My first thought was, that I need somethin like:

@Output
Property setGitInfo()

in TaskA and then have something like this in TaskB:

@Input
Property getGitInfo()

I would wire them like my other properties in my plugin where I create these tasks.
But there is nothing like “@Output” … all default outputs are based on files.

Could you clarify or provide a weblink to an example maybe ?

Many thanks in advance :slight_smile:

It will not be “output”, as only file-based outputs are supported as you recongized.
But the outputs are only for up-to-date checks and caching anyway.
So if you don’t have inputs / outputs for your taskA, it will always be executed.
So it probably needs @Internal.

For taskB, if it should count as input, you would annotate the properties of GitInfo with according input annotations and annotate the property with @Nested.

But while thinking about it, if this is something you are going to publish, you should maybe consider using the third option instead, unless you really want the users of those tasks to be able to set those values too.

Or you call disallowChanges() after you wired them, but it might still be confusing then to have them in the API.
If this is just private for your build, it probably doesn’t matter much.

Thanks Björn,

I think the shared build service would be too much effort for the size of the project. It’s also not wanted that the user can set the Input manually, because its a calculated value (Git States etc).

Is there something to be considered bad of simply just using

doLast {
this.ext[GIT_INFO_KEY] = config
}

in Task A and resolving the object back in TaskB using:

doFirst {
TaskProvider task = project.tasks.named(Tasks.QUERY_GIT.name)
if (task.isPresent()) {
GitInfo info = task.get().ext[GITQueryTask.GIT_INFO_KEY]
}
}

? As for now it feels simple and elegant and more appropriate than Inputs/Outputs ?

I think the shared build service would be too much effort for the size of the project.

A build service is not really much effort, they are pretty simple actually.

It’s also not wanted that the user can set the Input manually, because its a calculated value (Git States etc).

Which is a point for build service, not against.

Is there something to be considered bad of simply just using

Yes, any usage of “extra” properties is considered bad and usually just a work-around for not doing it properly. But well, whatever works for you. :slight_smile:

Okay, you got me :slight_smile: I’ll have a look how to implement a build service!

1 Like

I implemented the build-service ! You were right. It fits like “Deckel aufm Topf” :wink: perfect solution ! I don’t even need the “GetGitInfo” task anymore, because the service is far more well suited for this.

Now my other tasks, simply get the needed information by this service and it looks much cleaner.

Many thanks for sharing your precious time to help a gradle newbie :slight_smile:

1 Like