Gradle project / task dependency & JavaScript lib in war - grails

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
}

Related

Gradle - "override" behaviour/properties from build.gradle

I'm not a Gradle expert by any means so please be gentle...
I have a Gradle build which I'm trying to run on Jenkins. The build.gradle contains the following:
repositories {
maven {
url "http://some_internal_corporate_repo"
}
}
The Jenkins server that I am running the job on cannot access "some_internal_corporate_repo".
As I can't modify the build.gradle I would like to know if there's a way I can somehow extend or override the build.gradle, on the Jenkins server, to point to mavenCentral (or similar), maybe via an init file or setting a property etc?
Thanks in advance
EDIT: in the end, because I was using Jenkins, I used it's Groovy support (execute Groovy build step) to address my issue:
def file = new File('build.gradle')
def newConfig = file.text.replace('url "http://some_internal_corporate_repo"', 'url "http://repo.maven.apache.org/maven2/"')
file.text = newConfig
You can define multiple repositories.
The order of declaration determines how Gradle will check for dependencies at runtime
repositories {
maven {
url "http://some_internal_corporate_repo"
}
mavenCentral()
}
You can use a properties to define the maven repo url:
repositories {
maven {
url "${repositories_maven_url}"
}
}
In the gradle.properties file
repositories_maven_url=maven_url
According to the gradle documentation, gradle.properties files are applied in the following order:
gradle.properties in project root directory.
gradle.properties in GRADLE_USER_HOME directory.
system properties, e.g. when -Dgradle.user.home is set on the command line.
Or you can use something like this:
repositories {
maven {
url getMavenUrl()
}
}
/**
* Returns the url of the maven repo.
* Set this value in your ~/.gradle/gradle.properties with repositories_maven_url key
* If the property is not defined returns a default value
* #return
*/
def getMavenUrl() {
return hasProperty('repositories_maven_url') ? repositories_maven_url : "YOUR_DEFAULT_VALUE"
}

Could not resolve all files for configuration gradle build

I want tagsoup jar as dependency for one of my test case which reads a html.
In my build.gradle I have done these changes
asciidoctorj {
version = '1.5.4'
}
repositories {
maven {
url "http://mvn-nexus.my.company:8081/nexus/content/groups/public/"
}
mavenCentral()
}
compile(
'org.codehaus.groovy:groovy-all:2.4.14',
'org.codehaus.groovy.modules.http-builder:http-builder:0.7',
'org.apache.httpcomponents:httpclient:4.5.2',
'org.apache.httpcomponents:httpmime:4.5.2',
'commons-cli:commons-cli:1.2',
'ant:ant:1.7.0',
'com.cloudbees:groovy-cps:1.19',
'org.codehaus.gpars:gpars:1.2.1'
)
testCompile(
'junit:junit:4.12',
'org.codehaus.groovy:groovy-all:2.4.14',
'org.spockframework:spock-core:1.1-groovy-2.4',
'org.mockito:mockito-core:2.12.0',
'com.athaydes:spock-reports:1.4.0',
'org.slf4j:slf4j-api:1.7.13',
'org.slf4j:slf4j-simple:1.7.13',
'com.lesfurets:jenkins-pipeline-unit:1.0',
'org.ccil.cowan.tagsoup:1.2.1'
)
varsCompile sourceSets.main.output
}
But I get the following error in my jenkins build while building this project
What went wrong:
Could not resolve all files for configuration ':testCompileClasspath'.
Could not find org.ccil.cowan.tagsoup:0.9.7:.
Required by:
project :
What am I missing?
You miss the artefact name. Try :
'org.ccil.cowan.tagsoup:tagsoup:1.2.1'

Gradle ant subproject dependency ordering

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')?

How to upload artifact to network drive using gradle?

I am reading this:
http://www.gradle.org/docs/current/userguide/artifact_management.html
to understand how to publish/upload my artifact to a network drive/fileshare which is a requirement (we have a maven repo up and running but some artifacts needs to be dumped on a fileshare). The examples I have found are more focused on deploying to repositories, maven, ivy, etc.
I have a simple eclipse java project that I build using gradle 1.2 with the following build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src'
}
}
test {
java {
srcDir 'test'
}
}
}
repositories {
flatDir {
name "fileRepo"
dirs "file://internal.newtwork.drive/folder/test"
}
}
uploadArchives {
repositories {
add project.repositories.fileRepo
}
}
Where in the gradle docs can I read about how to copy resources to a remote fileshare?
I have tried to update the protocol and the dir attribute based on the below answers but I get this error:
What went wrong:
Execution failed for task ':uploadArchives'.
Could not publish configuration ':archives'.
java.io.FileNotFoundException: /internal.newtwork.drive/folder/test/sample-gradle-java-unspecified.jar (No such file or directory)
The destination is correct so does the flatDir repo not support networkdrives?
You should define the following parameters:
archivesBaseName = 'yourappname'
group = 'your.app.package'
version = '1.0.0'
Your URL doesn't mention a scheme (http:, file:, etc.). I don't know if you can get away with using a file: URL, or whether you need to us a different syntax to specify a directory rather than an HTTP URL, but either way, you'll need to correctly form the URI for the Windows UNC path.
See this question for more details.
It looks like you're crossing your wires. The url would only be part of that ivy repository declaration which you're apparently not using. The filesystem repository would be handled by the flatDir block which is then referenced by the add project.repositories.fileRepo statement. I'd suggest trying the full path in the flatDir dir variable, otherwise the path of least resistance may just be to throw together a simple manual file copy (or other transfer) task which is then added on to the main deploy task you're using.
//Try this,
apply plugin: 'java'
apply plugin: 'maven'
repositories {
maven {
url "$archivaUrl"`enter code here`
credentials {
username = "$userName"
password = "$passWord"
}
}
}
// Dependencies
dependencies {
// specify the lib files at compile and run time
compile fileTree(dir: 'lib', include: ['**/*.jar','*.jar'])
runtime fileTree(dir: 'lib', include: ['**/*.jar','*.jar'])
}
// source path
sourceSets {
main {
java {
srcDirs 'src'
}
}
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: "$archivaUrl") {
authentication(userName: "$userName", password: "$passWord")
}
pom.version = "1.0-SNAPSHOT"
pom.artifactId = "fd-common"
pom.groupId = "com.somename.common"
}
}
}

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