Gradle - access other plugin version - gradle

I'm want to obtain other plugin version from my own plugin. I can't find a way to do that via PluginContainer nor PluginManager.
For example for build.gradle.kts:
plugins {
id("some.plugin") version "1.2.3"
id("my.plugin") version "3.4.5"
}
From the code of "my.plugin" I would like to read that "some.plugin" is in version "1.2.3".

If you want to access other plugins versions you could do something like:
plugins {
id("base")
id("org.hidetake.ssh") version "2.10.1"
id("com.jfrog.artifactory") version "4.29.2"
}
apply plugin: MyPlugin
class MyPlugin implements Plugin<Project> {
#Override
void apply(Project target) {
// retrieve plugins dependencies from buildscript classpath
DependencySet pluginDependencies = target.buildscript.configurations.getByName("classpath").allDependencies
// use the found plugins dependencies
pluginDependencies.forEach { Dependency classpathDep ->
println(" Plugin dependency found: $classpathDep.name, version=$classpathDep.version")
}
}
}
This will prompt:
> Configure project :
Plugin dependency found: org.hidetake.ssh.gradle.plugin, version=2.10.1
Plugin dependency found: com.jfrog.artifactory.gradle.plugin, version=4.29.2
> Task :prepareKotlinBuildScriptModel UP-TO-DATE
BUILD SUCCESSFUL in 434ms

nop ... still 2022 this is a 🚧
even google ships tons of lines on it
even your api() declaration (with version range)
nor can I see that dependency constraints will help us
in combination
like
class YourPlugin : Plugin<Project> {
override fun apply(project: Project) {
project
.buildscript.dependencies.constraints
.add("classpath", "com.example:other-plugin") {
it.version {
it.require("[1.0, 2.0)")
}
}
}
}
because you can't add constraints in this gradle phase
ending with
> Cannot change dependencies of dependency configuration ':app:classpath' after it has been resolved.
tldr;
so I don't see anything else than
iterate all project build dependencies checking for version
await depending plugin provides a version
https://docs.gradle.org/current/userguide/toolchains.html is JVM specific and even not addresses this aspect
btw, I was not successful when trying to use the version constraints for comparison
if (project.pluginManager.hasPlugin("com.example.other") == false) {
throw DependencyVerificationException("This plugin needs com.example.other")
}
project
.buildscript
.configurations
.getByName("classpath")
.withDependencies {
it.find {
it.group == "com.example" &&
it.name == "other-plugin"
}
?.version
?.let {
if (DefaultImmutableVersionConstraint.of("1.0") /*no clue how to compare with*/ == it)
else throw DependencyVerificationException("This plugin needs com.example.other at least with version 1.0")
} ?: throw DependencyVerificationException("This plugin needs com.example.other")
}
btw. because it is related: for testing different versions there are indeed some things out there like https://github.com/ajoberstar/gradle-stutter

Related

How to define dependency version only once for whole Gradle multi-module project?

