maven project as dependency in gradle project - maven

I have a project which is using Gradle as build tool and a second subproject which is using Maven's POM. I don't have the freedom of changing build tool on the subproject.
What I want to achieve is to add my project with Maven POM as dependency on my Gradle project.
Where root (current dir) is my project with Gradle and contains the build.gradle, the Maven project is under vendor/other-proj/ with POM file just under that directory.
I have tried these variations on my build.gradle file:
1st try:
include("vendor/other-proj/")
project(':other-proj') {
projectDir = new File("vendor/other-proj/pom.xml")
}
dependencies {
compile project(':other-proj')
}
2nd try:
dependencies {
compile project('vendor/other-proj/')
}
3rd try:
dependencies {
compile project('vendor/other-proj/pom.xml')
}
4th try:
dependencies {
compile files 'vendor/other-proj/pom.xml'
}
I can't find anything related on the web, it seems most Gradle/Maven use cases are affected by publishing to Maven or generating POM, but I dont want to do any of those.
Can anybody point me to right direction?

you can "fake" including a Maven project like this:
dependencies {
compile files("vendor/other-proj/target/classes") {
builtBy "compileMavenProject"
}
}
task compileMavenProject(type: Exec) {
workingDir "vendor/other-proj/"
commandLine "/usr/bin/mvn", "clean", "compile"
}
This way Gradle will execute a Maven build (compileMavenProject) before compiling. But be aware that it is not a Gradle "project" in the traditional sense and will not show up, e.g. if you run gradle dependencies. It is just a hack to include the compiled class files in your Gradle project.
Edit:
You can use a similar technique to also include the maven dependencies:
dependencies {
compile files("vendor/other-proj/target/classes") {
builtBy "compileMavenProject"
}
compile files("vendor/other-proj/target/libs") {
builtBy "downloadMavenDependencies"
}
}
task compileMavenProject(type: Exec) {
workingDir "vendor/other-proj/"
commandLine "/usr/bin/mvn", "clean", "compile"
}
task downloadMavenDependencies(type: Exec) {
workingDir "vendor/other-proj/"
commandLine "/usr/bin/mvn", "dependency:copy-dependencies", "-DoutputDirectory=target/libs"
}

You cannot "include" a maven project in gradle settings.gradle. The simplest way would be to build the maven project and install it to your local repo using mvn install(can be default .m2, or any other custom location) and then consume it from your gradle project using groupname:modulename:version
repositories{
mavenLocal()
}
dependencies{
implementation 'vendor:otherproj:version'
}
It is possible to depend directly on the jar of the maven project using compile files but this isn't ideal because it wont fetch transitive dependencies and you'll have to add those manually yourself.

Related

Gradle: Use a sibling subproject as plugin

I have a project with two subprobjects: gradle-plugin and plugin-consumer. I want to apply the plugin from gradle-plugin to plugin-consumer. I tried to do this:
// plugin-consumer/build.gradle
buildscript {
dependencies {
classpath project(':gradle-plugin')
}
}
apply plugin: 'my.plugin.id'
But I was greeted with the following error:
A problem occurred configuring project ':plugin-consumer'.
> Cannot use project dependencies in a script classpath definition.
I assume this is not supported because it'd require fully building gradle-plugin before plugin-consumer can be configured.
Fortunately I can use a fileTree dependency to accomplish my goal:
// plugin-consumer/build.gradle
buildscript {
dependencies {
classpath fileTree(includes: ['*.jar'], dir: '../gradle-plugin/build/libs')
}
}
apply plugin: 'my.plugin.id'
This works, but it feels like a massive hack and leads to "bootstrapping problems".
For example, I can't clean gradle-plugin because the (deleted) jar file is necessary for configuring plugin-consumer, which must be done to (re)build gradle-plugin.
Fortunately this can be avoided by always running build immediately after clean (in the same 'run' so to speak). This can be done manually (gradle clean build) or automatically (with clean.finalizedBy(build)). Again, this works, but feels like a hack.
At last, my actual question: is there a better way to do this?
Please note that gradle-plugin is an independent plugin that's not only used by plugin-consumer, therefore buildSrc is unfortunately not an appropriate solution here.
You can publish the plugin to your local Maven repository with the Maven Publish plugin. Then simply consume it like any other artifact.
Assuming you have something similar in your plugin project:
plugins {
`maven-publish`
`java-gradle-plugin`
}
Simply publish it locally:
./gradlew :my-plugin-project:publishToMavenLocal
Then in your consuming project, something like:
buildscript {
repositories {
mavenLocal()
}
dependencies {
"classpath"("com.example:my-plugin-gav:1.0.0-SNAPSHOT")
}
}
// apply plugin

Why won't gradle jar build a jar that gradle build does?

