Copy Gradle dependencies from another subproject without deprecation warning - gradle

In a Gradle project I have multiple sub-projects. I need to copy the dependencies from the configuration of one sub-project to that of another. I can achieve this using the following, adapted from this answer here:
task copyDependencies(type: Copy) {
from project(":sub").configurations.compile
into "${buildDir}/libraries"
}
Unfortunately, with Gradle 5.1, this generates the following deprecation warning (truncated for brevity):
The configuration :sub:compile was resolved without accessing the project in a safe manner. ... This behaviour has been deprecated and is scheduled to be removed in Gradle 6.0.
What's the best way to do this now for Gradle 5.1 and later?

The warning appeared as reaching across project boundaries can cause issues when the build runs in parallel.
The proper way of doing this is to let Gradle know that the project declaring the copyDependencies task will need the project :sub's dependencies.
You can achieve this by doing the following:
configurations {
dependenciesToCopy
}
dependencies {
dependenciesToCopy project(':sub')
}
task copyDependencies(type: Copy) {
from configurations.dependenciesToCopy
into "${buildDir}/libraries"
}
This will cause Gradle to properly create an execution dependency between your project and the resolution of the dependencies of the sub project.
Relevant discussion on the Gradle forums.

Related

How to declare a dependency between 2 non-custom Gradle tasks

I have a Gradle build in which I am publishing the output to the Maven local repo (its used by other modules of a larger non Gradle build). But doing so generates this warning:
Gradle detected a problem with the following location:
'display\build\outputs\apk\release\display-release.apk'. Reason: Task
':display:publishMavenAndroidPublicationToMavenLocal' uses this output
of task ':display:packageRelease' without declaring an explicit or
implicit dependency. This can lead to incorrect results being
produced, depending on what order the tasks are executed. Please refer
to
https://docs.gradle.org/7.2/userguide/validation_problems.html#implicit_dependency
for more details about this problem.
The link suggests that I declare a dependency between the 2 tasks.
But neither of the tasks are custom tasks, they are part of the included plugins. And I despite spending hours trying all kinds of syntax I can't work out how to declare the dependency from the publishToMavenLocal to the package task.
How do I declare it?
plugins {
id 'com.android.application'
id 'maven-publish' // So that we can publish the APKs
}
android {
...
}
publishing {
publications {
mavenAndroid(MavenPublication) {
groupId = 'com.mygroup.foo'
artifactId = project.name
version = 1.2.3'
artifact "$buildDir/outputs/apk/release/${project.name}-release.apk"
// Explicitly not generating a pom dependencies node
// 1) we don't need it because the APK includes all its deps.
on Artifactory.
}
}
}
build.finalizedBy publishToMavenLocal
I believe the problem stems from this line:
artifact "$buildDir/outputs/apk/release/${project.name}-release.apk"
The APK at that location is created by some task. Instead of referencing that tasks' output, you have given a direct path. Because of that, Gradle is not able to accurately deduce task dependencies.
I am not an Android developer, but judging from the error:
uses this output of task ':display:packageRelease' without declaring an explicit or implicit dependency.
The project display has a task named packageRelease which may or may not come from the Android Gradle plugin. Again, I am not an Android developer, so do not know for certain. The packageRelease is what produces the APK at the aforementioned path.
The publishMavenAndroidPublicationToMavenLocal is created when you create a publication named mavenAndroid; this is documented in the maven-publish documentation
With that said, you must declare task dependencies between the two. Something like:
tasks.withType(PublishToMavenRepository::class).configureEach {
inputFile.from(packageRelease)
}
tasks.withType(PublishToMavenLocal::class).configureEach {
inputFile.from(packageRelease)
}
Without knowing the task type of packageRelease and unfamiliarity with Android projects, best I can do above.

Run task before repositories are added and dependencies are resolved

I'm working on compiling python bindings using gradle.
There is a plugin by linkedin that facilitates that.
They also include a project called the pivy-importer that converts python dependencies into an ivy repository.
I've created a gradle plugin that wraps the pivy-importer so that it can run as a python task.
My repositories are declared like this:
repositories {
pyGradlePyPi()
ivy {
name 'pypi-local' //optional, but nice
url "${project.buildDir.path}/pythonIvy"
layout "pattern", {
ivy "[organisation]/[module]/[revision]/[module]-[revision].ivy"
artifact "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
m2compatible = true
}
}
}
The problem, however, is that the repositories are being loaded before the plugin executes.
The first task that the python task runs is pinRequirements so I was adding my cusom pythonImporter task before that like this:
pinRequirements.dependsOn pythonImporter
However, even when I do that, the console shows that the pythonImporter task is running before but as soon as it tries to assemble the dependencies, it can't find them even though they do exist in the file system.
If you rerun the task again, however, it passes because the first run added the repository to the file system.
TL;DR
I need a way to run a task before dependencies are looked up under using a project's configured repositories are loaded.
I moved the tasks execution to my buildSrc subproject and made the build task depend upon its execution.
This works because the buildSrc project is always evaluated before the rest of the projects so you can do "before build" logic there.

I need debugging tips for a broken project dependency