I made a decision to migrate from Dependency Management Plugin to Gradle built-in BOM import support. Since Gradle built-in BOM import support has better performance But
I run into the issue:
I cannot find alternatives for dependency and dependencySet in native Gradle:
dependencyManagement {
dependencies {
dependency("org.springframework:spring-core:4.0.3.RELEASE")
}
}
//or
dependencyManagement {
dependencies {
dependencySet(group:'org.slf4j', version: '1.7.7') {
entry 'slf4j-api'
entry 'slf4j-simple'
}
}
}
and then I could use dependency without version
dependencies {
compile 'org.springframework:spring-core'
}
How can I get the same behavior in naive Gradle? I mean: I'd like to define a version once as I did it when using Dependency Management Plugin
Solution below helps to avoid versions copy-paste. However it isn't the same with Dependency Management plugin.
For Gradle Kotlin Dsl:
You can create buildSrc with you own code, when you can place any constants.
Algorithm:
Create folder buildSrc/src/main/kotlin
Create file buildSrc/src/main/kotlin/Versions.kt with content:
object Versions {
const val junitVersion = "5.5.5" // just example
}
Create file buildSrc/build.gradle.kts with content:
plugins {
`kotlin-dsl`
}
Use the following syntax in your gradle.kts files:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:${Versions.junitVersion}")
}
For Gradle Groovy:
Create file gradle.properties
Put versions there with syntax like okhttp_version=4.2.0
Use the following syntax in your gradle files:
dependencies {
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp_version
}
You can do so on the gradle.properties file. I.e.:
# APPLICATION PROPERTIES
name=projectName
group=com.domain
version=1.0.0
description=A brief description
gradleScripts=https://raw.githubusercontent.com/hexagonkt/hexagon/1.2.0/gradle
# DEPENDENCIES VERSIONS
kotlinVersion=1.3.61
kotlinCoroutinesVersion=1.3.2
Or in settings.gradle if you don't want to create another file:
rootProject.name = "hexagon-contact-application"
gradle.rootProject {
allprojects {
version = "1.0.0"
group = "org.hexagonkt"
description = "Contact application backend api"
}
extensions.gradleScripts = "https://raw.githubusercontent.com/hexagonkt/hexagon/1.0.18/gradle"
extensions.kotlinVersion = "1.3.50"
extensions.kotlinCoroutinesVersion = "1.3.2"
extensions.hexagonVersion = "1.0.21"
extensions.logbackVersion = "1.2.3"
extensions.bcryptVersion="0.8.0"
extensions.javaJwtVersion="3.8.2"
}
And if you want to avoid adding the version variable to all related dependencies, you can create a method in the build file:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.50'
}
apply from: "$gradleScripts/kotlin.gradle"
apply from: "$gradleScripts/service.gradle"
apply from: "$gradleScripts/junit.gradle"
defaultTasks("test")
mainClassName = 'com.hexagonkt.contact.ApplicationKt'
applicationDefaultJvmArgs = ["-Xms64M", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC"]
dependencies {
httpkt(it, "http_server_jetty")
httpkt(it, "store_mongodb")
httpkt(it, "hexagon_web")
implementation("at.favre.lib:bcrypt:$bcryptVersion")
implementation("com.auth0:java-jwt:$javaJwtVersion")
testImplementation("com.hexagonkt:port_http_client:$hexagonVersion")
}
private void httpkt(final def dependencies, final String artifact) {
dependencies.implementation("com.hexagonkt:$artifact:$hexagonVersion")
}

How to Make Kotlin Gradle Plugin not Manage Version

When I use Kotlin Gradle Plugin and consume Kotlin BOM at the same time it seems that the plugin version takes in priority for kotlin-stdlib, how do I make the plugin not manage my dependency?
plugins {
kotlin("jvm") version "1.2.50"
}
dependencies {
implementation(platform("some-bom:0.3")) // this has API dependency to kotlin-bom 1.3.50
implementation(kotlin("stdlib")) // this resolves to 1.2.50 (plugin version) instead of 1.3.50 (BOM version)
}
Project is using Gradle 5.2.1
I can't reproduce it, it looks like a bug. As a workaround you can enforce a particular version by specify isForce = true:
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.2.50") {
isForce = true
}
implementation("org.jetbrains.kotlin:kotlin-stdlib-common:1.3.10"){
isForce = true
}
isForce is not transitive, so you have to specify all the transitive kotlin dependencies explicitly with isForce flag true or create a virtual platform:
open class KotlinAlignmentRule : ComponentMetadataRule {
override fun execute(ctx: ComponentMetadataContext) {
ctx.details.run {
if (id.group == "org.jetbrains.kotlin") {
belongsTo("org.jetbrains.kotlin:kotlin-platform:${id.version}")
}
}
}
}
And add it to your dependencies block:
dependencies {
components.all(KotlinAlignmentRule::class.java)
implementation(platform("some-bom:0.3"))
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.2.50") {
isForce = true
}
}
This last solution is the best imo.

Gradle dependency resolution strategy with maven deployer

I am working on an android project. We are using the DependencyResoultionStrategy to swap some dependency versions. The code looks like this:
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
final version = getVersionForDependency(project, details.requested.group, details.requested.name)
if (version != null) {
details.useVersion(version)
}
}
So for example, the project requests the dependency group:name:1.1.2 but it is swapped so the dependency group:name:1.2.0 is used. This works perfectly and the project is built with the right dependency (the second one).
We also have a publish task, which deploys the project to a local maven repository. We use the maven plugin for this, the code looks like this:
apply plugin: 'maven'
task publish(dependsOn: uploadArchives)
uploadArchives {
configurations {
deployerFTP
}
repositories {
mavenDeployer {
configuration = configurations.deployerFTP
repository(URL) {
authentication(USERNAME, PASSWORD)
}
}
}
dependencies {
deployerFTP "org.apache.maven.wagon:wagon-ftp:2.4"
}
}
The problem is, if I publish the library, in the resulting .pom file, the dependency group:name:1.1.2 is entered, not the one which is actually used. How can I change this behavior, so the pom contains the right dependency?
I have found an answer, simply add this code block:
mavenDeployer {
// ...
pom.whenConfigured { pom ->
pom.dependencies = pom.dependencies.collect { dep ->
def version = getVersionForDependency(project, dep.groupId, dep.artifactId)
if (version != null) {
dep.version = version
}
return dep
}
}
}

