Gradle ant subproject dependency ordering - ant

I've got a project with 6 subprojects that have ant build.xml files in them. I'm trying to write a top level gradle file that will do the ant 'default' task on all the projects, respecting their order dependencies. So I have this in settings.gradle (which happens to be the order I want them run in):
include 'core', 'api-web', 'execution', 'cluster', 'persistence', 'choreo-tests'
And I have this in my top level build.gradle:
project(':api-web') {
dependencies {
compile project(':core')
}
}
project(':execution') {
dependencies {
compile project(':api-web')
}
}
project(':cluster') {
dependencies {
compile project(':execution')
}
}
project(':persistence') {
dependencies {
compile project(':cluster')
}
}
project(':choreo-tests') {
dependencies {
compile project(':persistence')
}
}
And then each directory has this in its build.gradle:
ant.importBuild 'build.xml'
However, if I try to run this:
gradle --info default
I get this output:
> Could not find method compile() for arguments [project ':core'] on org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated#4d12bc7b.
I don't understand, since the build.xml files all have a compile target. Is there something I need to do to have the ant build.xml files get loaded into their own namespace?
Or, more specifically, after having loaded these subprojects, which contain gradle tasks created from the ant targets, how can I specify the dependencies between subprojects tasks? Every build.xml I have has a 'default' task. How do I specify that my 'default' task in project(':api-web') depends on the 'default' task of project(':core')?

Related

Creating Jenkins pipeline using a multi-project gradle build

I have a multi-project Gradle build working locally.
There is a parent gradle file, build.gradle
The settings.gradle file assigns the projects to their respective gradle build files:
include 'load'
include 'loadRemote'
project(':loadRemote').buildFileName = 'remoteLoad_build.gradle'
project(':load').buildFileName = 'load_build.gradle'
rootProject.name = 'EquipLoad'
The build.gradle parent file calls a buildAll command to build the 2 projects from the command line locally.
I created a Jenkins file to build both projects. But the Jenkins pipeline does not recognize the specific project tasks.
These are the tasks for the buildAll command
gradle.projectsEvaluated {
task compileAll (dependsOn: [project(':loadRemote').remoteLoadCleanCompileStage]) {
compileAll.finalizedBy project(':load').loadCleanCompileStage
}
task packageAll (dependsOn: [project(':loadRemote').remoteLoadPackage]) {
packageAll.finalizedBy project(':load').loadPackage
}
task buildAll (dependsOn: [compileAll]) {
buildAll.finalizedBy packageAll
}
}
The error in Jenkins is that it does not recognize the task project(':loadRemote').remoteLoadCleanCompileStage
How can I identify a multi-build project in Jenkins?
Do I have to add the settings.gradle file?
UPDATE
I thought that the different build files could not be located in the project so I added this to the settings.gradle file
rootProject.name = 'EquipLoad'
include 'load'
project(':load').projectDir = new File(settingsDir, rootProject.rootDir.getAbsolutePath() + "/Load")
project(':load').buildFileName = 'load_build.gradle'
include 'loadRemote'
project(':loadRemote').projectDir = new File(settingsDir, rootProject.rootDir.getAbsolutePath() + "/LoadRemote")
project(':loadRemote').buildFileName = 'remoteLoad_build.gradle'
The error is still the same, the build.gradle file (parent) does not recognize the dependency task project(':loadRemote').remoteLoadCleanCompileStage
Looking at the debug statements, the child build gradle files are found and identified:
Evaluating project ':loadRemote' using build file '/var/.../loadRemote/remoteLoad_build.gradle'.
The same text is shown for the load build file.
Yet the tasks within these gradle build files are not recognized in the parent build.gradle file.
The problem was a simple case sensitive mistake.
I named the folders: Load and LoadRemote. But identified them in the gradle scripts as ':load' and ':loadRemote'. By changing the script text to ':Load' and ':LoadRemote' fixed my problem.

How perform OpenJPA Enhancement when using Gradle?

