gradle resolve the dependencies if the artifact is not found then build the dependent and upload the artifact - gradle

During configuration cycle of gradle where it tries to resolve the dependencies is there a way where I can add custom task/plugin such as to build the dependent project(details of svn path of the dependent project is provide thru ext properties) if the artifact is not found.
Thank you.

There isn't currently a built-in feature for this. It may be possible to implement this yourself, but it won't be easy. To get started, have a look at https://github.com/pniederw/elastic-deps, which is a proof-of-concept to replace project dependencies with external dependencies if they aren't available locally.
PS: Configurations are resolved when their artifacts are first requested, which typically happens in the execution phase (not configuration phase).

I had a need for the same feature. Getting it to work with gradle was a cinch. The hard part was figuring out how Android Studio syncs the gradle files. Without a successful sync, the IDE will complain it can't find any dependencies. At any rate, I figured it out, here is my solution to make it work with gradle and Android Studio.
https://gist.github.com/vangorra/c1383c355ce8fe56adf8
It essentially boils down to defining the project in settings.gradle:
include 'library'
project(':library').projectDir = file('../Library/library')
Then you have to use a one-liner with options closure for your dependency:
compile ( project(':library').projectDir.exists() ? project(':library'): 'Library:library:unspecified#aar') {
transitive = true
}

Related

Is it possible to use the Realm Kotlin Multiplatform SDK with only IntelliJ (not Android Studio)?

In my Kotlin Multiplatform app I use IntelliJ for the shared libraries rather than Android Studio. So far that approach has worked fine but when I looked at using the Realm Kotlin Multiplatform SDK - to my surprise - the documentation states that it requires Android Studio.
I thought I would give it a try anyway but I didn't have any success. Is this actually possible?
https://www.mongodb.com/docs/realm/sdk/kotlin/install/kotlin-multiplatform/
Initially I added
plugins {
id("io.realm.kotlin")
}
and
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt")
implementation("io.realm.kotlin:library-sync:1.0.0")
}
}
but not this since I don't have an Android Studio style project level build.gradle. Since I'm not using a mono repo I don't have two separate build.gradle files. The one I have is at the project level but has the contents of what the app level build.gradle would look like.
classpath("io.realm.kotlin:gradle-plugin:1.0.0") // did not add this
At this point the project would not complete a gradle sync.
I have a settings.gradle file with
if (requested.id.namespace == "com.android" || requested.id.name == "kotlin-android-extensions") {
useModule("com.android.tools.build:gradle:4.1.3")
}
so I tried
if (requested.id.namespace == "io.realm" || requested.id.name == "kotlin-android-extensions") {
useModule("io.realm.kotlin:library-sync:1.0.0")
}
thinking maybe that could substitute for not using classpath("io.realm.kotlin:gradle-plugin:1.0.0") anywhere but it didn't help.
I was able to get the Gradle sync to complete successfully
by using id("io.realm.kotlin") version "1.0.0" in the plugin block instead of just id("io.realm.kotlin") as specified in the documentation.
However it won't compile when I try to publish to mavel local
I get this sort of error. I say this sort of error because if I run the publish to maven local task again the target will be different; it cycles through them each time for some reason. So I don't literally get the same error each time I run the task.
Could not determine the dependencies of task ':compileKotlinIosArm64'.
> Could not resolve all task dependencies for configuration ':iosArm64CompileKlibraries'.
> Could not resolve org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt.
Required by:
project :
project : > io.realm.kotlin:library-sync:1.0.0 > io.realm.kotlin:library-sync-iosarm64:1.0.0
project : > io.realm.kotlin:library-sync:1.0.0 > io.realm.kotlin:library-sync-iosarm64:1.0.0 > io.realm.kotlin:library-base:1.0.0 > io.realm.kotlin:library-base-iosarm64:1.0.0
...
I tried adding the coroutines dependency to each target specifically but that didn't help either.
Also, if I comment out the realm plugin and dependency but just leave the coroutines dependency there it publishes to maven local without any issues.
I asked on the Kotlin slack group in the realm channel and it was suggested that it "should" work so wondering if anyone else knows the trick or if you know if it's NOT possible.
Thanks.
Edit
I created a test library and was able to get it to compile. I was also able to reproduce the issue by adding ktor libraries which seem to conflict with implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt"). I still wasn't able to find a solution though.
It says to use strictly here but not sure how to make ktor use that version https://kotlinlang.org/docs/multiplatform-mobile-concurrency-and-coroutines.html#multithreaded-coroutines.
Also, even without ktor it still doesn't compile if I add iosSimulatorArm64 as a target. In that case I get this error:
Could not determine the dependencies of task ':compileKotlinIosSimulatorArm64'.
> Could not resolve all task dependencies for configuration ':iosSimulatorArm64CompileKlibraries'.
> Could not resolve io.realm.kotlin:library-sync:1.0.1.
Edit 2
I thought what the heck I'll try to create a multiplatform library with Android Studio (chipmonk) just to see if that works. Nope. Even worse. Without doing anything except create the project from the wizard I get these sorts of errors all over the place in the build files with no clear indication of what's causing it:
Cannot access 'java.lang.Comparable' which is a supertype of 'org.gradle.kotlin.dsl.KotlinBuildScript'. Check your module classpath for missing or conflicting dependencies
Cannot access 'java.lang.Object' which is a supertype of 'org.gradle.kotlin.dsl.KotlinBuildScript'. Check your module classpath for missing or conflicting dependencies
I think I'm gonna have to either find a different way to store and sync local data or put KMP on hold for now until things are a bit more stable and just do full native and write all the code multiple times. I seem to be pretty much out of options for solving this.

When working on a project and one of it's dependency in parallel how to load it from the file system

I'm working on a java dependency that I publish on GitLab via gradle. In parallel I also work on some projects dependent of it.
When I need to do a change in the parent I have to wait for my CI/CD to be over before I can keep developing the childs. There is most certainly a way to tell gradle 'check there before online' but all I've found until now is to do that with local jar but not raw source files.
I tried most of the things in How to make Gradle repository point to local directory but without success as gradle is excepting a maven repo structure with some pom.xml files.
So how could I achieve something like this ?
After rethinking the problem and studying a bit more gradle/maven I found the solution.
Just execute the task gradle publishToMavenLocal in the parent project. Then in the dependent project add mavenLocal() to your list of repo. That's all you have to do.
I'm still looking for a way to make gradle build and publish the parent automatically on the child's build. But it's already much more practical like this?

How to use custom gradle plugin without publishing it to maven/ivy repositories?

I have 2 gradle projects. One is my custom gradle plugin and the other one is project which uses this plugin.
I know I can build my custom plugin, publish it to some repository and use it in my other project but is there any way how can I set something like "dependency" for my plugin (in build.gradle of my other project) and use it without need of building/publishing it somewhere?
To get and idea what I am trying to accomplish, here is some code which hopefully demonstrates the idea:
buildScript {
dependencies {
compile project(":my-gradle-plugin")
}
}
apply "my-gradle-plugin"
You can do that if your plugin project can be moved inside buildSrc of the project that wants to include it. In that case, the plugin will be by default on the classpath of the project.
If that plugin is shared between multiple projects, you will need to produce the binary and then reference it. Note that a local repository can be used, it does not have to be a remote one. One advantage of using a local repository is that Gradle will not cache the resolved plugin and thus any update, even without a version change, will be picked up immediately.

Same Gradle files, same code base, different dependency graphs for different developers

