This message was deleted.
# community-support
s
This message was deleted.
j
In the root project it is working and it is not empty, but in a subproject it is empty
I have found which is causing the issue, but I don't understand why, and the difference is the subproject is applying the Kotlin JVM plugin
And it has to be applied after my plugin, if I apply my plugin at bottom, the issue is gone, no sense
The issue is not happening with
java
plugin
I am not sure how Kotlin JVM plugin can be breaking it
c
it’s likely resolving your provider / valueSource at a different time (or in a different order). Takes a bit of tweaking to get the resiliency right to avoid ordering problems.
j
But I don't know why Kotlin is broken it like that, I am depending on Assemble task and looks like Kotlin is creating in a weird thing or I am not configuring my task in a lazy way
Copy code
project.tasks.named(ASSEMBLE_TASK_NAME).configure {
    it.dependsOn(semverPrintTask)
}
I tried without the
configure
, same issue
Copy code
project.tasks.named(ASSEMBLE_TASK_NAME) {
    it.dependsOn(semverPrintTask)
}
I was aplying base plugin before so I was no getting a crash, but the property was empty. After removing the base plugin from my plugin to use assemble configured by Kotlin I get a crash based on order in the plugins block...
c
usually indicates something is happening during configuration (where code is susceptible to ordering issues( instead of being lazy and done during execution (after all plugins applied, plugins evaluated). Check where your configuration is set, ensure it’s only resolved lazily.
j
Is it possible to track it with a scan? I am unable to see where I am failing
the only thing I see I am using in configuration phase is the ValueSource but I think it is normal
c
Possibly. I often end up adding debug statements to help understand call order.
j
Is it possible the Kotlin plugin is doing something in a not lazy way if I am unable to reproduce the issue with java plugin and it is only happening with Kotlin one?
c
could be, question is how is that tickling your code? is the Kotlin plugin reading something you are providing earlier than expected?
j
that is the weird thing, I am setting the version which is calculated inside the ValueSource using my plugin extension property, but that property is not fetched by Kotlin plugin
but even calling my semverPrint task which has nothing to do with Kotlin, it still prints incorrect values
c
what is an example of an incorrect value?
j
Checked with Android plugin, no issue too
Copy code
> Task :semverPrint
semver for semver-plugin-playground: c0.1.0.0+30b28c6+DIRTY

> Task :library-one-a:semverPrint
semver for library-one-a: a2.5.4.4+DIRTY
That is the correct values
after changing Android or Java plugin to Kotlin, and keeping it after my plugin, I get:
Copy code
> Task :library-one-a:semverPrint
semver for library-one-a: a0.1.0.0+30b28c6+DIRTY
the reason it is not printing it is coming back to 0.1.0 is it is getting the plugin extension property as empty
both, Java and Android are working correctly in any order
c
how does it get that plugin extension property?
j
it is configured there (
projectTagPrefix
)
and it is used inside
ValueSource.obtain
method
c
ok. thanks for sharing that. perhaps try to `set`the property.
convention
is the default value, usually only used in say an extension constructor, not when passing a value around. There are some corner cases where properties without a set value behave differently.
`set`will also uncover cases where properties that are supposed to be set aren’t set - Gradle will chirp about those.
what does
semverExtension.tagPrefix
look like?
j
Copy code
public val tagPrefix: Property<String> = objects.property<String>().convention(DefaultTagPrefix)
and in the consumer library:
Copy code
semver {
    tagPrefix.set("a")
}
c
ok. that looks correct.
how is the semver extension created? Specifically, is it the same instance in the plugin as in the build file (
semver { tagPrefix … }
)
j
after changing everything to set it still fails
c
yea. let’s check where / how the extension is created.
j
Copy code
extensions.create<SemverExtension>(extensionName)
but I am not using it directly
later I use
Not sure if it will be the same instance
c
that will return the same instance, have many cases of doing exactly that. hmmm.
j
After wrapping my entire plugin with
Copy code
target.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
    ...
}
the problem is fixed, but I am applying my plugin in the order where it should not be working
not sure if this implies the problem is caused by my plugin or I am in the same point
c
it seems like the ValueSource is being resolved before your configuration has taken effect. That may happen if a plugin accessed
project.version
, as that would happen well before your configuration stanza is executed. For other version management plugins, they force the order, as in calling
project.version = scm.version
after the configuration stanza.
j
how they force the order?
c
easy way to test that - add a println statement in the ValueSource, and another one immediately before
semver {}
configuration block. I’ll find an example of forcing the order, standby…
Copy code
scmVersion {
    tag {
        prefix = 'my-project-name'
    }
}

project.version = scmVersion.version
> Order of definition does matter! First, you need to apply the plugin, then configure it using
scmVersion
extension and only then current version can be set for whole project via
scmVersion.version
.
>
j
mmm my plugin is which is applying the version indeed, this would force the user to apply it manually, right?
I guess there is no way to avoid that and do in my plugin
c
yes. if you are allowing the user to configure it (that semver config stanza) then they have to force the order. If you can configure it all internally you can control the order.
chicken and egg - can’t read the version until we have the configuration on how to read/structure the version.
only way around that is to eliminate the configurability, but presumably you have a need for that.
j
I can fix the issue by configuring it via project properties instead of extension properties, not beautiful, but I avoid the boilerplate of setting the version
c
yep. those would be available in the plugin (providers.gradleProperty), avoiding this timing issue.
j
I guess why Kotlin is calling the version in a different way that Java or Android does, because they are not having this issue
not sure if Kotlin is calling
project.version
or
project.version.toString()
if is this last one, probably that can be the issue because the
project.version.toString()
should be only called inside tasks
I will investigate it, any way, really thank you for your help 🙂
c
exactly. that’s where these timing issues become insidious - everything looks to be working great, until it doesn’t. Somewhere in the Kotlin plugin it is likely calling the
.toString()
, often indirectly (e.g. printing out the version). Sometimes running in --info or --debug changes the behaviour, as the simple act of printing out the version resolves it perhaps sooner than intended.
No worries, hope it all works out!
🙂 1
j
Looks like there are a few
v
> because the
project.version.toString()
should be only called inside tasks
Who defines that? I mean, it would be nice if it were the case, but I don't remember this being any rule written somewhere.
c
Certainly no rule for that. project.version is dated, from original model where it was assumed to be static (or externally defined). Challenging to make it dynamic…
j
I think I have read it in some place today when I was trying to fix this issue but I am not being able to find it from mobile
v
where it was assumed to be static (or externally defined).
That's not fully true. If that were the case it would have been a
String
field. It was always meant to be dynamically calculated, by having an
Object
field where the call to
toString()
determines the version to be used.
j
Knowing that anybody can set anything there that can be configured lazily, calling to string outside of a task is risky
v
Sure it is. But some plugins (hopefully non still existing) even just casted the value to a
String
because they did not consider that it actually can be anything. That the value of
version
is changed frequentely is indeed not a too well supported case.