Skip to content
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

Request: replace string-based templating with lambda parameters, so I can programatically create the version #70

Open
aSemy opened this issue Apr 26, 2022 · 12 comments
Assignees
Labels
enhancement New feature or request

Comments

@aSemy
Copy link
Contributor

aSemy commented Apr 26, 2022

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<RefPatchDescription> action) {
RefPatchDescription ref = new RefPatchDescription(BRANCH, Pattern.compile(pattern));
action.execute(ref);
this.list.add(ref);
}

        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

- `refs` List of ref configurations, ordered by priority.

Is it ordered by ascending priority, as in the first definition will be overridden by later definition, if they match?

@qoomon
Copy link
Owner

qoomon commented Apr 26, 2022

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

@qoomon
Copy link
Owner

qoomon commented Apr 26, 2022

regarding your other point, ℹ First matching configuration will be used. from top to bottom. Does that help?

@qoomon qoomon self-assigned this Apr 26, 2022
@qoomon qoomon added the enhancement New feature or request label Apr 26, 2022
@qoomon
Copy link
Owner

qoomon commented Apr 26, 2022

@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?

@aSemy
Copy link
Contributor Author

aSemy commented Apr 26, 2022

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.

@qoomon
Copy link
Owner

qoomon commented Apr 27, 2022

@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.

@qoomon
Copy link
Owner

qoomon commented Apr 27, 2022

I'll try to implement it in Java and then I'll migrate the project to kotlin

@qoomon
Copy link
Owner

qoomon commented Apr 27, 2022

your approach would work, however it would lead to a ugly syntax like

branch(".+") { gitSituation ->
      new PatchDescription( version = "${gitSituation.ref}")
 }

@aSemy
Copy link
Contributor Author

aSemy commented Apr 27, 2022

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.

@aSemy
Copy link
Contributor Author

aSemy commented Oct 25, 2022

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?

@qoomon
Copy link
Owner

qoomon commented Oct 25, 2022

@aSemy oh that would be awesome.

@aSemy
Copy link
Contributor Author

aSemy commented Oct 25, 2022

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.

  1. the git version can be determined before the projects are configured
  2. the version only has to be configured once, and will be immutable
  3. 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 {}.

@qoomon
Copy link
Owner

qoomon commented Oct 26, 2022

@aSemy sounds great I was not aware of Gradle Settings plugins

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants