How can I exclude dependencies brought in from other sub-projects? - gradle

This is not a duplicate since those other solutions did not work.
I have a sub-project:
:commons:widget
gradle.build (sub-project) resembles this:
configurations {providedCompile}
dependencies {
compile project(":commons:other-widget")
...other dependencies...
}
If you display the dependencies:
+--- project :commons:some-other-project
+--- project :commons:exclude-me-project (*)
\--- org.apache.cxf:cxf-rt-frontend-jaxrs: -> 3.0.3 (*)
What doesn't work:
Any of the usual syntax. I've tried every variation I can think of. Even went looking for the API but was unable to find what I need there.
In this project's dependencies section:
...
compile project(":commons:some-other-project") {
exclude (":commons:exclude-me-project")
}
Result:
Could not find method exclude() for arguments [:commons:some-other-project] on project
I've also tried:
compile ( project (':commons:some-other-project') ) {
transitive = false
}
Result: Instead of removing dependencies of ":commons:some-other-project", it removes ":commons:some-other-project".
I have a large and complicated project to convert. I've a lot of this sort of work ahead of me. Given a project as a dependency, how do I exclude things from it?

exclude for dependencies has a little bit another syntax, so try to do it providing the module name, which is equals to the exclude-me-project name, like:
compile(project(":commons:some-other-project")) {
exclude module: "exclude-me-project"
}
Alternatively, you may exclude all the transitive dependencies for commons project, but it will remove all the deps of the some-other-project project, including the exclude-me-project:
compile(project(":commons:some-other-project")) {
transitive = false
}

for new gradle syntax you can do something like:
implementation (project(path: ':my_library_v1.0.0')) {
exclude (group: 'com.google.code.gson', module: 'gson')
}

Kotlin DSL answer
This will exclude a subproject from another subproject:
implementation(project(":nice-subproject")) {
exclude(module = "annoying-transitive-subproject")
}
Also note that using exclude on a test fixture dependency requires a cast
implementation(testFixtures(project(":nice-subproject")) as ModuleDependency) {
exclude(module = "annoying-transitive-subproject")
}

Related

Adding subproject resolved dependencies to earlib in gradle 5.5.1