This problem seems like a real mystery to me. We are working on a Spring REST app. On my team, we have Jenkins running a build on all checkins (CI build). In addition, there is an official build done elsehwere nightly. Some integration tests recently started failing during the CI build, and we traced the cause to jar conflicts. However, we had successfully excluded the transitive dependencies that caused those conflicts earlier, and for the official build, and for some developers on the team, that is still true. For others it no longer is.
We have the same code base, and the same Gradle files. When I run the dependency task on my system, I have a long tree of transitive dependencies in one subproject (as does the Jenkins machine), whereas others have no such tree. In addition, the size of the WAR is several orders larger for some developers than for others. The transitive dependencies come from another related project uploaded to Nexus.
I have refreshed dependencies both on my machine and the Jenkins machine, and even wiped out .gradle, but to no avail.
It sounds like something environmental, but the Gradle versions and Java versions are all roughly the same, a couple minor versions off at most.
Any ideas about what could cause this discrepancy?
You could force your dependencies to specific versions across the board
def gsonModule = 'com.google.code.gson:gson'
configurations.all {
resolutionStrategy {
// add dependency substitution rules
dependencySubstitution {
substitute module(gsonModule) with module("$gsonModule:2.6.1")
}
}
}
// note: configurations block must be above the dependencies
// or build will error
dependencies {
compile "$gsonModule:2.7"
}
Then when any developer/CI/test/CD runs the build your resolutionStrategy forces consistency across all compilations. Default behavior in gradle is upon version conflict the newer version will be used. This will force the all versions to the same regardless of their declared version.
$ ./gradlew dependencies --configuration compile -q
------------------------------------------------------------
Root project
------------------------------------------------------------
compile - Dependencies for source set 'main'.
\--- com.google.code.gson:gson:2.7 -> 2.6.1
Reference: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
You should use gradle wrapper to ensure the same gradle version throughout, in order to exclude some possibility of that being a factor.
Also, add --refresh-dependencies to the gradle command-line. It may be that some of your dependencies are not being versioned correctly, and this flag will verify each time that only the latest are pulled.
Finally, take a look at workstations that have different results, and ensure that you have identical gradle.properties in your gradle user home folder and the project folder.
First, thanks for the quick responses, but I have an update:
In short, one of my colleagues identified one of the problems. I can't get into details, but the gradle files have convenience functions for either downloading another project from Nexus (such as the related project that I referred to above) or using a locally-built artifact if it exists.
Doing the latter resolves the issue. Downloading from Nexus (as Jenkins did, and as you should be able to do) allows the issue to occur, exposing it. I don't believe this effects the build order, but it does effect the transitive dependencies that are pulled in.
There are also some problems in the dependencies of the various sub-projects: e.g., one project intended not to have dependencies has one, and that one is a big culprit in bringing transitive dependencies. So when that base project is pulled in by other projects, it has ripple effects. And some of those dependency blocks need to be cleaned up.
Again, thanks for the responses!

eclipse gradle workspace resolution between gradle projects not working

2 gradle projects, A and B where A has compile dependency on B defined. Remappig of JARs is enabled for maven & gradle projects. I've tried with custom tooling model enabled and disabled. I have local repositories defined in a file under init.d directory.
Question 1: Why do I get an error of undersolved dependency for project B while resolving dependencies for A? Even though B isn't deployed to any of the repositories local workspace resolution should kick in and resolve it in same way as it is for maven projects (that works btw).
Question 2: Does B need to have anything special apart from group and version defined in build.gradle to be visible for workspace resolution?
I am running with eclipse 4.4.1 and Gradle IDE 3.7.0.201503301651-CI-B39. I've also tried stable release with same eclipse version.
When running with --debug I can see gradle trying to resolve from local repositories and than giving up?
The answer to both your question boils down to the fact that there is no workspace resolution as you might know it from maven / m2e.
The 'remapping' of dependencies does not 'resolve' projects in the workspace in the sense that it treats the workspace as some kind of a repository.
Instead dependencies are resolved as normally by Gradle from whatever repositories you have defined in your build scripts. Then the tooling will attempt to determine if some of the resolved jar dependencies correspond to projects in your workspace. It then 'replaces' (or 'remaps') the jar dependency with a project dependency.
So, this means that you must at least publish the jar to some place where it can be resolved before the remapping can kick in. (From that point on you do not have to republish your jars as it doesn't really matter that the resolved jar isn't 'up-to-date')
Some other things that may be useful to know...
remapping is only applied to tooling managed dependencies, so you must have 'dependency management' enabled.
There's a bug that makes this not work for 'flat file' repo. There could be other cases affected by similar bugs. You should report such bugs if you run into them. (Allthough I didn't have much luck myself getting the Gradle folk's attention about the flatfile bug)

Resources