This message was deleted.
# community-support
s
This message was deleted.
c
Something like this fall-through chain of providers? Yes, this works with configuration caching.
Copy code
/**
 * Looks up the specified property from the following sources, in order:
 *
 * -Gradle property
 * -System property
 * -Environment variable (with name transformed to uppercase, '.' replaced with '_'
 */
public fun ProviderFactory.property(name: Provider<String>): Provider<String> {
    return gradleProperty(name)
        .orElse(systemProperty(name))
        .orElse(environmentVariable(name.map { it.uppercase().replace(".", "_") }))
        .forUseAtConfigurationTime()
}
c
I saw that for use with is now deprecated
c
correct
c
So I was just using the normal property access. Has property and property
So I need to use the property factory stuff then?
c
yes. the resolution of properties should be deferred until execution time (when the property values are needed).
i.e. avoid
.get()
, etc on properties.
c
Does it actually matter if all that property does is get set for the purpose of it being passed to the test?
It doesn't further affect gradle at all
c
it does in the sense of configuration and task caching; if the property value changes caches are invalidated.
c
Okay
Thank you I'll get her done
👍 1
I guess I was kind of hoping all that stuff was configuration cache aware now
c
most common things are, if you are using Properties/Providers.
c
Do I actually need to have the function there? And is it then just a matter of calling the function directly inside of my tasks.test?
c
that function was for reuse, not necessary to have it. Something like this:
Copy code
named<Test>("test") {
        prop.set(
            providers.gradleProperty("some.gradle.property")
                .orElse(providers.systemProperty("some.system.property"))
        )
    }
that will set a value for the property
prop
on the
test
task; within the task you would use
prop.get()
to resolve it’s value.
c
But how do I check if it has property in the first place? I only want to do this if it's set
c
it does that for you via the orElse clauses. You can provide a default via
.convention
(or add another orElse). If you really want to check if it has a value use
prop.isPresent
inside the task action.
You can also do something like this:
Copy code
public fun ProviderFactory.gradlePropertyPresent(name: Provider<String>): Provider<Boolean> {
    return gradleProperty(name).map { true }.forUseAtConfigurationTime()
}
c
The Gradle property function doesn't seem to exist the kotlin DSL
Also exactly the work for a project property?
c
Hmmm. It does on recent 7.4, 7.5 versions of Gradle.
c
. I am using 751 but it doesn't seem to want to recognize it for an import
And system property takes two or three arguments
c
Provider<String> gradleProperty(Provider<String> propertyName);
on ProviderFactory since Gradle 6.2
Provider<String> systemProperty(String propertyName);
on ProviderFactory since Gradle 6.1
c
I think I'm confused because I was your interfaces and I don't seem to have any static methods
c
ignore those extension functions, they were illustrative. In a Kotlin DSL build script there is
providers
on the project that should be used.
c
Oh I think I see what you have in mind. So once I get the cradle or system property from providers. Do I then just call the normal system property to set it?
c
no. use the syntax provided to get a gradle property provider, set that on your task, and call
.get()
inside the task action on the proeprty.
c
Why not just do providers.gradleproperty.get?
c
that subverts the point of providers - to defer resolution until it’s needed.
.get()
should only be called at execution time (inside task action).
c
Also is Gradle property actually going to work for a project EG -P property
c
yes
c
But how do I set it back to a system property that the test will receive? Looking at your code I don't see that
c
Copy code
named<Test>("test") {
        prop.set(
            providers.gradleProperty("some.gradle.property")
                .orElse(providers.systemProperty("some.system.property"))
        )
    }
