-
Notifications
You must be signed in to change notification settings - Fork 8
Check that publishingType has a valid value
#169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
||
| override fun centralPortal(action: Action<CentralPortalOptions>) { | ||
| check(!centralPortalConfigured) { | ||
| "Nmcp: centralPortal {} must be called only once" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is that requirement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
centralPortal {} creates the tasks so calling it twice fails with "task already exists" the second time.
I know Gradle wants you to be declarative and register the task eagerly in Plugin.apply() but I found out that:
- this pollutes the model if no publishing is done
- it makes it unclear the precedence of setting the property in case multiple users set the properties.
I have wasted days/weeks of my life trying to understand what changed the value of a given property under the hood. This solution, while less flexible makes it clear that .gradle.kts files are imperative, not declarative and who owns a given property. This should obviously be revisited for declarative Gradle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your pain, however, the approach of "no one can override" effectively blocks overriding the value should one need it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, it's always a trade-off.
To override a value, you'll have to wrap whatever convention plugin is setting it in the first place so there is ultimately a single source of truth for the value.
If you don't own the convention plugin then you'll have to talk with the plugin maintainers so that they open an API for you.
It's painful but so is the debugging of Gradle lifecyle. Which one is worst is a legit question that hopefully declarative Gradle will answer.
| val validValues = listOf("AUTOMATIC", "USER_MANAGED") | ||
| check(publishingType == null || publishingType in validValues) { | ||
| "Nmcp: invalid Central Portal publishingType value '$publishingType'. Must be one of ${validValues}." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only there was a way like data objects to prevent invalid values at the configuration time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is your point that publishingType should be an enum? (data objects probably won't do it for Groovy callers?).
I think we discussed that in the past. I'm with you on the theory. Type-safety is better.
But in that specific case, I found out that in practice, the IJ imports are not working so well in .gradle.kts files, importing symbols doesn't work in applied .gradle files because the symbols are not in the compile classpath of those scripts. Also a plain String allows adding new values without having to update the plugin, may sonatype decide to add more values. As with everything, it's a tradeoff.
Might change it for v2 once we have more feedbacks about the API and the tooling has improved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK Kotlin's data objects (== static final ... fields) should be perfectly usable with both Java and Groovy.
For instance:
sealed class PublishingType {
data object Automatic : PublishingType()
data object UserManaged : PublishingType()
data class Other(val value: String) : PublishingType()
}Both Groovy and Java should support cases like publishingType = PublishingType.Automatic.INSTANCE or publishingType = new PublishingType.Other("some_new_value_added_by_sonatype")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes of course. No exhaustive when there but it's not an issue at all in that case and allows the Other case 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the key point is to have an escape hatch for the case if Sonatype adds a new publication type that is not yet supported in the plugin. At the same time, well-known cases can have type-safe APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth adding static final accessors to reduce .INSTANCE boilerplate, however, I'm not sure how common is it:
sealed class PublishingType {
data object Automatic : PublishingType()
data object UserManaged : PublishingType()
data class Other(val value: String) : PublishingType()
companion object {
@JvmField val AUTOMATIC: PublishingType = Automatic
@JvmField val USER_MANAGED: PublishingType = UserManaged
}
}Then Java/Groovy should be able to access values like in publishingType = PublishingType.AUTOMATIC
No description provided.