This message was deleted.
# community-support
s
This message was deleted.
m
Does this mean calling getProject() from a task implementation is a bad thing?
I'm no Project isolation/configuration cache expert so take this a grain of salt but yea, I think this is bad (more details in the Gradle docs)
If you enable configuration cache I think you'll get an error
What extensions do you need from the project?
a
I only do this for custom tasks with custom extensions. I'm guessing I just need to make properties on the task for the things I need to access, and then wire up the task properties to the extension properties at configuration time.
m
Yep, exactly
The doc says this:
Copy code
In all cases the reason these types are disallowed is that their state cannot easily be stored or recreated by the configuration cache.
👍 1
"these types" including
Project
a
This gets me thinking that I may be abusing the extension API. I have a lot of Gradle tasks and plugins for deployment logic to AWS, specifically S3 and ECR. I have an S3 and ECR extension and each of these extensions have methods for hiding the implementation like "uploadToS3". The big issue I keep facing is how to properly mock my S3Client class in my tests as I do not want them accessing real S3. I have recently started using local stack for my integration tests with GradleRunner and I am not mocking anything, but for my unit tests using ProjectBuilder I am able to create a "mock" extension that my task is accessing. Normally I would just create custom classes and have that all in the constructor of my task but since I can't use "MyCustomTask task = new MyCustomTask(mockS3Client)" as new is disallowed for testing tasks. Maybe I should just give up on the ProjectBuilder unit tests for my tasks and just rely on good integration testing.
e
you can have constructor arguments for your custom tasks,
Copy code
abstract class MyTask @Inject constructor(
    extension: MyExtension
) : DefaultTask() {
    // ...
}

tasks.register("myTask", MyTask::class, myExtension)
or get them during configuration
j
Passing the extension to the constructor looks like it is incompatible with configuration cache
Copy code
@get:Input
val allTests: Property<Boolean>
    get() =
        objects
            .property<Boolean>()
            .convention(allProjectsExtension.install.get().preCommit.get().allTests)
maybe it is related to using
get()
e
try
.map { ... }
instead of
.get()...
?
j
with
map/flatMap
I am getting a
Provider<Boolean>
instead of the property
Copy code
allProjectsExtension.install
                .flatMap(InstallOptions::preCommit)
                .flatMap(PreCommitOptions::allTests)
e
you can pass a
Provider
into
Property.convention()
j
Copy code
@get:Input
val allTests: Property<Boolean>
    get() =
        objects
            .property<Boolean>()
            .convention(
                allProjectsExtension.install
                    .flatMap(InstallOptions::preCommit)
                    .flatMap(PreCommitOptions::allTests)
            )
that still fails with configuration cache 😞
e
why is it a computed getter? it only makes sense as a stored property, I would think
either that or you don't need to configure it on the task separately from the extension, in which case Provide should be enough and drop all the stuff wrapping it to Property
j
without the getter, same issue
not sure about what you mean with the last statement
using Provider as input instead of Property?
Sorry, I was configuring something wrong, anyway moving it to Provider is cleaner and it works, thank you!
e
what I meant was that, regardless of configuration caching, a getter returning a new property on each invocation doesn't make sense. either your task should have a
Property
which is created once (if you want to configure it separately per task instance) or should not use a
Property
(if it's only ever derived from other values)
👍 1
thank you 1