that create a provider that will first try a gradle property then a system property. In your task action use
prop.get()
to resolve.
c
Where does prop come from? And that still doesn't seem like it would set it back to system property for the purpose of spring getting it in my test
Isn't that getting it from the initial system property that's running gradle?
c
prop is a property on the task. What are the specifics of your example?
It will get it from the system properties passed to gradle via -D or vis systemProp.<whatever> in gradle.properties.
c
I've got providers Gradle property run system property spring.profiles.active CI
c
what does the task definition look like?
c
Right, exactly
Really hard to get from the computer here. The task is just your normal test task
And I'm just trying to set the spring profile if I set a property from the Gradle command line
switched to my personal computer
Copy code
tasks.test { useJunitPlatform() providers.gradleProperty("ci").orNull?.run { systemProperty("spring.profiles.active, "ci") } ... }
c
that won’t work. you aren’t setting anything on the task. It looks like your are trying to set a system property there - won’t work in that manner, you’ll need to look at the test task to see how to set a system property (i can’t recall atm).
c
I mean, that's a correct invocation for setting a system property
there's no prop.set on the task though
c
Something like this:
Copy code
tasks.named<Test>("test") {
    useJUnitPlatform()
    systemProperty( "spring.profiles.active", providers.gradleProperty("test.spring.profiles.active").orElse(""))
}
with
-Ptest.spring.profiles.active=ci
c
how is that different... orNull is just doing a get and then run will exec when it's not...
seems the same...
functionally
the documentation says orNull gets the value or returns null
c
true, but you don’t really want to do that yourself - let the Gradle internals resolve as necessary.
c
seems like mine might actually be (negligibly) more performant too as system property wouldn't get called unless (and I wouldn't want it to) it was set
c
unlikely to be any material / measurable performance difference. tend to prefer cleaner code first.
c
isn't orNull just going to call the same get as earlier? trying to understand the difference. Also I'm uncertain (and untested) whether setting spring profiles to an empty string is going to unset my other default of test
obviously I could actually put something, but that might cause a different kind of confusion
c
you could use ‘test’ as the default, or do a
.map {}
to add test into what was passed in the property. The difference is that Gradle will invoke the provider internally, if and when required, removing .get() or .orNull from your code. Imperative code in build scripts is a code smell, makes it noisy and hard to maintain.
c
yeah, but it causes confusion I think from a spring perspective... idk, urgh
debate-ably imperative
c
it’s more idiomatic Gradle; of course, one can do whatever is possible in the world of Kotlin
c
as val foo = bar ? "foo" : null is debate-ably imperative
and
orElse
is just as imperative 😉
to be honest, if I could have done this without touching the gradle scripts, I would have
ultimately though, I'm not seeing a functional difference asside from style...
c
Not style. Resolving a provider outside of the execution phase is not idiomatic, it incurs potentially unnecessary operations, clutters the code, and doesn’t allow for subsequent configuration changes to be picked up before execution. The providers pattern was introduced for many good reasons; subverting those reverts back to the many problems.
c
hmm...
oh
how would it resolve outside of execution?
run isn't async
it would be nice if provider has
ifPresent
as it otherwise looks a lot like
Optional
c
as soon as you call
.orNull
or
.get()
during configuration (such as configuring a task) that subverts lazy configuration. Providers are generally either passed to Gradle to be later resolve, or resolved in your custom task actions (during execution of the task, if the task is even executed).
There is
isPresent
on Provider but that falls into the same lazy configuration trap.
(when called outside of execution phase)
c
I said
if
not
is
still
so there's no approved way to only set the probably on the other property being set?
the configuration cache definitely seems to recognize the probably change now...
c
you can chain properties together if that’s the goal. e.g.
prop1.set(prop2)
, without having to resolve the values.
good to hear!
c
what is this .set? I don't see it on Provider
where do I get this
c
Providers are the read-only aspect of Properties. Typically a task will expose properties (that can be set). Also available on extension objects. for example:
Copy code
scmVersion {
    localOnly.set(true)
    tag {
        prefix.set("release")
        versionSeparator.set("/")
    }
}
c
... so how would I be setting that if this isn't a property available on test task
c
you’re not. The provider is passed into the systemProperty method on the test task, which internally does <something> with it.
c
tried what you're suggesting and it doesn't work because
systemProperty
doesn't take a Provider, and
orElse
returns a provider
so it's serializing garbage
perhaps I should open a bug?
c
seems like that would be a good enhancement request, to accept a Provider in Test.systemProperty.
👍 1
v
If
systemProperty
would properly handle providers, the difference would not only be style, but a Chris version would reuse CC even if the value changes, yours not
👍 1
c
In this case is mine good enough? To be honest though... In this case the value is very rarely going to change in a single environment
if anyone has more comments or whatever
I'm going to make another one too I think regarding some additional provider API regarding conversion of booleans
which is one of the reasons I originally wrote mine that way, also maybe a biconsumer
ifPresent biconsumer
should that be one ticket or 3? 😛
Okay, I'm done writing tickets. Please comment. They all link back to the first one
v
In this case is mine good enough?
If the test task cannot get the value from a provider anyway (didn't check), probably yes.