In my Gradle project, I define an additional sourceSet.
sourceSets {
sample {
java {
srcDir 'sample/java'
}
compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath
}
}
I then add a task:
task sampleJar(type: Jar) {
classifier 'sample'
from sourceSets.sample.output
}
artifacts {
archives sampleJar
}
If I do > gradle build the additional jar file builds from the additional source set. However, if I do > gradle jar, it doesn't. any reason why?
When I go through the output messages, I see:
gradle build has sampleJar in the Tasks to be executed:
but
gradle jar doesn't.
But unsure as to why?
Because jar is just the task that assembles the main jar file.
build, on the other hand, is the top-level life-cycle task, which depends on assemble. And assemble is documented as
Depends on: jar, and all other tasks that create artifacts attached to the archives configuration.
Since your sampleJar pecisely creates an artifact attached to the archives configuration, assemble, and thus build depends on it.

Add dynamic dependencies via command line

Is it possible to use CLI to add a jar with Gradle plugin (or task) to the build classpath without modifying build.gradle? Can the add JAR be resolved from Maven repository?
Is buildscript { dependencies { classpath }} controllable from CLI? And can I use CLI to make Gradle to resolve the JAR from Maven?
Basically I need to achieve the same situation as with Maven, which allows invoking any plugin by
mvn <plugin-group-id>:<plugin-artifact-id>:<plugin-version>:<plugin-goal>
I'm writing a pair of Maven and Gradle plugins to extract information about projects and their dependencies into JSON file, which can be later processed programatically. The idea is to be able to apply it on a large number of OSS projects and, therefore, without modifying them.
I think I get it now
myinit-script.gradle
if (hasProperty('extraDependencies')) {
def extraDeps = property('extraDependencies').split(',')
allprojects {
buildscript {
dependencies {
classpath extraDeps
}
}
}
}
command line
gradlew --init-script myinit-script.gradle -PextraDependencies=org.foo:bar:1.0,org.foo:baz:1.2 build

Gradle's publishToMavenLocal task is not executed correctly

I'm trying to create a gradle based multi-module project. There is also an project that contains different gradle scripts that enables pluggable build configurations. One of those scripts is for publishing artifacts to maven repository. This is the content of that script:
apply plugin: 'maven-publish'
configure(subprojects.findAll()) {
if (it.name.endsWith('web')) {
publishing {
publications {
mavenWeb(MavenPublication) {
from components.web
}
}
}
} else {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
}
}
build.dependsOn publishToMavenLocal
This script is included in the build gradle file of other project.
apply from: '../../food-orders-online-main/artifact-publish.gradle'
When I run build task it always shows that publishToMavenLocal task is up to date and I cannot find the artifacts in the local repository. Am I doing something wrong?
By adapting answer from here, it works for me.
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
repositories {
mavenLocal()
}
}
I think this could be a manifestation of a bug with gradle, that modules can lose the publishMavenJavaPublicationToMavenLocal task when they are depended upon in a certain way.
If gradle determines that there is no publishMavenJavaPublicationToMavenLocal task for a module then the publishToMavenLocal task will always report that it is up to date.
The specific case I have found occurs in a multimodule setup, with multiple levels of nested modules. It can be summarised as follows, where shared:domain loses its publishMavenJavaPublicationToMavenLocal when depended upon by A
root
root gradle build file
->A
own gradle build file with dependency on shared:domain
-> shared
gradle build file for shared modules
-> shared:domain
-> shared:B
I have created a small example project demonstrating this behaviour available here - https://github.com/piersy/Gradle2MavenPublishBug
I have also logged a bug with gradle here - http://forums.gradle.org/gradle/topics/the-publishmavenjavapublicationtomavenlocal-task-disappears-from-a-project-when-that-project-is-depended-upon-in-a-specific-way
For now the workarounds I have found are to
Remove A's dependency on shared:domain
Make A a submodule with its configuration specified in its parent module build file
Give shared:domain its own gradle build file

Gradle dependency to project in buildscript

Trying to get my head around if it is possible to use Tasks from other projects in Gradle. Let's say ProjectB is a project with src/main/groovy containing com.MyTask, having parent ProjectA
In build.gradle in ProjectC, also having parent ProjectA:
buildscript {
dependencies{
project(':ProjectB')
}
}
That seems to be legit, because introdusing a typo in "project(:'ProjectB')" fails hard. What also fails is introducing this line:
import com.MyTask
Is project-references not valid in buildscript closure? Also tried moving com.MyTask to buildSrc/src/main/groovy with the same amount of success.
The solution which worked for me was to make "com.MyTask" available both at configurationtime and in sources.
ProjectA(the parent) got this added to buildSrc/build.gradle's sourceSets:
sourceSets{
main{
groovy{
srcDir 'ProjectB/src/main/groovy'
}
}
}
Now ProjectC and all other projects can use MyTask. At the same time it is bundled with the final jar of ProjectB.
The issue has also been discussed thoroughly between between Adam Murdoch, Luke Daley and Steve Ebersole: http://gradle.1045684.n5.nabble.com/buildSrc-as-a-regular-project-td5677255.html
Edit: It was smarter manipulating parent buildSrc than the standalone project. That way IntelliJ is happy-go-lucky.
From Gradle documentation 15.4. Adding dependencies to a task:
Example 15.13. Adding dependency on task from another project
build.gradle
project('projectA') {
task taskX(dependsOn: ':projectB:taskY') << {
println 'taskX'
}
}
project('projectB') {
task taskY << {
println 'taskY'
}
}

Resources