Configuration options
I am considering adding several configuration options to refreshVersions, and I'd like to gather what other options users of this project might want. This will influence the design of the configuration options API.
Input/thoughts/suggestions are welcome!
Options to have
- Timeout before warning/blaming slow repo/url/connection [unit: seconds?] [allow per-repository-override?]
- Timeout before giving up [unit: seconds?] [allow per-repository-override?]
- Whether to list all updated versions in versions.properties, or only list latest versions per stability level (at the time of writing, the latter is the current only behavior).
Configuration options API design
There's a few solutions to offer configuration of refreshVersions options listed above. Not all solutions provide the same experience and possibilities when it comes to renaming, backwards compatibility…
1. Properties file options
We can use the java .properties files. It is simple, and its usage a common practice in the Gradle ecosystem.
These would be namspaced to allow detecting any obsoleted keys without having the keep the entire list.
Example:
refreshVersions.obsoleteOption=whatever
refreshVersions.warn_slow_after_seconds=2
refreshVersions.repo_connection_timeout_seconds=10
We can have options specified at the top of the versions.properties file
Pros:
- A change in config options doesn't fail the build or gradle sync/import
- Local/temporary/contextual overriding can be made straightforward
Cons:
- An error doesn't fail the build or gradle sync/import, allowing misconfiguration to be ignored
- Discoverability
- All strings, no type safety
- Hierarchy is verbose (need to repeat key "sub-namespace")
2. Kotlin DSL
Kotlin DSL configuration would take place in the settings.gradle.kts file, as an extra argument of the bootstrapRefreshVersions function.
How it would look like is not clear yet because there's concerns regarding API stability and impact of changes for this approach.
Pros:
- Hierarchy is easy with nested DSLs
- Discoverability
- Type safety
- Users can write custom logic that affects the config options if they need it
Cons:
- A non backwards compatible change in config options will fail the build or gradle sync/import
- Local/temporary overriding is less straightforward
- Not compatible with Groovy DSL unless extra effort is spent for it. (Though migrating just settings.gradle is easier than migrating build.gradle files)
I would perfer the Kotlin DSL solution because it opens the paths to computations/logic in the configuration (e.g. produce a list from a pattern and some exceptions instead of listing all). I understand that this can be abused (which was my initial concern when we moved from Maven to Gradle), but overall looks to me that the benefits outweigh the downsides. Otherwise, I can already see projects that generate the properties file.
On the topic of configuration options: the current "latest version based on stability" works mostly well. But some libs have unusual numbering conventions where it does not work. It would be nice to be able to provide per-lib "filters" (e.g. regex) overrides for these. One downside is that this might lead to hiding major upgrades that do not pass the filter. Showing both "filtered" and "unfiltered" would help here, which is what look to me an extension to your "show latest version for all stability levels" idea from above.
Hope this helps a bit and makes sense.
@nkiesel Thanks for your thoughts, I'm still not sure a Kotlin DSL is the right approach, but your point of view gives food for thoughts. I'll keep this issue updated as I'm starting to implement something (which might be after the north hemisphere summer).
Can you link versions of libraries that do not play well with the current implementation of the latest most stable strategy?
I tend to favor declarativity when possible, so a well documented configuration file may work better in this case. I suggest however to use a mixed approach: express the configuration in a Kotlin API, and allow loading of options via Konf. This way you get support for rich configurations (e.g. in YAML) and users can always fallback to Kotlin if they need to.
YAML is very error-prone as it cannot be automatically formatted and just an extra space can break it in hard to read way. I'm forced to use it in GitHub Actions, and that's more than enough for this project.
It's a standard way of using rich configurations, it's not by chance that GH Actions uses it. Off the tip of my head, the the same do Travis CI and Jekyll, it's a rather common configuration format, I used it extensively, and plan to keep using it in future.
Moreover, if you go through Konf you get support for multiple sources (YAML, JSON, TOML, and others); so, although I don't see why would you need automatic formatting for a configuration file, by going this way you simply let the final user pick whatever file format sie prefers, and the tool gets the same internal Kotlin representation anyway.
The fact that it's used by many is not an argument I consider. That'd just keep the trend, and I do not want to keep it going since it has intrinsic pitfalls. I want it away from the work I commit to maintain.
Well, I believe that disregarding popularity at once may not be wise in general, it at least raises the question of why do many use something if it got intrisic pitfalls (shared with any language with semantic indentation, hereby including Python and the Markdown I'm writing now). Maybe you are right and there is a huge mass of careless designers around, or maybe those pitfalls are not so deep after all. (By the way, I got a similar feeling towards other very common technologies, so I understand the aversion, don't take the comment as an attempt at patronizing you, it's not).
Anyway, let me discard YAML at once and revisit the solution I suggested, that revolves around Konf, which is format agnostic. See it as a possibility for implementing your first proposal, as property files are supported, yet potentially avoiding the issue of hierarchy verbosity. You won't maintain any YAML, so the solution can be considered despite your aversion for the format -- unless you find that also JSON / TOML / XML / HOCON are intrisically bad (yet at that point I'd be puzzled on why the property files are not). If you find it dangerous, or a source for other people bothering you with support request due to them using YAML, you could exclude it from the supported formats (by simply not including it). You'd get almost as free lunch the possibility to extend / enhance the configuration in future, as well as leaving to end users the choice of the specific configuration format matching their taste, among the set you identify as suitable (having discarded YAML, I invite you to consider TOML, still rich, yet unaffected by semantic indentation as far as I remember.
Too many configuration options is a minus, not a plus. We can start by documenting what we already have.
see https://github.com/jmfayard/refreshVersions/wiki/Draft:-configuration-options