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

How to use an external plugin in a local plugin and where to put its version #14

Closed
CLOVIS-AI opened this issue Feb 8, 2023 · 7 comments
Labels

Comments

@CLOVIS-AI
Copy link

CLOVIS-AI commented Feb 8, 2023

Hi! I have started to study this repository and it seems to be a solution to many of my problems. However, when trying to apply it to my projects, I'm stuck on something.

I am using gradle-git-version to generate Gradle's version from Git, and RefreshVersions to store the version numbers in a .properties file.

Previously, the setup looked like this:

// root build.gradle.kts

plugins {
    id("com.palantir.git-version")
}

fun calculateVersion(): String = //

version = calculateVersion()

subprojects {
    version = rootProject.version
}

My understanding is that I should make this entire thing its own included build in gradle/plugins/versioning and use it as a plugin in all projects of the main build to avoid using subprojects.

For this, I have:

// gradle/plugins/settings.gradle.kts

dependencyResolutionManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

include("versioning")
// gradle/plugins/versioning/build.gradle.kts

plugins {
    `kotlin-dsl`
}
// gradle/plugins/versioning/src/main/kotlin

plugins {
    id("com.palantir.git-version")
}

fun calculateVersion() = //

version = calculateVersion()

However, I get:

Failed to generate type-safe Gradle model accessors for the following precompiled script plugins:
 - src/main/kotlin/versioning.gradle.kts

org.gradle.internal.exceptions.LocationAwareException: Precompiled script plugin
Plugin [id: 'com.palantir.git-version'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (plugin dependency must include a version number for this source)

I understand that it cannot find the version (since it's provided by RefreshVersion, which is only applied to the main build), but I don't understand what is the proper way to do this:

  • add RefreshVersions to each included plugin individually? That doesn't sound like the modularity this project aimed for
  • hardcode the plugin versions in each dependent plugin? That sounds a bit counter-intuitive when there's a platform module that's supposed to encapsulate all version information
  • some other solution?

It would be nice to add an example to this repository of a gradle/plugins plugin which applies a third-party plugin to demonstrate what the idiomatic way to manage its version is.

@CLOVIS-AI CLOVIS-AI changed the title No example of how to use an external plugin in a plugin No example of how to use an external plugin in a local plugin Feb 8, 2023
@bddckr
Copy link

bddckr commented Feb 9, 2023

What you describe is setting up a composite build for the versioning plugin. But are you missing the includeBuild call in pluginManagement in your settings file/plugin perhaps?

This repository does it in a settings plugin:


This settings plugin is then applied in the product build:
includeBuild("../../gradle/settings")

So in your example, I think you need to include the plugins build in your root settings.gradle.kts.

@jjohannes
Copy link
Owner

jjohannes commented Feb 9, 2023

There is indeed no example of using an external plugin in this repo. Thanks for that feedback. I'll see to add one.

In a setup like this, you need to define a dependency to the "Component" that contains the plugin. There you then also define the version. This is unfortunately not explained very well in the Gradle docs or on the plugin portal pages. In your example, this goes into gradle/plugins/versioning/build.gradle.kts:

dependencies {
  implementation("com.palantir.gradle.gitversion:gradle-git-version:0.15.0")
}

Here is a compact example with explanation:
https://github.com/jjohannes/understanding-gradle/tree/main/03_Plugins
https://github.com/jjohannes/understanding-gradle/blob/main/03_Plugins/my-build-logic/java-plugins/build.gradle.kts

@jjohannes
Copy link
Owner

Example added: 6470f78

@CLOVIS-AI
Copy link
Author

I see, so the platform project also declares the version constraints for plugins? Doesn't that create a risk of confusion between regular dependencies and plugins?

@jjohannes
Copy link
Owner

Doesn't that create a risk of confusion between regular dependencies and plugins?

Yes. Good point. Thanks for bringing it up.

This not only concerns plugins, but also libraries you use in your plugins, like Guava in the example here. Which was already used for both before I added the plugin version as well. And you could say, from that perspective, that a plugin is just another Java library that you only use in your plugins.

As another example; in this repo, it is separated: https://github.com/jjohannes/gradle-project-setup-howto

I think as with many things in dependency (version) management, there is no real good one-fits-all solution.

Technically, your product code and your plugin code are different things. You could say it's just coincidence that the product and the build system are both written in Java so there is absolutely no reason to mix the two.

On the other hand, you could say that using Java both for the product and the build system is an advantage (e.g. all team members can work on both using a single programming language). Then if you work on both regularly, you can say that it's good to keep versions aligned. For example, to avoid the mental overload of juggling different versions of Guava when you switch context. And if there are vulnerabilities, you may want to update everything everywhere in any case.

Both viewpoints are valid imo.

If I separate, I would do it consequently. Which would mean that, if we do it for this example, that Guava is listed two times (in both product and plugins platfom). As we have the catalog on top (right now) we could still have the same version from one catalog in both platforms. Which is another compromise. But then I would wonder if there should be two catalogs as well (somehow related to discussion in #4).

@jjohannes jjohannes changed the title No example of how to use an external plugin in a local plugin How to use an external plugin in a local plugin and where to put its version Feb 9, 2023
jjohannes added a commit that referenced this issue Feb 9, 2023
@CLOVIS-AI
Copy link
Author

And you could say, from that perspective, that a plugin is just another Java library that you only use in your plugins.

That's true, but it's also a very different operation business-wise to update a dependency of the product, than it is to update a dependency of a build-time script/plugin (though of course they are similar from Gradle's point of view). I'll take a look at your plugins-platform example; in your experience, is it worth splitting them into different platforms?

Then if you work on both regularly, you can say that it's good to keep versions aligned.

This is true, but Gradle is always quite late on Kotlin versions, so there is already quite a big difference :)

I'm currently a bit lost between all the options, and to decide how they should fit together. Between convention plugins, platform and/or version catalog, etc.

@jjohannes
Copy link
Owner

I agree with all of that. I did not mean to imply that it is always a good solution to have only one platform. I just wanted to elaborate on why it could be a good choice in certain cases.

If there are hard technical reason to not do this – like the Kotlin version – you should definitely not mix them I think.

We should probably split the platform in this repo as well. 🤔 It's maybe the cleaner solution for most cases.

I'm currently a bit lost between all the options, and to decide how they should fit together. Between convention plugins, platform and/or version catalog, etc.

Me too. 😃 Right now it feels like there is not the one best solution as it depends on so many factors what works better in a certain project structure and team constellation. I think all solutions are fine as long as you centralize the version somewhere.

Then something to think about is who works with dependencies and with version upgrades and when. I think it is important to think about this process as this is something that is touch continuously (which makes it special compared to other build configuration).

That's also what I talk about in where I quickly go over different options: https://youtu.be/8044F5gc1dE

And that's why in gradle-project-setup-howto I also have example of some custom "tooling" (dependency analysis plugin and custom Gradle tasks) to analyze dependencies and guide users if there are issues.

But I also don't have any long term experience unfortunately. I am just starting to establish such things in the projects I am involved in as well.

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

No branches or pull requests

3 participants