Request: replace string-based templating with lambda parameters, so I can programatically create the version
Opened this issue ยท 12 comments
At the moment the version is constructed based on a static string template. The plugin will do a find/replace in the version
string for format placeholders, and replace them with existing format placeholder values.
However I would like to dynamically select the version, based on the format placeholder values. For example:
If CODEBUILD_WEBHOOK_TRIGGER
is not available, then use the 'ref' placeholder.
version = "0.0.0-SNAPSHOT"
gitVersioning.apply {
refs {
branch(".+") {
// if the env-var is unavailable, use the 'ref'
version = "\${commit.timestamp.datetime}-\${env.CODEBUILD_WEBHOOK_TRIGGER.slug:-\${ref}}"
}
}
rev { version = "\${commit.timestamp.datetime}-\${commit}" }
}
This resolves to
20220425.112958-${ref}
But I want it to be
20220425.112958-feat-add-widget
Suggestion
Perhaps the find/replace can be made more intelligent, but I'd recommend an alternative. Remove the string templating, and provide the git variables as parameters to the existing action.
public void branch(String pattern, Action<GitProperties, RefPatchDescription> action) {
RefPatchDescription ref = new RefPatchDescription(BRANCH, Pattern.compile(pattern));
// action.execute(ref); // don't execute immediately, evaluate it later, once the git properties are determined
this.list.add(action);
}
// when required, evaluate the version
public RefPatchDescription evaluateVersion() {
for (var Action<> action in list) {
return action.invoke(gitProperties)
}
}
(I'm not sure on the correct Action
class to use, but in this case GitProperties
would be provided as an argument and the Action
must return a RefPatchDescription
.
In build.gradle.kts
it would be used something like this
version = "0.0.0-SNAPSHOT"
gitVersioning.apply {
// List of ref configurations, ordered by priority. First matching configuration will be used.
refs {
branch(".+") { gitProperties ->
var gitRef = gitProperties.env("CODEBUILD_WEBHOOK_TRIGGER")
if (gitRef.isNullOrBlank()) gitRef = gitProperties.ref()
version = "${gitProperties.commit.timestamp.datetime}-${gitRef}"
}
}
rev { gitProperties ->
version = "${gitProperties.commit.timestamp.datetime}-${gitProperties.commit}" }
}
Other points
A quick question, rather than making a ticket just for for it, I am confused by this line
gradle-git-versioning-plugin/README.md
Line 112 in 41e0fea
Is it ordered by ascending priority, as in the first definition will be overridden by later definition, if they match?
Hi @aSemy , this is a very interesting idea. This plugin is a clone of the maven git versioning extension, that is why it has static templating, however I really like your approach it is much more gradle like. I'll try to implement it this way and release a new major version within the next month
regarding your other point, โน First matching configuration will be used.
from top to bottom. Does that help?
@aSemy I haven't found a way to implement your idea with the Action class nor any alternative. Do you have an clue for a solution?
Ah I thought the Action class was a significant Gradle object, but thinking about it, it's not. It just needs to be a lambda parameter. In Kotlin it would be
fun branch(pattern: String, action: (GitProperties) -> RefPatchDescription) {
this.list.add(action)
}
I forget what the Java interface is, but you could always define your own. I think it would be something like this.
@FunctionalInterface
interface RefPatchDescriptionProvider {
public RefPatchDescriptor action(GitProperties gitProperties)
}
...
public void branch(String pattern, RefPatchDescriptionProvider action) {
this.list.add(action);
}
I think that will be fine, and would be compatible with the Gradle task avoidance way of working.
If it would help out, I can try and implement it, but I'm really not a fan of Java any more, so I'd like to do it in Kotlin. Would you be interested in converting the project to Kotlin? At least the Gradle plugin element.
@aSemy I'm totally on your side i switched to Kotlin some years ago also :-), however I was too lazy to convert this project. So yes I am interested in converting it. One Requirement would be that it will still works within groovy gradle files.
I'll try to implement it in Java and then I'll migrate the project to kotlin
your approach would work, however it would lead to a ugly syntax like
branch(".+") { gitSituation ->
new PatchDescription( version = "${gitSituation.ref}")
}
Ah I see... I'll see if I can make a draft PR as a demo.
I think using @HasImplicitReceiver
is the start of improving it
import me.qoomon.gitversioning.commons.GitSituation;
import me.qoomon.gradle.gitversioning.GitVersioningPluginConfig.RefPatchDescription;
import org.gradle.api.HasImplicitReceiver;
@FunctionalInterface
@HasImplicitReceiver
interface RefPatchDescriptionProvider {
void action(RefPatchDescription description, GitSituation gitSituation);
}
in Gradle this would be used like this
branch(".+") { gitSituation ->
version = "${gitSituation.ref}")
}
I think this can probably make it work. But thinking about it this situation is probably a good fit for Gradle's 'NamedDomainObjectContainers' https://docs.gradle.org/current/userguide/custom_gradle_types.html#collection_types. But that can be done much later.
I'll try to implement it in Java and then I'll migrate the project to kotlin
hey @qoomon, how would you feel about picking this up again? :) I'd like to help out. I can start by converting the Gradle config to Kotlin?
I have done some pondering and I think the best way forward is to essentially create a new version by changing gradle-git-versioning-plugin to be a Gradle Settings plugin.
https://stackoverflow.com/questions/69149466/gradle-7-2-how-to-apply-a-custom-gradle-settings-plugin
abstract class GradleGitVersionPlugin : Plugin<Settings> { }
This has some advantages.
- the git version can be determined before the projects are configured
- the version only has to be configured once, and will be immutable
- the settings plugin can apply an extension to all subprojects that will contain the computed version
I also think that confusing bit of how a version is selected #71 (comment) can be made more clear by making it conditional when the version is selected. Instead of having a refs {}
block, the plugin should provide a sealed-class with three subtypes (attached, detached, unknown), so users can do an exhaustive when {}
.