How to retrieve the current dependencies in a Grails 3.2 script - grails

Context
I created a Grails 3.2.11 script with the next command:
grails create-script script-test
The above command generated the file: script-test.groovy.
Then, I need to verify if a jar file dependency is present at the current grails project.
At Grails 2.4 you could do that with a grailsSettings.runtimeDependencies call:
def verifyJarDependency(String dependencyName) {
//Gets all Grails Application dependencies.
def dependenciesInstance = grailsSettings.runtimeDependencies
//Defines the result variable
def result = false
//Adds references to all classes used in Grails Application.
dependenciesInstance?.each { dependencyFile ->
//Gets the file name
String fileName = dependencyFile.name
//Verifies if the actual file contains the Dependency file string
if (fileName.contains(dependencyName)) {
//There is a Jar file with the Dependency string.
println "The Dependency file found is: $dependencyFile"
result = true
}
}
//If there is no Dependency jar file it returns false.
return result
}
For example if you execute the next piece of code inside a grails 2.4 script file:
target(buildPlugin: "Retrieves all the jar files which this instance is using") {
//Gets all Grails Application dependencies.
def dependenciesInstance = grailsSettings.runtimeDependencies
dependenciesInstance?.each { dependencyFile ->
//There is a Jar file with the Dependency string.
println dependencyFile
}
}
setDefaultTarget(buildPlugin)
You will get an output like next:
/home/username/.sdkman/candidates/grails/2.4.3/lib/org.grails/grails-datastore-simple/jars/grails-datastore-simple-3.1.2.RELEASE.jar
/home/username/.sdkman/candidates/grails/2.4.3/lib/org.grails/grails-datastore-gorm/jars/grails-datastore-gorm-3.1.2.RELEASE.jar
/home/username/.sdkman/candidates/grails/2.4.3/dist/grails-plugin-converters-2.4.3.jar
/home/username/.sdkman/candidates/grails/2.4.3/dist/grails-plugin-mimetypes-2.4.3.jar
/home/username/.sdkman/candidates/grails/2.4.3/lib/com.h2database/h2/jars/h2-1.3.176.jar
/home/username/.sdkman/candidates/grails/2.4.3/lib/log4j/log4j/jars/log4j-1.2.17.jar
/home/username/.sdkman/candidates/grails/2.4.3/dist/grails-resources-2.4.3.jar
This information will be used later for Proguard in order to obfuscate the jar file.
Question
How I can retrieve the current Grails 3.2 project dependencies inside a custom script?

You can execute "gradle dependencies" in custom script:
description "Project dependencies", "grails list-dependencies"
println gradle.dependencies()
and parse output

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"
}

Getting version info and build data from grails war file

In my application the user has the option to upload a war file to update the software.
I want to get some version information from the war file, before I deploy it to my server. How can I do this?
This information would be useful for me:
def jversion=[
"buildDate": grailsApplication.metadata["build.date"],
"version": grailsApplication.metadata["app.version"],
"branch": grailsApplication.metadata["GIT_BRANCH"],
"buildNumber": grailsApplication.metadata["build.number"],
"gitCommit": grailsApplication.metadata["GIT_COMMIT"]
]
What information can I get from the war file and how?
Best regards,
Peter
For this purpose you can add a script to the grails application that adds this information to a file whenever the user builds the war. Create a new script file under ./scripts in grails app with name _Events.groovy. Here you can hook into different grails events that gets triggered when an app starts or war gets built.
You can use eventCreateWarStart event to log the information whenever war gets built. Below is some sample code that can help you get started. It fetches the current branch name and commit id from local git and stores the data to a file named application.properties.
eventCreateWarStart = { warName, stagingDir ->
addBuildInfo("${stagingDir}/application.properties")
}
private void addBuildInfo(String propertyFile) {
def jVersion = [
"appName" : grailsApp.metadata['app.name'],
"version" : grailsApp.metadata["app.version"],
"buildDate" : new Date(),
"branch" : getBranch().trim(),
"Commit" : getRevision().trim(),
"buildNumber": System.getProperty("build.number", "CUSTOM"),
]
File file = new File(propertyFile)
file.text = ""
jVersion.each {
key, value ->
file.text += "${key}:\t${value}\n"
}
}
def getBranch() {
Process process = "git rev-parse --abbrev-ref HEAD".execute()
process.waitFor()
return process.text ?: 'UNKNOWN'
}
def getRevision() {
Process process = "git log --oneline --no-abbrev-commit -1".execute()
process.waitFor()
return process.text ?: 'UNKNOWN'
}
There is a grails plugin also that claims to fetch build properties from Hudson/Jenkins, if they are being used for building the war.
Grails 3.0.9, in GSP, you can get info from META-INF file. Try these
${grails.util.Metadata.current.getApplicationVersion()}
${grails.util.Metadata.current.getEnvironment()}
${grails.util.Metadata.current.getApplicationName()}
But i don't know how to get build date info.
For grails 3 you can use buildProperties task to add any custom information to war such as build date, verion info, git revision etc.
buildProperties {
inputs.property("info.app.build.date", new Date().format('yyyy-MM-dd HH:mm:ss'))
}
See this article for how to do the same http://nimavat.me/blog/grails3-add-custom-build-info-to-war

