Gradle multi module dependencies with Continuous Integration - jenkins

Just starting with Android Studio/Gradle/CI, I have an Android Studio project setup with a structure resembling this:
┌ Project
│
├── Module "lib-core" (produces .aar)
│
├── Module "lib-v1" (produces .aar, depends on "core-lib")
│
├── Module "lib-v2" (produces .aar, depends on "core-lib")
│
├── ... (potentially mode libs)
│
└── Module "test-app" (produces .apk, depends on "lib-v1" and "lib-v2")
"lib-core" is used directly only from inside this project, while "lib-v1" and "lib-v2" can also be used from other projects ("test-app" is a sample project to show the usage of "lib-s") and need to be on our Maven repo as aar-s.
This project is also built with Jenkins and the artifacts go to a local Maven repo (Sonatype Nexus). This is achieved through "assembleRelease uploadArchives" tasks. As a part of the CI, the projects need to be versioned accordingly. Ideally, all lib modules (actually their artifacts) should be kept at the same version.
Now to address the issue: Let's say I've bumped the version to 1.4.2. Now, when Jenkins tries to evaluate the build scripts, it complains that "lib-core" with version 1.4.2 does not yet exist, which is true. This is the case where "lib-v1" would have the dependency to "lib-core" via 'compile "org.example:lib-core:1.4.2#aar"'
If, on the other hand, "lib-v1" declares the dependency to "lib-core" via 'compile project(":lib-core")', the produced pom.xml on the Nexus-repo (for "lib-v1") doesn't include the correct reference to "lib-core"... Unfortunately I currently don't have access to a sample but if I remember correctly the groupId is something on the line of "unresolved", "unspecified" or similar. So in that case "lib-v1" can't be used further down the pipeline (using { transitive = true } to resolve "lib-core")
Is there a way to setup the build script so the "lib-core" would be built and its artifact uploaded before evaluating the other modules, but without splitting this into multiple projects? Or some other way of setup which would enable building of this project both on the developer machine and the CI server?
It somehow seems I'm over-complicating things and this could be accomplished in some other (simple) way, I'm just not seeing it currently.
EDIT
When I declare the dependency with 'compile project(":lib-core")' I get the following in pom.xml for "lib-v1" on the Nexus repo:
<dependency>
<groupId>Library</groupId>
<artifactId>lib-core</artifactId>
<version>unspecified</version>
<scope>compile</scope>
</dependency>
artifactId is correct, but groupId is the module name, while the version is "unspecified" - so the project using "lib-v1" can't resolve the "lib-core" dependency.

I do not think it's possible to do "built and its artifact uploaded before evaluating the other modules," due to gradle has to complete "Configuration" phrase before "Execution" phrase During "Configuration" phrase, gradle will try to evaluate all dependencies in all modules.
However, "declares the dependency to "lib-core" via 'compile project(":lib-core")'" should works for you and we have similar set-up as yours which works ok. Maybe somethings wrong with module gradle/version in your build.gradle. If you can provide more details, e.g. pom.xml and build.gradle, it will be more clear.
Could you try following in your build.gradle at Project level.
allprojects {
group = 'Library'
version = '1.4.2.'
}

Related

Jenkins Pipeline - Workflow CPS plugin JAR dependencies

I'm implementing unit tests for code used in a Jenkins Pipeline Shared Groovy Library. Specically, I need to mock the steps object available in the Jenkinsfile, which is an instance of org.jenkinsci.plugins.workflow.cps.DSL. In my Gradle build I've specified a dependency like so:
testCompile group: 'org.jenkins-ci.plugins.workflow', name: 'workflow-cps', version: '2.30', ext: 'jar'
which is the project hosting the class above. Without specifying the ext as a JAR, Gradle retrieves the .hpi file since this is the packaging defined in the project's pom.xml; obviously I need to override this and fetch the JAR for my project. However, in doing this Gradle does not download the transitive dependencies of the workflow-cps JAR and I find myself having to populate my build.gradle with all the dependencies determined via trial and error. Is there a way to retrieve the transitive dependencies, or is this a limitation of the workflow-cps project and how it defines its pom.xml?
The CPS class you're wanting to mock won't contain methods/variables introduced by plugins or your workflow lib, so this approach probably won't be fully satisfying.
Facing the same challenge I took the pragmatic approach of making my own TestScript interface in my test sources and Mock that, and not typing the script reference in classes.
The drawbacks are not having IDE code inspection for stuff referencing the script, and having to manually add signatures to TestScript as I add tests (which is also error-prone, since I have manually ensure that those signatures match).
But it works, and avoids getting dragged into plugin dependency hell.

Grails Project missing Java library at runtime

