Don't use later library version from transitive dependency in Gradle - 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'
}
}

Related

Remove transitive classpath dependency - plugins block

I want to remove the log4j transitive dependency from the shadow gradle plugin.
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
I search for a solution but did not get any. I know I can remove this using the following code -
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.1.2', {
exclude module: 'log4j'
}
}
}
But is there any way to do this with plugins block?
No, the plugins { } is itself a DSL which is limited by design. This is documented in the documentation:
https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax
The plugins {} block does not support arbitrary code. It is constrained, in order to be idempotent (produce the same result every time) and side effect free (safe for Gradle to execute at any time).
It is designed to do one thing and one thing only: apply plugins.
I used following code to exclude the dependency -
buildscript {
repositories {
..
}
dependencies {
..
}
configurations.classpath {
exclude module: 'log4j'
}
}
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.2'
}

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 - access other plugin version

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

What is correct version match between kotlin-gradle-plugin and kotlin-js-library?

I have:
ext.kotlin_version = '1.1.3'
ext.kotlin_js_version = '1.1-M04'
repositories {
mavenCentral()
maven{ url = "https://dl.bintray.com/kotlin/kotlin-dev/" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
then in another build.gradle:
dependencies {
compile "org.jetbrains.kotlin:kotlin-js-library:$kotlin_js_version"
}
But I always get:
org.jetbrains.kotlin/kotlin-js-library/1.1-M04/ef6b315dbb89927eb72fbce262ba3a74dc1ebcb5/kotlin-js-library-1.1-M04.jar'
was compiled with an incompatible version of Kotlin. The binary
version of its metadata is 6.0.0, expected version is 1.0.1
I want the latest of both. I think? Or does one lag behind the other?
you can find the latest release versions here:
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib
right now it is on: 1.1.3-2

How to use Gradle's dynamic versions and avoid betas?

I have this on my build.gradle:
testCompile(group: 'junit', name: 'junit', version: '4.+')
It resolves to:
junit:junit:4.+ -> 4.12-beta-1
I don't want to use beta releases but at the same time I want to use the dynamic version.
in this case I want to depend on 4.11 .
Is it possible?
How?
Note: Maven "versions" plugin - how to exclude alpha/beta versions from reponse? has an answer for maven but I'm not sure how to translate this in Gradle.
You could use ComponentMeta to set the status:
dependencies {
components {
eachComponent { ComponentMetadataDetails details ->
def version = details.id.version
if (version.contains("beta") || version.contains("alpha")) {
details.status = "milestone" // default in Gradle
}
}
}
}
Then use the status range syntax for your dependency:
testCompile(group: 'junit', name: 'junit', version: 'latest.release')
Now Gradle won't consider your beta a "release", and hence it won't match 4.12-beta-1. This won't let you only pick 4.x releases though, i.e. a 5.2 release would also apply.
Gradle's dynamic versions don't currently support such excludes.
This is the way I've solved this for my own use case. The following allows exclusion rules to be added that filter candidates during dependency resolution.
Candidates matching regular expression exclusion rules are rejected.
This is Kotlin DSL, but would probably work just as well if converted to Groovy.
configurations.all {
resolutionStrategy
.componentSelection
.all(object : Action<ComponentSelection> {
#Mutate
override fun execute(selection : ComponentSelection) {
// Add exclusion rules here
excludeSelectionByRegex(selection, "org\\.jetbrains.*", ".*", ".*-(eap|M).*")
excludeSelectionByRegex(selection, "org\\.my-group.*", "my-module", ".*-beta")
}
})
}
fun excludeSelectionByRegex(selection: ComponentSelection, groupRegex: String, moduleRegex: String, versionRegex: String) {
if (groupRegex.toRegex().matches(selection.candidate.group) &&
moduleRegex.toRegex().matches(selection.candidate.module) &&
versionRegex.toRegex().matches(selection.candidate.version)
) {
selection.reject("Matched exclusion rule")
}
}

Resources