It's configured the same here as it is everywhere else. In fact I use an import for configuring integration tests. I've done everything I can think of including a rename of local integration test tasks and configurations, including looking at the dependency tree, including running with --debug. Yet for some reason Gradle insists that the property integrationTest doesn't exist on the sourceSet for an inter-project dependency:
integrationTestCompile project(':components:things-components:abc-stuff').sourceSets.integrationTest.output
...now I'm not particularly fond of this syntax and I've already griped up a storm about inter-project test dependencies and how they should be in a test utility component. However, I'm doing it this way because this appears to be what IntelliJ will accept. Writing like this causes trouble:
integrationTestCompile project(path: ':components:things-components:abc-stuff', configuration: 'integrationTest')
How can I figure this out? I just don't get why only one project has this issue.
For the record, I've also tried:
integrationTestCompile project(path: ':components:things-components:abc-stuff', configuration: 'integrationTestCompile')
The issue is that Gradle hasn't been told to make a jar for you that you can consume in your other project.
integrationTestCompile project(':components:things-components:abc-stuff').sourceSets.integrationTest.output
Gets the classFiles and the dependencies, thats why its working using that notation. If you want to use the configuration notation you will need to tell gradle to publish a jar on the integrationTest. The jar doesn't have to be published to a repository, but will be used for the internal builds.
You can do this by doing:
configurations {
integrationTest
}
task integrationTestJar (type: Jar) {
baseName = "${project.name}-integ-test"
from sourceSets.integrationTest.output
}
artifacts {
integrationTest integrationTestJar
}
If you end up doing this in a log of projects, I would recommend writing a quick plugin that does this for you.

Gradle task similar to ivy resolve?

I am working on a project on the side of the main project. The main project used to use ivy so my side project can take advantage of the ivy.xmls and do ivy:resolve to solve all dependencies into a cache.
The main project has moved to gradle and I was wondering if there is a task in the gradle API that can populate gradle cache when I only have the gradle build files.
You can accomplish the same thing with Gradle by configuring a task to copy a configuration to a destination.
task copyDependencies(type: Copy) {
from configurations.runtime
into "$buildDir/deps"
}

Gradle artifactory plugin saying "Cannot cast object 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention'..."

Here's the configuration to get the artifactory plugin:
buildscript {
repositories {
mavenCentral()
maven { url 'http://jcenter.bintray.com' }
}
dependencies {
classpath group:'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '3.0.1'
}
}
apply plugin:'com.jfrog.artifactory'
apply plugin:'ivy-publish'
...some publish spec stuff...
I run gradle (2.3) and I get:
> Failed to apply plugin [id 'com.jfrog.artifactory']
> Cannot cast object 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention#6b6c7be4' with class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention' to class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention'
Certainly looks like a classpath issue, but I literally have this project and a sibling project using this same set of gradle/artifactory configurations and one works and the other does not. Both are part of the same top level project. Same JDK (1.8.0_20). Same Gradle. Same everything.
I'm baffled...
The problem was that when I added the various bits to the sibling project that meant I had two projects defining the buildscript {} section.
buildscript {
...
dependencies {
classpath group:'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '3.0.1'
}
}
Apparently that caused two different versions of the dependency to exist in the classpath, hence the error.
The solution was to move the buildscript bit into the master project so those dependencies are only defined once:
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath group:'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '3.0.1'
}
}
Here's another potential cause. All of this looks to be a problem with rival classloaders defining the class. The full qualified classes include the loader. so, load A foo.bar is not loader B foo.bar and crossing that divide is a complex dance requiring interfaces and careful definition.
So, when using the Jenkins artifactory plugin to build your gradle project with the gradle artifactory plugin, you must add the usesPlugin or jenkins plugin will generate an init script which adds the gradle plugin on to a class loader.
def server = Artifactory.server "artifactory"
def rtGradle = Artifactory.newGradleBuild()
rtGradle.usesPlugin = true // Artifactory plugin already defined in build script
...
My problem was, desktop build OK, jenkins build shows this post's problem
I was getting a similar exception when building with Jenkins. For me the conflict was with Jenkin's version and the version in the Build script:
To address this the Artifactory section of the build has a flag you can check specifying that you want to use the version from the gradle file:
This fixed my issue. Hope it helps.
I had a similar problem. Gradle seems to try to reach across and do some checking or evaluation across siblings. I have a top level settings.gradle with 10 or so subprojects.
The fix for me was to put the buildscript block and dependencies at the top level build.gradle and put it in each of the individual subprojects build.gradle files where needed.
My guess as to the reason this works is that the plugin gets loaded in the parent which will be a parent classloader, then each child project inherits that classloader such that the declaration in the lower child script uses that classloaders class and CCE does not occur. The problem is they are the same class, but not assignable since the different classloaders per subproject if nothing is declared at the top. This was Gradle 2.4, and using IntelliJ 14.
In case it helps someone, I got the same error, but for a different reason.
I had the following in my build.gradle:
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:+"
}
At some point the artifactory plugin updated itself from version 3.x to version 4.x while building, because no specific version was specified for the dependency. After it updated I got the error (Could not find any convention object of type ArtifactoryPluginConvention).
I guess the problem was that the rest of the configuration in my build script doesn't work with the new plugin version. Setting the dependency to use version 3.x fixed the problem for me:
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.+"
}
While the currently accepted answer correctly identifies the cause of this issue, the proposed solution doesn't work when you still need to be able to build individual subprojects (because then of course they no longer have access to the buildscript defined repositories and dependencies). The solution that worked for me was to have identical buildscript blocks in each of my subprojects, that seemed to be the key. Any variations would cause the original error.
I got the same exception thrown by bamboo:
'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention#18eb2827' with class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention' to class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention'
Since the bamboo Bamboo Artifactory Plugin by default looks for the gradle.propeties file in each sub-project module, it has to be provided there.
There is no need for publishing logic in the build.gradle file since the Bamboo Artifactory plugin will read the gradle.properties file for each module respectively, containing:
group=com.example
artifactId=your-project
version=1.0.0
The reason that I got the ArtifactoryPluginConvention exception thrown was that my configured build plan on Bamboo was misconfigured.
With misconfigured, the build ordered of the tasks was not correct. Have a look at your bamboo building tasks/preferably clone a Bamboo plan that is already working.

Resources