I have a multi-project build with 100+ EAR files. The subprojects more or less use a convention like this:
subproject1
-| subproject1JAR
-| subproject1EAR
-| subproject1WAR
subproject2
-| subproject2JAR
-| subproject2EAR
-| subproject2WAR
When I refer to JAR, below, I'm referring to the business logic/SDK contained in, e.g., subproject1.jar.
I have some logic in an afterEvaluate block in subprojects{} that parses the .classpath files of the subprojects in order to build the EAR files. This is working but one thing I'm not getting as compared to the legacy (manual) builds is that the EAR/lib folder needs to contain all the dependencies of the JAR file.
Apologies for the wall of code here, I'm just trying to provide the full context for this question.
// this is from subprojects
if(proj.projectDir.name.endsWith('EAR')){ <-- configures EAR proj based on folder name
proj.apply plugin: 'ear'
proj.ear {
baseName = proj.projectDir.name
// snip other ear config stuff
}
if(f_ui.exists()){ // <-- f_ui is a File pointed at what ought to be the WAR subproject
proj.dependencies{
deploy project(path:":${proj_war}WAR", configuration:'archives')
}
}
if(f_jar.exists()){ // <-- f_jar is a File pointed at what ought to be the JAR subproject
proj.dependencies{
earlib project(path:":$proj_jar", configuration:'archives')
}
def jar_proj = project(":$proj_jar")
proj.evaluationDependsOn(":$proj_jar")
jar_proj.configurations.runtime.allDependencies.forEach { <-- trying to add deps here but
println "##> DEPENDENCY $it" <-- these are empty here
proj.dependencies.add('earlib', it)
}
}
// ## END OF EAR PROJECT CONFIGURATION
}
You can see above where I'm trying to add the dependencies OF THE JAR to the earlib configuration but at this point it seems the dependencies have not been resolved so no dependencies are added.
I believe this unanswered question seems to be asking the same thing.
Any suggestions on how I should be doing this in order to get the dependencies of the JAR into the ear/lib folder?
I certainly don't think this is the best solution but it seems to be working so I'll describe what I did.
Create a custom configuration into which all the dependencies I needed to show up in the earlib were added:
subprojects { Project proj ->
def projname = proj.name
afterEvaluate {
logger.info "## {} afterevaluation #0 started",projname
["Proj1","proj2", "proj3"].each{ depson ->
if (classpathFileContains(proj,depson)) {
proj.configurations.maybeCreate('extra')
proj.dependencies.add('extra', project(":${depson}"))
}
}
...
Add those as implementation dependencies:
try {
// if the project has 'extra', add them to the implementation
proj.configurations.named('extra')
proj.configurations.extra.dependencies.each{
proj.dependencies.add('implementation', it)
}
} catch(e) {
logger.info "## Project {} did not have an extra", proj.name
}
Add the jar file and then add the extra dependencies from the custom configuration:
proj.dependencies{
earlib project(":$proj_jar")
}
try {
jar_proj.configurations.named('extra')
jar_proj.configurations.extra.dependencies.each{
proj.dependencies.add('earlib', it.copy())
}
...
Incidentally, I ran across several other instances of people having
this challenge with earlib (see
ex1,
ex2,
ex3,
plus the reference in the question).
I'm going to try to simplify things and will update this answer if I have an aha moment but as of now this approach is working.

How to add string replacement to plugins block [duplicate]

One of my build scripts imports that nebula plugin:
plugins {
id 'nebula.ospackage' version '3.5.0'
}
I've been moving all of my version info into a separate file that all projects have access to and am wondering what is the correct syntax to convert to something like:
plugins {
id 'nebula.ospackage' version "$versions.nebula_gradle_ospackage_plugin"
}
When I try running the above with "gradle clean build", I get the following error:
build file 'build.gradle': 2: argument list must be exactly 1 literal
non empty string
See
https://docs.gradle.org/2.7/userguide/plugins.html#sec:plugins_block
for information on the plugins {} block
# line 2, column 33.
id 'nebula.ospackage' version "$versions.nebula_gradle_ospackage_plugin"
The linked article shows how I could use the "buildscript" block, which works, but it seems like there must be a way to make this work in a single line?
As of Gradle 5.6, you can declare your plugin versions in the gradle.properties file, and reference these properties in plugins block.
For example, the gradle.properties file:
springBootVersion=2.2.0.RELEASE
the plugins block in build.gradle:
plugins {
id "org.springframework.boot" version "${springBootVersion}"
}
See: https://github.com/gradle/gradle/issues/1697#issuecomment-506910915.
See also:
https://docs.gradle.org/5.6/release-notes.html#central-management-of-plugin-versions-with-settings-script
https://docs.gradle.org/5.6/userguide/plugins.html#sec:plugin_management
You cannot use variable here:
Where «plugin version» and «plugin id» must be constant, literal,
strings. No other statements are allowed; their presence will cause a
compilation error.
This is an old post, but the bug is still open, and I found this post looking for workarounds.
It seems you were aware of this already, and actually have BoygeniusDexter's answer, but I think this may help others finding this post like I did. The following workaround is based on the Gradle docs and solved the problem for me:
buildscript {
ext {
springBootVersion = '2.0.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
plugins {
id 'java'
// and other plugins
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
}
// but the one with the variable version is applied the old way:
apply plugin: 'org.springframework.boot'
// We can use the variable in dependencies, too:
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
// ...
}
In addition to #zhouji comment, you can not only specify the versions in gradle.properties, but you can also define it programmatically like:
buildscript {
ext {
kotlinVersion = "${JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16) ? '1.5.32' : '1.4.32'}"
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version "${kotlinVersion}"
}
Gradle 7
Gradle 7 introduced version catalogs for declaring dependencies and sharing them between projects/modules.
Plugins can be declared in the catalog:
// settings.gradle
dependencyResolutionManagement {
versionCatalogs {
libs {
version('android-plugins', '7.3.0')
plugin('android-application', 'com.android.application').versionRef('android-plugins')
// A library declaration using the same version.
library('some-library', 'com.group', 'artifact').versionRef('android-plugins')
}
}
}
The declaration can be referred to in the plugins block:
// build.gradle
plugins {
alias(libs.plugins.android.application) apply false
}
The version can also be referred to in the plugins block:
// build.gradle
plugins {
id 'com.android.application' version libs.versions.android.plugins apply false
}
See the version catalogs documentation for more information.
Note: In the declaration, - is used as separator in the dependency name. On the consuming side . is used instead, as - is the sign for the minus operator of the groovy language and can't be used in property names.
So the separators are different on the declaring and consuming side - which threw me off at first.
Summary
Omit the version from the plugin block
Move/specify the version in the buildscript.dependencies block, instead
Use a variable in that block that is a const variable
In short, plugin blocks require string literals or properties whereas dependency blocks permit varables. The original question asks for doing this in a "single line" and with this approach, your plugin block is shorter and all your dependencies live in one place for all modules. Depending on your goals, that might be better than doing everything in "one line."
Full Example
For Android, I was able to do this by omitting the version from the plugin block and then specifying it as a const in the buildscript dependencies, instead. That block allows variables, whereas the plugin block only allows string literals. From there, I use an object in buildSrc because that provides the most flexibility, while keeping all dependency info in one file for all modules. So my setup looks like this:
├── project/
│ ├── build.gradle
| └── app/
| └── build.gradle
| └── buildSrc/
| └── build.gradle.kts
| └── src/main/java/com/example/package/Deps.kt
From there, to specify any plugin version as a variable in one place, the app/build.gradle file omits the version (using kotlin as an example but the same approach works for any plugin):
app/build.gradle
plugins {
id 'kotlin-android' // omit version property here but provide it in buildscript dependencies
...
}
...
dependencies {
...
// Dagger
implementation Deps.Dagger.ANDROID_SUPPORT
kapt Deps.Dagger.ANDROID_PROCESSOR
kapt Deps.Dagger.COMPILER
}
Then the buildscript dependency section (usually in the parent build.gradle file but can also be in the same file) provides the version USING A VARIABLE!
project/build.gradle
import com.example.package.Deps // object in the buildSrc folder with all version info
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
}
}
Lastly, all the version information is managed in buildSrc, with an object in the Deps.kt file (there are many blog posts out there on using buildSrc with Android projects):
Deps.kt
object Deps {
// For use in the top-level buildscript dependency section which only works with a constant rather than `Deps.Kotlin.version`
const val kotlinVersion = "1.3.72"
object Kotlin : Version(kotlinVersion) {
val STDLIB = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
}
object Dagger : Version("2.25.2") {
val ANDROID_SUPPORT = "com.google.dagger:dagger-android-support:$version"
val ANDROID_PROCESSOR = "com.google.dagger:dagger-android-processor:$version"
val COMPILER = "com.google.dagger:dagger-compiler:$version"
}
}
open class Version(#JvmField val version: String)
Overall, I really like this setup. It's flexible, all dependency info is in one place, even across multiple modules and, best of all, it allows for code completion in the gradle files, when typing dependencies!
// gradle.properties
springBootVersion=2.6.7
// settings.gradle.kts
pluginManagement {
val springBootVersion: String by settings
plugins {
id("org.springframework.boot") version springBootVersion
}
}
// build.gradle.kts
plugins {
id("org.springframework.boot")
}
I hit this issue.
when I ran
gradle clean test build
instead of
./gradlew clean test build
and my "gradle" was at version 4.x
but my ./gradlew resolved to 6.9 or higher.
aka, "oops, I forgot my build.gradle files were coded to use later versions of gradle(w), but I snapfu-ed and executed the older 4.x version of regular "gradle"

In gradle, how to use a variable for a plugin version?

One of my build scripts imports that nebula plugin:
plugins {
id 'nebula.ospackage' version '3.5.0'
}
I've been moving all of my version info into a separate file that all projects have access to and am wondering what is the correct syntax to convert to something like:
plugins {
id 'nebula.ospackage' version "$versions.nebula_gradle_ospackage_plugin"
}
When I try running the above with "gradle clean build", I get the following error:
build file 'build.gradle': 2: argument list must be exactly 1 literal
non empty string
See
https://docs.gradle.org/2.7/userguide/plugins.html#sec:plugins_block
for information on the plugins {} block
# line 2, column 33.
id 'nebula.ospackage' version "$versions.nebula_gradle_ospackage_plugin"
The linked article shows how I could use the "buildscript" block, which works, but it seems like there must be a way to make this work in a single line?
As of Gradle 5.6, you can declare your plugin versions in the gradle.properties file, and reference these properties in plugins block.
For example, the gradle.properties file:
springBootVersion=2.2.0.RELEASE
the plugins block in build.gradle:
plugins {
id "org.springframework.boot" version "${springBootVersion}"
}
See: https://github.com/gradle/gradle/issues/1697#issuecomment-506910915.
See also:
https://docs.gradle.org/5.6/release-notes.html#central-management-of-plugin-versions-with-settings-script
https://docs.gradle.org/5.6/userguide/plugins.html#sec:plugin_management
You cannot use variable here:
Where «plugin version» and «plugin id» must be constant, literal,
strings. No other statements are allowed; their presence will cause a
compilation error.
This is an old post, but the bug is still open, and I found this post looking for workarounds.
It seems you were aware of this already, and actually have BoygeniusDexter's answer, but I think this may help others finding this post like I did. The following workaround is based on the Gradle docs and solved the problem for me:
buildscript {
ext {
springBootVersion = '2.0.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
plugins {
id 'java'
// and other plugins
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
}
// but the one with the variable version is applied the old way:
apply plugin: 'org.springframework.boot'
// We can use the variable in dependencies, too:
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
// ...
}
In addition to #zhouji comment, you can not only specify the versions in gradle.properties, but you can also define it programmatically like:
buildscript {
ext {
kotlinVersion = "${JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16) ? '1.5.32' : '1.4.32'}"
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version "${kotlinVersion}"
}
Gradle 7
Gradle 7 introduced version catalogs for declaring dependencies and sharing them between projects/modules.
Plugins can be declared in the catalog:
// settings.gradle
dependencyResolutionManagement {
versionCatalogs {
libs {
version('android-plugins', '7.3.0')
plugin('android-application', 'com.android.application').versionRef('android-plugins')
// A library declaration using the same version.
library('some-library', 'com.group', 'artifact').versionRef('android-plugins')
}
}
}
The declaration can be referred to in the plugins block:
// build.gradle
plugins {
alias(libs.plugins.android.application) apply false
}
The version can also be referred to in the plugins block:
// build.gradle
plugins {
id 'com.android.application' version libs.versions.android.plugins apply false
}
See the version catalogs documentation for more information.
Note: In the declaration, - is used as separator in the dependency name. On the consuming side . is used instead, as - is the sign for the minus operator of the groovy language and can't be used in property names.
So the separators are different on the declaring and consuming side - which threw me off at first.
Summary
Omit the version from the plugin block
Move/specify the version in the buildscript.dependencies block, instead
Use a variable in that block that is a const variable
In short, plugin blocks require string literals or properties whereas dependency blocks permit varables. The original question asks for doing this in a "single line" and with this approach, your plugin block is shorter and all your dependencies live in one place for all modules. Depending on your goals, that might be better than doing everything in "one line."
Full Example
For Android, I was able to do this by omitting the version from the plugin block and then specifying it as a const in the buildscript dependencies, instead. That block allows variables, whereas the plugin block only allows string literals. From there, I use an object in buildSrc because that provides the most flexibility, while keeping all dependency info in one file for all modules. So my setup looks like this:
├── project/
│ ├── build.gradle
| └── app/
| └── build.gradle
| └── buildSrc/
| └── build.gradle.kts
| └── src/main/java/com/example/package/Deps.kt
From there, to specify any plugin version as a variable in one place, the app/build.gradle file omits the version (using kotlin as an example but the same approach works for any plugin):
app/build.gradle
plugins {
id 'kotlin-android' // omit version property here but provide it in buildscript dependencies
...
}
...
dependencies {
...
// Dagger
implementation Deps.Dagger.ANDROID_SUPPORT
kapt Deps.Dagger.ANDROID_PROCESSOR
kapt Deps.Dagger.COMPILER
}
Then the buildscript dependency section (usually in the parent build.gradle file but can also be in the same file) provides the version USING A VARIABLE!
project/build.gradle
import com.example.package.Deps // object in the buildSrc folder with all version info
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
}
}
Lastly, all the version information is managed in buildSrc, with an object in the Deps.kt file (there are many blog posts out there on using buildSrc with Android projects):
Deps.kt
object Deps {
// For use in the top-level buildscript dependency section which only works with a constant rather than `Deps.Kotlin.version`
const val kotlinVersion = "1.3.72"
object Kotlin : Version(kotlinVersion) {
val STDLIB = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
}
object Dagger : Version("2.25.2") {
val ANDROID_SUPPORT = "com.google.dagger:dagger-android-support:$version"
val ANDROID_PROCESSOR = "com.google.dagger:dagger-android-processor:$version"
val COMPILER = "com.google.dagger:dagger-compiler:$version"
}
}
open class Version(#JvmField val version: String)
Overall, I really like this setup. It's flexible, all dependency info is in one place, even across multiple modules and, best of all, it allows for code completion in the gradle files, when typing dependencies!
// gradle.properties
springBootVersion=2.6.7
// settings.gradle.kts
pluginManagement {
val springBootVersion: String by settings
plugins {
id("org.springframework.boot") version springBootVersion
}
}
// build.gradle.kts
plugins {
id("org.springframework.boot")
}
I hit this issue.
when I ran
gradle clean test build
instead of
./gradlew clean test build
and my "gradle" was at version 4.x
but my ./gradlew resolved to 6.9 or higher.
aka, "oops, I forgot my build.gradle files were coded to use later versions of gradle(w), but I snapfu-ed and executed the older 4.x version of regular "gradle"

Gradle exclude a specific subproject from full build

In our Gradle project, we want to add a new module for functional-tests that needs to be able to access dependencies from other subprojects but still not be run as part of the full project build. If I try this, it still gets built:
def javaProjects() {
return subprojects.findAll { it.name != 'functional-tests' }
}
configure(javaProjects()) {
...
}
project(':functional-tests') {
....
}
The result is the same even if I move the functional-tests build to a separate build.gradle file of its own. Can someone point out how to achieve this?
I found a better solution to be to exclude the functional tests from running on the command line or via the build file.
For example, to run all tests except the functional tests, run:
$ gradle check -x :functional-tests:check
Then when building the project, you can let the subproject build but exclude their tests from running.
$ gradle clean assemble -x :functional-tests:check
A better option is do disable the functional tests in your build file unless a property is set. For example, in your build.gradle you'd add:
project('functional-tests') {
test {
onlyIf {
project.hasProperty("functionalTests")
}
}
}
This way, functional tests are always skipped unless you specify a specific build property:
$ gradle check
$ gradle -PfunctionalTests check
Hope that helps!
I do it like this:
//for all sub projects
subprojects {
if (it.name != 'project name') {
//do something
}
}
by this way, I can exclude some special project in subprojects.
you can also use it in allprojects or project.
As far as I know it's not possible to deactivate or exclude project after it as been included in settings.gradle. Therefore it maybe done in the following way in settings.gradle:
include 'p1', 'p2', 'p3'
if (any_condition_here) {
include 'functional-tests'
}
It will require additional checking in build.gradle - to configure the project if it's included.
What also comes to my head is -a command line switch, see here. Maybe it might helpful somehow.
You can't exclude the subproject, but you can disable subproject tasks:
gradle.taskGraph.whenReady {
gradle.taskGraph.allTasks.each {
if(it.project == project) {
it.onlyIf { false }
}
}
}
Just to mention that you donćt need to create a new module for integration/functional tests. I prefer to make a new, dedicated source set...
The approach is nicely described here: https://tomgregory.com/gradle-integration-tests/

Gradle multiple compile dependencies syntax

I am trying to declare a compile dependency in Gradle 1.12, with multiple items that shares the same exclude clauses (this is to avoid repeating the exclusion everywhere). I know I can do something like this:
configurations {
compile.exclude group: 'com.google.gwt'
all*.exclude group: 'com.google.guava'
}
but this will affect ALL configurations. What I want is something like this (which does not work in Gradle 1.12 as written below):
compile (
["org.jboss.errai:errai-data-binding:2.4.4.Final"]
,["org.jboss.errai:errai-data-ioc:2.4.4.Final"]
){
exclude group: 'com.google.gwt'
exclude group: 'com.google.guava'
}
so I can gather together all dependencies for which I need exclusion in one place, and still be able to have elsewhere this:
compile 'com.google.guava:guava:17.0'
Update:
Just to clarify, my only goal is to replace this piece of code:
compile ('bla.bla.bla:1.0'){
exclude 'same.component:1.0' //Ugly repeat
}
compile ('boo.boo.boo:1.0'){
exclude 'same.component:1.0' //Ugly repeat
}
compile ('uh.uh.uh:1.0'){
exclude 'same.component:1.0' //Ugly repeat
}
compile ('oh.oh.oh:1.0'){
exclude 'same.component:1.0' //Ugly repeat
}
with something short and sweet like this (not working currently):
compile( 'bla.bla.bla:1.0'
,'boo.boo.boo:1.0'
,'uh.uh.uh:1.0'
,'oh.oh.oh:1.0'
)
{
exclude 'same.component:1.0' //Only once! Sweet!
}
There is no way to have per-dependency excludes while still being able to use the compile 'com.google.guava:guava:17.0' syntax. configurations.compile.exclude ... will only affect the compile configuration (and configurations inheriting from it), and is almost always preferable over per-dependency excludes.
Another solution is to factor out dependency declarations with something like:
ext.libs = [
error_data_ioc: dependencies.create("org.jboss.errai:errai-data-ioc:2.4.4.Final") {
exclude group: 'com.google.gwt'
exclude group: 'com.google.guava'
}
]
Then you can reuse these declarations wherever you need them (e.g. dependencies { compile libs.error_data_io }; also works from a subproject). If you really wanted, you could also share the same { exclude ... } block among multiple declarations (by assigning it to a local variable).

Resources