how to create a simple build script for grails 2.5

I have read the documentation here, which gives the structure, but does not offer any help on how to create the actual logic.
I want to build a very simple script which does a clean, creates the war, creates a zip of the sources (without the target directory, and without any svn dirs), and creates a tar (idealy gzipped) of the migrations dir so this can be used with liquibase. Each of these 3 artifacts should have the app version in their name (like the existing "grails war" does.
The project structure looks like this:
svn
main-app
grails-app
migrations
target
:
exploded-plugin-1
grails-app
:
exploded-plugin-2
grails-app
:
This is how far I have got:
includeTargets << grailsScript("_GrailsInit")
target(packageUs: "Creates war, zips source, tars liquibase scripts") {
depends(clean, war-us, zip-source, tar-liquibase)
}
setDefaultTarget(packageUs)
target ("war-us" : "creates war") {
ant.war() // this was a guess at calling the existing war - it doesnt work
}
target ("zip-source" : "zips sources") {
// cd to top dir of project, i.e. above the app.
}
target ("tar-liquibase":"produces tar of migrations dir") {
// tar up the migrations dir
// name it with the app-version
// put it in the target dir along side the war etc.
}
target ("clean") {
// call the default clean some how, or cd to target dir, and delete everything
}
The above script was originally created with "grails create-script package-us"
Sadly, not even this works, it produces the following error:
| Error Error executing script PackageUs: No signature of method: org.codehaus.gant.GantBinding$_initializeGantBinding_closure5.doCall() is applicable
for argument types: (java.lang.String, PackageUs$_run_closure5) values: [clean, PackageUs$_run_closure5#5ed0b4e3]
I could not find any example scripts nor documentation beyond the very basic overview in the link.
I cant even get ant.echo() to work - intellij says there is only one ant.echo function which takes a LinkedHashmap, a String and a Closure, but the ant documentation says echo only takes a "message" string. What should the linkedhashmap, string and closure be? I have tried minimum 30 different variations, none work.
Update 1: What I have got working so far
includeTargets << grailsScript("_GrailsInit")
target(packageUs: "Creates war, zips source, tars liquibase scripts") {
depends(clean, "war-us", "zip-source")
}
setDefaultTarget(packageUs)
target ("war-us" : "creates war") {
ant.echo(message:"hello") // this compiles and runs, but does nothing.
println "hello there" // this does work.
// ant.war(?)
}
// puts in it wrong dir, and doen't have app version in name, but at least it zips the right content!
target ("zip-source" : "zips sources") {
ant.delete(file: 'sources.zip') // dont know how to add this to the clean cycle
ant.zip(destfile: 'sources.zip', basedir: '..', excludes: "**/*.zip **/target/** **.idea **/.classpath **/.iml")
}
What I havent figured out:
How to get hold of app.version so it can put put in file names. e.g this: println "creating war for $app.version" does not work
how to build the war. It is not possible to put it in the depdends list, and ant.war("myfile.war") does not work unfortunately. Other strategies might be running this script on the war building event, which is not ideal, as wars are built frequiently without needing this, or perhaps to call "grails war" by calling a shell command.
Update 2 - Can't produce a "prod" war
With help from Ashraf Purno, we have a script (below) which creates a war, zips the sources and tar.gz the liquibase files and produces our package of them. However, it has one major flaw, the war that is created is always the "dev" version, in that when you deploy it to a tomcat, it tires to use the dev datasource, and dev environment. There seems to be no way to change this in the build scirpt, and setting the environment to be prod on the command line which calls the script (e.g. "grails prod myscript") also has no influence - it also produces a dev version of the war (which is of no use)
includeTargets << grailsScript("_GrailsInit")
includeTargets << grailsScript("_GrailsClean")
includeTargets << grailsScript("War")
target(warpack: "Creates war, zips source, tars liquibase scripts") {
depends(cleanAll, cleanRealyAll, war, "zip-source", "tar-liquibase", "package-all")
}
setDefaultTarget(warpack)
target ("cleanRealyAll" : "Cleans stuff that clean-all wont touch") {
println "wiping the target dir"
ant.delete(dir: "target")
ant.mkdir(dir: "target")
}
target ("zip-source" : "zips sources") {
println "zipping sources for ${metadata.'app.version'}"
String zipFile = "target/sources-${metadata.'app.version'}.zip"
ant.delete(file: zipFile)
ant.zip(destfile: zipFile, basedir: '..', excludes: "**/*.zip **/target/** **.idea **/.classpath **/.iml")
}
target ("tar-liquibase":"produces tar of migrations dir") {
println "tarring liquibase for ${metadata.'app.version'}"
String tarFile = "target/migrations-${metadata.'app.version'}.tar"
String gzipfile = "target/migrations-${metadata.'app.version'}.tar.gz"
ant.tar(destfile:tarFile, basedir: "grails-app/migrations")
ant.gzip(src: tarFile, destfile : gzipfile )
ant.delete(file: tarFile)
}
target ("package-all":"puts it all together in one file, relies on externally running 'grails war' first") {
println "creating package for ${metadata.'app.version'}"
String packageFile = "target/ourpackage-${metadata.'app.version'}.tar"
ant.delete(file: packageFile)
ant.tar (destfile: packageFile, basedir:"target", includes: "*.war *.zip *.gz" )
}
After a bit googling and peeking through grails core scripts I managed to create a script which does the things you mentioned in your question. Here it is
import grails.util.Metadata
includeTargets << grailsScript("_GrailsInit")
includeTargets << grailsScript("_GrailsClean")
includeTargets << grailsScript("_GrailsWar")
target(pack: "Creates war, zips source, tars liquibase scripts") {
depends(cleanAll, war)
String appVersion = Metadata.current[Metadata.APPLICATION_VERSION],
zipFileName = "${basedir}/target/sources-${appVersion}.zip",
tarFileName = "${basedir}/target/migrations-${appVersion}.tar.gz"
println "Creating Sources Zip"
ant.delete(file: zipFileName)
ant.zip(destfile: zipFileName, basedir: basedir, excludes: "**/target/** **/.idea/** **/.classpath/** **/.iml/**")
println "Creating Migrations Tar Ball"
ant.delete(file: tarFileName)
ant.tar(destfile: tarFileName, basedir: "${basedir}/grails-app/migrations")
}
setDefaultTarget(pack)
I have put all the tasks in a single target just for simplicity. You can divide them in several targets and add them to depends if you want. I have used Grails 2.5.1 for testing this script.
You can take a look here http://mrhaki.blogspot.com/2014/05/grails-goodness-run-groovy-scripts-in.html for some available props/configs in scripts.

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
}

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