This message was deleted.
# community-support
s
This message was deleted.
a
this issue is kind of related https://github.com/gradle/gradle/issues/12247 I think you can put the assignment in a
doFirst {}
block. And to be compatible with Config Cache, create a new
val
in the
configure {}
block.
s
Thank you! Putting the assignment into
doFirst
worked. I’m sorry, what does it mean
create a new val in the configure block
? I don’t understand what to do 😞 Could you clarify?
a
sure thing! I made an assumption that perhaps might not be true - are you setting
jvmArgs
using a dynamic variable? Because of weird config cache reasons it’s a good idea to have that variable defined within the
configure {}
block (but it’s not strictly necessary, I’m just sharing this in case it’s relevant in your case because you’re using config cache) Here’s a simpler example to demonstrate. Here’s
myCustomTask
that, like your task, does something in a
doFirst {}
block.
Copy code
val foo = "123"

tasks.register("myCustomTask") {
  doFirst {
    println("foo is $foo")
  }
}
If I run this using
./gradlew myCustomTask --configuration-cache
, I get an error - task actions (that’s the stuff inside the
doFirst {}
block) aren’t allowed to reference values that are defined outside of the task.
foo
is defined in the script, not in the task. The simple workaround is to just-redefine
foo
inside the task configuration.
Copy code
val foo = "123"

tasks.register("myCustomTask") {
  val foo = foo // redefine the val, so it's local to the task
  doFirst {
    println("foo is $foo")
  }
}
Now
./gradlew myCustomTask --configuration-cache
will work! Of course it’s possible this isn’t applicable to your situation, but it’s a weird problem that can be tough to understand the first time around, so I wanted to make sure I explained in case you bumped into it.
s
I see. You’re right I’m kind of doing this. I calculate the parameter based on properties passed to the build. I.e. it looks like this:
Copy code
jvmArgs += createTestJvmArg(paramName, defaultValue)
I guess I better do it this way:
Copy code
val a = createTestJvmArg(paramName, defaultValue)
jvmArgs += a
The
createTestJvmArg()
method is declared in the same
build.gradle
do I get it right?
a
yes that should be good
Copy code
targets {
  configureEach {
    testTask.configure {
      val testJvmArg = createTestJvmArg(paramName, defaultValue)
      
      doFirst {
        jvmArgs += testJvmArg
      }
    }
  }
}
I can’t remember if you need to explicitly tell Gradle about the task input properties though
Copy code
targets {
  configureEach {
    testTask.configure {
      val testJvmArg = createTestJvmArg(paramName, defaultValue)

      inputs.property("testJvmArg", testJvmArg)
      
      doFirst {
        jvmArgs += testJvmArg
      }
    }
  }
}
that would be important because if Gradle knows about all the inputs and outputs, then it can skip tasks if nothing has changed
s
I see. Looks good.
ah, just realized I tried to avoid execution of the method that computes the value 😆 if I take it outside of
doFirst
it is again executed in the configuration phase no matter what task is executed. Nevertheless, I think I understand what it is doing now. I will think more about the behavior I really want to get in the end. Thank you for your help!
a
haha oh yes, of course!
the solution to that is probably to use a provider so in your script you’d have
Copy code
fun createTestJvmArg(paramName: String, defaultValue: String): Provider<String> {
 return providers.provider { 
   "some value for $paramName, $defaultValue..."
 } 
}
then in your test configuration, define the val, but don’t crack it open until it’s necessary, in the
doFirst {}
Copy code
targets {
  configureEach {
    testTask.configure {
      val testJvmArg: Provider<String> = createTestJvmArg(paramName, defaultValue)

      inputs.property("testJvmArg", testJvmArg)
      
      doFirst {
        jvmArgs += testJvmArg.get()
      }
    }
  }
}
s
cool. I have never used providers before because I could not understand the purpose. Now I see what it is about. really nice. I will try to go with it. Thank you again!
👍 1
a
my pleasure!
v
You should definitely never change the configuration of a task from within its execution phase.
1
s
in my case, all I need is to add a test JVM argument based on a property passed to the build. Technically, I don’t need to change the parameter but I need to compute a slightly different value based on it. At the same time I’m trying to avoid this computation during configuration phase. Is there a better way to do that? Passing the property value straight to the test JVM might work too. Maybe I just don’t know how to do this.
v
The original code you had was perfectly fine to lazily configure the test task. If the configuration was always done, then you have another problem in your build. Something is causeing the task to be realized and configured even though it is not going to be executed, thus disturbing task configuration avoidance.
This can be an
.all
on a task collection, or a
.withType
with second argument, ...
But either way, still make sure to declare eventual inputs that should make the task out of date.
Or even better, use a
jvmArgumentProvider
👆 2
s
I see. then it might be because I have this:
Copy code
testing {
    suites {
        configureEach {
...
to configure common properties for all test tasks
v
But even then something is still disturbing task configuration avoidance
No, that should be fine
configureEach
is a lazy operation
And it is not about the test suite, it is about the task
Something is causing your task to realize and configure. And without seeing your full build it cannot be told here what it is
Set a breakpoint in that configuration part and find out what causes it in the stack
s
ok, I don’t see any
all
or
withType
in the script. Let me try creating a smaller script to see if it would have the same problem. if not, then I will need to find what’s wrong
v
Or throw an exception and read it in the stacktrace if you want it less convenient 🙂
👍 1
ok, I don’t see any
all
or
withType
in the script. Let me try creating a smaller script to see if it would have the same problem. if not, then I will need to find what’s wrong
It does not, I copied your code 1:1 and it worked perfectly fine lazily as it should be
s
then I will throw an exception to see the stacktrace :)
thanks for checking!
v
You can also have a look at a build
--scan
to see how many tasks are configured that shouldn't
m
To see the data about configured tasks more immediately, you can do
gradlew :help -Dorg.gradle.internal.tasks.stats
til 1
v
Nice, TIL, thank you very much, right away added to my user's
gradle.properties
. 🙂
🙂 2