I was trying to add some Java Libraries (AWS SDK for Java, Apache Commons Math, etc.) to my Grails project since some of my Java source code (placed in src/java) had dependencies. By following this answer, I was able to resolve compile errors by adding the jar files to the /lib folder and add it to the build path, as answered here: Add Java Libraries to a Netbeans Grails Project
However, when I call my Java source code from my controller during runtime, it is unable to find the Java libraries that I added, showing a NoClassDefFoundError. Should I be adding something to the BuildConfig.groovy file? I'm not sure what the name convention for the jar files to be added to the dependencies.
The question you refer to is 5 years old. You should use newer resources :)
The preferred approach now is to use dependencies in BuildConfig.groovy, and let Grails (via Ivy or Maven) download the jars for you once and reuse them for various projects.
It's not always obvious what the syntax is, and I find that http://mvnrepository.com/ is a great resource. For example if you search for "commons math" and click through to http://mvnrepository.com/artifact/org.apache.commons/commons-math you'll see a few versions. Click on version 2.2 and you'll see the Maven dependency XML but you can click on the Gradle tab and it's going to be similar to what you need for Grails. So I'd add
dependencies {
compile 'org.apache.commons:commons-math:2.2'
}
and if necessary change compile to runtime, build, etc. depending on what you need the jar in the build process.
In the rare case that you do have a jar that isn't available in a Maven repo (e.g. a shared library at your company) then you can put the jar file in the lib directory. As you've seen, Grails doesn't auto-detect it (this is as of version 2.0). But you can run grails compile --refresh-dependencies to get your jar added to the classpath.
My issue turns out to be the fact that AWS Java SDK had dependencies (Apache HTTP Client) that were not installed yet and that I was unaware of.
This is what I had to configure this for my BuildConfig.groovy file
dependencies {
runtime 'org.apache.httpcomponents:httpclient:4.2.5'
runtime 'com.amazonaws:aws-java-sdk:1.4.7'
}
All the dependencies for AWS Java SDK 1.4.7 can be found here: http://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk/1.4.7. All the dependencies outside of HTTP client were already installed for me, but may not be for your Grails setup.

How do I make the compile of one maven 3 project depend on the install of another?

I have a directory with a pom.xml and several subdirectories with their own pom.xml files
One subdirectory is local called thirdparty. It contains several jar files and installs them to the local maven repo when a mvn install is executed. These are needed by the mvn compile phase of the other artifacts. The root pom.xml simply executes the same step on each child pom.xml.
I'd like to modify the root pom.xml so that mvn compile will do an install on the third party folder before executing the other folders. I tried this in the maven-compiler-plugin:
<executions>
<execution>
<id>thirdparty</id>
<phase>install</phase>
</execution>
</executions>
I see nothing in the documentation about specifying a phase in a dependency element.
To make sure I have this straight, it sounds like you have an aggregator pom, AGG, and some submodules, A and B, where A is nothing but some third-party jars that have to be installed in the local repo before B will compile. If that's true, then two possibilities spring to mind:
1) Do away with A and instead install the third party jars into an appropriate standalone repo, like a local Nexus server, and add that repo to your pom. That would be the "Maven" way of doing it.
2) Add a dependency on A to B's <dependencies>. In A, configure the install plugin with an execution per jar that needs to be installed, and bind these executions to the compile phase. Then when you run compile on AGG, it will first run compile on A, which will install all the jars, followed by compile on B. Note that this will have the side effect of producing an A.jar, which will be a dependency of B, because maven assumes that every module produces exactly one artifact of some type. You might be forced to add at least one class or resource so that A.jar can actually be built. Not sure about that one. Alternately, you could experiment with setting A's packaging to "pom".
I believe you are using Maven in a wrong way.
Such kind of 3rd party dependencies should be put to local repository (or your internal Maven repository) before you run the compilation work, and dependencies in your project should be setup accordingly. "Installation of 3rd party artifacts" shouldn't be part of the build process.
And, in Maven world, we rarely have 3rd party libs exists as part of the source code. In fact one of the reason for using Maven is to get rid of such kind of libs in source code.
Sounds like you want a couple of dependancies. Look into the depends element.

Jenkins dependencies from sbt dependencies?

Is it possible to automatically sync Jenkins build dependencies with sbt dependencies? For example, if project B's build.sbt says that project A (which I also wrote) is a dependency of it, can the Jenkins build for project B be made to automatically detect this fact - and detect any other dependencies that may be added or removed to the build.sbt file in future?
You could use the ScriptTrigger Plugin to write the appropriate code. Or you could write your own plugin and look at IvyTrigger or Maven Dependency Update trigger. That might make a good enhancement to the sbt plugin.

Why is Grails taking the jar dependencies instead of the existing maven project dependencies?

I'm using IntelliJ IDEA 10.0.2 (with groovy/grails support), maven 2.2.1 and grails 1.3.6.
We have a big maven project, which depends on many other maven projects. Let's say the workspace structure looks as follows:
backend-project (Java project, without further project dependencies)
output-project (Java project, without further project dependencies)
frontend-project (Grails project, which dependes on both, backend and output)
That means, within my frontend-project's pom.xml I have defined 2 Project Dependencies:
e.g.
<dependency>
<groupId>com.company.project</groupId>
<artifactId>backend-project</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.company.project</groupId>
<artifactId>output-project</artifactId>
<version>${project.version}</version>
</dependency>
Let's assume that I change some Java Source within the output or backend project. When I
run the grails application now, then it won't consider the changes. I have to publish the changed artifact locally and then resolve it again by the grails project before running the application in order to take effect.
This tells me that the grails project just depends on the project dependency jars within the maven repository and does not care about any existing project dependency "sources" within the workspace.
Does it have to be that complicated and if so, why?
Note that if my frontend project was a spring web project, the changes will be seen in IDEA and tomcat will even reload the change dynamically.
Note that when IDEA recognizes a mavenized grails project, it won't run the grails project with: "grail run-app" anymore but with a more complicated version of: "mvn grails:exec -Dcommand=run-app". Don't know if this is of any relevance..
Thanks!
Mr. Slash
Maven always picks up the jar files from the repositories (local and then remote etc depending on your pom.xml config).
Think about it: How would your main project know where the backend-project or the output-project files are located?
If you want a direct dependency then remove it from pom.xml and modify the project build path to directly add the projects' outputs to your main projects. In Eclipse open the properties page of the main project => build path => projects => add.

Resources