Gradle + PlayFramework: Cannot resolve sources dependency

I'm using the new Play Framework support in Gradle 2.7.
Ironically, Play 2.3.x explicitly depends on org.scala-sbt:io:0.13.8.
Gradle is able to resolve the JAR (not the sources, just the classes) from typesafe's repository if I add
model {
components {
play {
platform play: "2.3.7", scala: "2.10", java: "1.7"
}
}
}
repositories {
maven {
name "typesafe-maven-release"
url "https://repo.typesafe.com/typesafe/maven-releases"
}
ivy {
name "typesafe-ivy-release"
url "https://repo.typesafe.com/typesafe/ivy-releases"
layout "ivy"
}
}
dependencies {
play group: "org.scala-sbt", name: "io", version: "0.13.8", classifier: "jar", configuration: "compile"
}
however it seems that it cannot resolve the io-sources.jar. I get this:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':runPlayBinary'.
Could not find io-sources.jar (org.scala-sbt:io:0.13.8).
Searched in the following locations:
https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/io/0.13.8/srcs/io.jar
I actually don't care about these sources, I just want to avoid this runtime exception when running gradlew runPlay
Execution exception
[RuntimeException: java.lang.NoClassDefFoundError: sbt/Path$]
Any advice? I can't seem to figure out how to exclude or resolve the sources dependency.
I ran into the same RuntimeException (NoClassDefFound sbt/Path$) with Play 2.4 and Gradle 2.7. In my case the root problem was to not define all repositories correctly (didn't include typesafe-ivy -> sbt-io was not resolved -> thought i need to state sbt-io-dependency -> wrong sbt-io led to mentioned Exception...).
I would advise you to add jcenter() as repository, remove the explicit dependency on sbt and state the play version in your build.gradle. As an example my working gradle.build:
plugins {
id 'play'
}
dependencies {
repositories {
jcenter()
maven {
name "typesafe-maven-release"
url "https://repo.typesafe.com/typesafe/maven-releases"
}
ivy {
name "typesafe-ivy-release"
url "https://repo.typesafe.com/typesafe/ivy-releases"
layout "ivy"
}
}
play 'com.typesafe.play:play-jdbc_2.11:2.4.3'
[...other dependencies - but not "org.scala-sbt"!]
}
model {
components {
play {
platform play: '2.4.3', scala: '2.11'
injectedRoutesGenerator = true
}
}
}
In your case the last part should be:
model {
components {
play {
platform play: '2.3.7', scala: '2.10'
}
}
}
A kind Gradle dev answered my question on the Gradle forums
TL;DR - Gradle/Play bug specific to 2.3.7 that can be resolved by using
repositories {
ivy {
url "https://repo.typesafe.com/typesafe/ivy-releases/"
layout "pattern", {
ivy "[organisation]/[module]/[revision]/ivys/ivy.xml"
artifact "[organisation]/[module]/[revision]/jars/[artifact].[ext]"
}
}
}
In my case, upgrading to Play 2.3.9 fixed my problem.

Don't use later library version from transitive dependency in Gradle

in my Android project I use
compile 'com.squareup.okhttp:okhttp:2.2.0'
I need okhttp in version 2.2.0 for my code to work properly. But I have a problem when I add
compile('io.intercom.android:intercom-sdk:1.1.2#aar') {
transitive = true
}
Because inside intercom-sdk there is okhttp dependency again for later version:
compile 'com.squareup.okhttp:okhttp:2.4.0'
Which results that my code uses that later version 2.4.0 instead of 2.2.0 I want. Is there please any way how in my module I can use 2.2.0 which I specified and let intercom to use its 2.4.0?
You can use something like this:
compile('io.intercom.android:intercom-sdk:1.1.2#aar') {
exclude group: 'com.squareup.okhttp', module: 'okhttp'
}
However pay attention. If the library uses methods that are not present in the 2.2.0 release, it will fail.
You should define a resolution strategy to set a specific version. This will guarantee you will get the correct version you wish no matter what the transitive dependency versions are:
allProjects {
configurations.all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
if (details.requested.name == 'okhttp') {
details.useTarget('com.squareup.okhttp:okhttp:2.2.0')
}
}
}
}
}
In newer versions of Gradle you can use:
allProjects {
configurations.all {
resolutionStrategy.force 'com.squareup.okhttp:okhttp:2.2.0'
}
}

Resources