I've tried this gradle plugin https://github.com/schmutterer/gradle-openjpa but it complains that it cannot find certain libraries and doesn't support providedCompile which makes this unusable for me anyway.
I've also tried calling ANT tasks, my latest attempt below is throwing:
Caused by: C:\Work_Java\workspace\PaxHoldRelease\jpa_enhance.xml:5: taskdef class org.apache.openjpa.ant.PCEnhancerTask cannot be found
build.gralde
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'ear'
// Java compilier compliance level
sourceCompatibility = 1.7
targetCompatibility = 1.7
repositories {
mavenLocal()
mavenCentral()
}
ant.importBuild 'jpa_enhance.xml'
war.dependsOn enhance
dependencies {
// Ensure ear plugin gets war file
deploy files(war)
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
compile 'javax.websocket:javax.websocket-api:1.1'
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.16'
compile 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.1'
compile 'org.glassfish:javax.json:1.0.4'
providedCompile 'org.apache.openjpa:openjpa:2.2.2'
providedCompile 'com.sybase:jconn3:6.05'
providedCompile files('libs/sqljdbc4-3.0.jar')
}
jpa_enhance.xml
This is the latest version in a long list of attempts and probably complete rubbish as I just ripped everything out in a fit of desperation :-(
<project>
<target name="enhance">
<taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask"/>
<!-- invoke enhancer on all .java files below the model directory -->
<openjpac>
</openjpac>
<echo message="Enhancing complete!"/>
</target>
</project>
Try this Andrew - I loosely based this gradle on the nice Enhancer script provided on S.O. by another member (for the DataNucleus enhancer).
Note that you will need to modify the entity-files (include/exclude) to point to your specific 'to be/to not be' enhanced Java source files. Further, this approach assumes that classpath derives from your parent build.gradle.
task openJPAEnhance {
description "Enhance JPA model classes using OpenJPA Enhancer"
dependsOn compileJava
doLast {
// define the entity classes
def entityFiles = fileTree(sourceSets.main.output.classesDir).matching {
include 'org/foo/mypkg/entity/*.class'
exclude 'org/foo/mypkg/entity/DoNotEnhance.class'
}
println "Enhancing with OpenJPA, the following files..."
entityFiles.getFiles().each {
println it
}
// define Ant task for Enhancer
ant.taskdef(
name : 'openjpac',
classpath : sourceSets.main.runtimeClasspath.asPath,
classname : 'org.apache.openjpa.ant.PCEnhancerTask'
)
// Run the OpenJPA Enhancer as an Ant task
// - see OpenJPA 'PCEnhancerTask' for supported arguments
// - this invocation of the enhancer adds support for a default-ctor
// - as well as ensuring JPA property use is valid.
ant.openjpac(
classpath: sourceSets.main.runtimeClasspath.asPath,
addDefaultConstructor: true,
enforcePropertyRestrictions: true) {
entityFiles.addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet)
}
}
}
I hope this helps, and the individual who wrote that first gradle script did not mind that we re-purposed it (from DataNucleus) to OpenJPA.

Gradle project / task dependency & JavaScript lib in war

