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

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")
}
}

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 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")
}

Gradle 6 dependencies with strict version and because keyword

The problem
I'm currently experimenting with Gradle 6.0 and ran into the problem that I would like to combine the because statement with the syntax for e.g. strict and rejected versions.
My buildscript:
dependencies {
testImplementation(group: 'org.junit.jupiter', name: 'junit-jupiter-api') {
version {
strictly '[5.0, 6.0]'
prefer '5.5.2'
reject '5.5.1' // for testing purpose only
}
}
testRuntimeOnly(group: 'org.junit.jupiter', name: 'junit-jupiter-engine') {
version {
strictly '[5.0, 6.0]'
prefer '5.5.2'
reject '5.5.1' // for testing purpose only
}
}
// Force Gradle to load the JUnit Platform Launcher from the module-path
testRuntimeOnly(group: 'org.junit.platform', name: 'junit-platform-launcher') {
version {
strictly '[1.5, 2.0]'
prefer '1.5.2'
}
}
}
What I've tried so far
I've currently tried to add the because statement below or above the versionstatement and adding curly brackets around them, but none of these things seemed to work out.
The question
Is it possible to add the because statement to the last dependency and if yes, how?
It would be interesting too, to know whether I can combine both testRuntimeOnly into one.
Using the Kotlin DSL, you can easily see exactly what is available to you. So converting your sample to use the Kotlin DSL, we have
dependencies {
testImplementation("org.junit.jupiter", "junit-jupiter-api") {
version {
strictly("[5.0, 6.0]")
prefer("5.5.2")
reject("5.5.1") // for testing purpose only
}
}
testRuntimeOnly("org.junit.jupiter", "junit-jupiter-engine") {
version {
strictly("[5.0, 6.0]")
prefer("5.5.2")
reject("5.5.1") // for testing purpose only
}
}
// Force Gradle to load the JUnit Platform Launcher from the module-path
testRuntimeOnly("org.junit.platform", "junit-platform-launcher") {
version {
strictly("[1.5, 2.0]")
prefer("1.5.2")
}
}
}
Is it possible to add the because statement to the last dependency and if yes, how?
Yes it is. Since I'm using the Kotlin DSL now, I can easily bring up intelli-sense:
You can see here because is available outside the version block, so:
// Force Gradle to load the JUnit Platform Launcher from the module-path
testRuntimeOnly("org.junit.platform", "junit-platform-launcher") {
version {
strictly("[1.5, 2.0]")
prefer("1.5.2")
}
because("my reason here.")
}

How to exclude multiple groups when using dependencies with gradle

Just like this code:
dependencies {
compile ('com.wdullaer:materialdatetimepicker:3.2.2') {
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'design'
}
}
In an android app build.gradle file, when I want to dependency a remote library, how to use exclude group syntax to exclude multiple groups?
Although the code above is a right way, but it`s a little bit complicated.Is there a simpler way?
Well basically 'exclude' is just a method belongs to 'ModuleDependency' class which accepts a 'Map' of 'group' and 'module' and there's no way to pass more.
However you can use 'Groovy' power in this case and for each 'group' from list to call method 'exclude' on 'ModuleDependency' and to pass current 'group'. Take a look at approximate code below.
compile() { dep ->
[group1, group2].each{ group -> dep.exclude group: group }
}
Using this solution with Groovy combinations (Cartesian product) to exclude some list from all configurations:
/**
* These artifacts must be excluded from all configurations and dependencies.
*/
final excludedModules = [
'module-to-exclude-1', 'module-to-exclude-2'
]
/**
* Exclude dependencies from all configurations.
* This configuration solves an issue
* when the same transitive dependency is included by different libraries.
*/
configurations {
[all, excludedModules].combinations { config, moduleToExclude ->
config.exclude module: moduleToExclude
}
}
Example is here:
compile group: 'org.jitsi', name: 'libjitsi', version: '1.0-9-g4b85531', {
[new Tuple('org.opentelecoms.sdp', 'sdp-api'),
new Tuple('junit', 'junit')].each {
exclude group: "${it.get(0)}", module: "${it.get(1)}"
}
}

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