We have just started using Gradle and do have a few (noob) questions - hopefully someone can shed some light on those issues :)
We're using Angular and Grails to build our web-app. We want to be as modular as possible and hence put all the Angular-related artifacts (mainly *.js and *.html files) in a separate project in our Gradle multiproject build.
Our project structure is as follows:
- root
-- build.gradle
-- settings.gradle
|-- web-grails (grails project)
|----- build.gradle
|-- web-js-html (angular / js / html sources)
|----- build.gradle
As a start, we simply want to package web-js-html project accordingly. What we've come up so far (other suggestions very welcome) is to apply a webjars structure to it, i.e. have a .jar file with the required resources under /META-INF/resources. Online, we found the following config that seems to work just fine:
// file :web-js-grails/build.gradle
apply plugin: 'java'
ext {
webjarconfig = [
staticHTMLFilesDir : "${projectDir}/src/main/webfrontend",
baseDir: "META-INF/resources/",
subDir : "webjars/" + deployed_app_name
]
}
configurations {
webjar
}
task webjar(type: Jar, dependsOn: 'jar') {
from(fileTree(webjarconfig.staticHTMLFilesDir)) {
into webjarconfig.baseDir + webjarconfig.subDir
}
outputs.file archivePath
}
artifacts {
webjar(webjar.archivePath) {
type 'jar'
builtBy webjar
}
}
By invoking 'gradle webjar', the jar gets created with the files in the correct place.
Question 1:
What I would have expected is that this jar also gets properly created if I invoke 'gradle build'. As far as I understand, 'gradle build' is a task defined by the java plugin which, at some point, invokes the 'jar' task. Once that 'jar' task is done, I would expect the webjar task to be invoked. But it's not, so clearly I'm missing something. Does it follow that webjar only ever gets executed if explicitly invoked (either from command-line or from within the build.gradle file)?
Now, we would like the webjar to be included in the web-grails war-file. The config of :web-grails/build.gradle is as follows:
apply plugin: "grails"
repositories {
mavenLocal()
maven { url artifactory_url }
}
buildscript {
repositories {
mavenLocal()
maven { url artifactory_url }
}
dependencies {
classpath 'org.grails:grails-gradle-plugin:2.0.1-SNB1'
}
}
grails {
grailsVersion = '2.3.8'
groovyVersion = '2.3.0'
}
dependencies {
bootstrap 'org.grails.plugins:tomcat:7.0.50'
compile project(':web-js-html')
}
After try-and-error and quite a bit of reading, I arrived at this (possibly wrong) conclusion: when I invoke 'gradle build' on :web-grails, then (I assume) :build will also be invoked on the referenced :web-js-html project. I say this because the jar gets re-created in the build/lib folder, but obviously not using the webjar-task. Hence, the resulting jar only contains the MANIFEST.MF only.
Question 2:
Do I use Gradle correctly in that case and am I only overseeing a little thing or is this whole approach questionable? How can I get the :web-js-html jar into the war properly?
Thank you for your help in advance!
Your part where you define the new artifact doesn't make any sense for me. Change
artifacts {
webjar(webjar.archivePath) {
type 'jar'
builtBy webjar
}
}
to
artifacts {
webjar webjar
}
Maybe you should rename either your configuration or your task. However the first webjar is your configuration and the second one your task which creates the new jar.
Note that this will create a new artifact, so you have to give it a different name with
task webjar(type: Jar, dependsOn: 'jar') {
baseName = 'newJar'
from(fileTree(webjarconfig.staticHTMLFilesDir)) {
into webjarconfig.baseDir + webjarconfig.subDir
}
outputs.file archivePath
}
But I think you don't want to create a second jar, but change the original one. In that case your don't have to write a new task, but configure the default jar task like this:
jar {
from(fileTree(webjarconfig.staticHTMLFilesDir)) {
into webjarconfig.baseDir + webjarconfig.subDir
}
outputs.file archivePath
}

Jenkins build for project with provided dependencies

While I am building Gradle based project via Jenkins I'm getting compilation errors. It occurs because a have several jars in build.gradle file with scope 'provided'. I need this to do not include them into generated jar-file. How can I specify path or smth else to let project build on integration server?
Thanx in advance.
Listing of build file provided
configurations {
provided
}
sourceSets {
main {
java { srcDir 'src/main/java' }
resources { srcDir 'src/main/resources' }
compileClasspath += configurations.provided
}
}
dependencies {
provided 'somelib1'
provided 'somelib2'
provided 'somelib3'
}

Classpath for ant plugins when using ANTBuilder from Gradle

I have a build.gradle file which loads PMD (downloading it from upstream Maven), and then loads an Ant build.xml file which requires PMD:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'pmd:pmd:4.2.5'
}
}
ant.importBuild 'shared-build.xml'
However, the Ant import fails:
taskdef class net.sourceforge.pmd.ant.PMDTask cannot be found
using the classloader AntClassLoader[]
at org.apache.tools.ant.ProjectHelper.addLocationToBuildException(ProjectHelper.java:551)
[...]
at org.gradle.api.internal.project.DefaultAntBuilder.importBuild(DefaultAntBuilder.groovy:76)
How can Gradle's ant integration be instructed to make this available?
There's no straighforward way to do it, as Gradle does not offer any API support for this. So you need to hack it some way.
For example, you can do something like this, right before calling ant.importBuild
org.apache.tools.ant.Project.class.classLoader.addURL( file('libs/somelib.jar').toURI().toURL() )
Alternatively you can call the addURL() method with the paths you get through the Gradle's dependency resolution (again, this should be executed before the call to ant.importBuild).
configurations { someconf }
dependencies { someconf "org.eclipse.jdt:ecj:3.6.1" }
def antClassLoader = org.apache.tools.ant.Project.class.classLoader
configurations.someconf.each { File f ->
antClassLoader.addURL(f.toURI().toURL())
}
Of course, another solution would be to have the classpath defined inside your build.xml file so you won't have to do anything from Gradle.
See some input here http://gradle.1045684.n5.nabble.com/How-to-add-to-classpath-for-ant-importBuild-td3268631.html

Resources