I have a Groovy application that I build with Gradle. As usual I have defined the application version number/string in the build.gradle script.
Now I want to use that version string within the Groovy application, as hard-coded static piece of information. For example as a final static member in the main application class:
class MyApp {
final static APP_VERSION = "0.1"
}
Since the version information comes from the build.gradle script, that Groovy class member above needs to be set by Gradle before the sources are compiled.
In other words: I need a Gradle task that allows me to set the value of a variable in the Groovy sources, before they are built by Gradle. I could for search for that value via regular expression and replace it in the Groovy source file, but that feels a bit clunky.
Any "best practice" ideas how to achieve that?
i can't give you final solution, but, i think, you should look at AST Transformations
Another option, if you pack the application in jar / war, - you can get a version of the application from the manifest file (but it will not work if you are starting app from IDE)
final static versin = MyApp.class.getPackage().getSpecificationVersion()
Related
Working on my 6th or 7th Jenkins script now - and I already noticed they share a bit of code (essentially just the same groovy subroutines over and over again). I wouldn't like to continue with that and rather learn some best practices.
It seems that "Shared Libraries" are the thing to do. (Or is there a better way when you just want to share groovy code, not script steps etc.?)
Those scripts are part of a larger repo (that contains the source of the entire project, including the other scripts), stored in a subfolder Jenkins/Library with this structure:
Jenkins/Library
+- vars
| common_code.groovy
There is only a vars folder, no src. The documentation said
For Shared Libraries which only define Global Variables (vars/), or a Jenkinsfile which only needs a Global Variable, the annotation pattern #Library('my-shared-library') _ may be useful for keeping code concise. In essence, instead of annotating an unnecessary import statement, the symbol _ is annotated.
so I concluded that I wouldn't need a src folder and can do with vars alone.
The library is made available via "Configure Jenkins" > "Global Pipeline Libraries" with SourcePath set to "/Jenkins/Library/" and is brought in with the statement #Library('{name}') _ as first line of the script.
However, when attempting to use the library, I get the error shown in the subject.
What's the problem? (I already searched around and found this instance of the problem, but that doesn't seem to fit for my issue - unless I misunderstood something.)
To specify a name of the library you should set the same name in your jenkins settings:
Name.
An identifier you pick for this library, to be used in the #Library
annotation. An environment variable library.THIS_NAME.version will
also be set to the version loaded for a build (whether that comes from
the Default version here, or from an annotation after the #
separator).
Your '{name}' parameter inside of #Library() means you should add a library with the same name. Because it's not a variable like "${name}" which is not a built in variable and undefined.
If you wish to set up your library with the same name as your jenkins pipleine you could use env.JOB_NAME variable, or check the all environment and pre-defined variables:
println env.getEnvironment()
Or check job parameters only:
println params
Now step-by-step instructions:
Create your library, for example from Git SCM as shown on the screenshot.
Put your library code to the project, e.g: <project_root_folder>/vars/common_code.groovy. You don't need your additional path Jenkins/Library. Also you have named your file in 'snake case' style, which is not usual for groovy:
The vars directory hosts scripts that define global variables
accessible from Pipeline. The basename of each *.groovy file should be
a Groovy (~ Java) identifier, conventionally camelCased.
So your file in 'camel case' should looks CommonCode.groovy.
Write your library code:
// vars/commonCode.groovy
// Define your method
def call() {
// do some stuff
return 'Some message'
}
Write your pipeline. Example of scripted pipeline:
#!/usr/bin/env groovy
// yourPipeline.groovy file in your project
#Library('jenkins-shared-library') _
// Get the message from the method in your library
def messageText = commonCode() as String
println messageText
If you wish to define some global variables this answer also may help you.
PS: Using 'vars' folder allows you to load everything from your vars folder once at the same time. If you wish to load dynamically use import from src folder.
I have a very similar issue to what is described here:
How to import from one level above the current package in groovy
I don't want to move SharedState to an action/pkg subdirectory. What I want to do is to maintain the following structure:
groovy / action / TestDataHelper
groovy / action2 / TestDataHelper2
groovy / action3 / SharedState
and then gain access to SharedState from both TestDataHelper and TestDataHelper2.
I cannot do that anyhow using package, which I tend to understand is impossible by default. I could use classpath shenanigans instead, but need some guidance on that first.
Thanks for any kind of feedback.
The answer is to use additional class path in the Jenkins job seed job - advanced section in the Build. The path needs to be matching mother directory of the project.
/home/user/mother_dir
The groovy script can be anywhere under /home/user/mother_dir, in my case it's under /home/user/mother_dir/other_dir/script.groovy
Then, I put the classes I would like to import within a package in a /home/user/mother_dir/package_dir. In the groovy script mapped with the job I import package.* and have access to all the necessary classes from the package_dir.
I have an ant build which contains tasks of format
build
build.foo.bar
So to add dependencies in gradle the first one is easy
build.dependsOn(...)
But the second one is interpreted as method nesting. I suspect there's a standard groovy way to do this but I haven't cracked it.
How do I reference an ant task containing periods in an build.gradle file?
project.tasks['build.foo.bar'].dependsOn(...)
should do the trick.
See Project.tasks, which returns a TaskContainer (extending TaskCollection), and TaskCollection.getAt() which, as its doc says, can be called using the [] operator.
I'm working on a sort of 'multi-tenant' grails app that will be used as a 'platform' upon which quick sites will be developed.
A 'site' will include a layout, images, and page gsps.
Right now, these are spread across the project in their normal locations, eg:
/grails-app/views/layout
/grails-app/views/<site>
/web-app/images/
Ideally, they'd all be in one place, centralized by site, like
/sites/<site>/layout
/sites/<site>/pages/
/sites/<site>/imagtes
My current thinking is this could be accomplished with a Build.groovy script and doing some ant trickery at build time.
But I'm not sure if it's possible to do this copying-by-convention - ie I don't know the directories that are present until it runs. (I'm also no ant guru)
Any ideas/suggestions? Thanks!
I have used the following script, named _Events.groovy and located in a scripts folder under your grails application, to copy files before my build:
includeTargets << grailsScript("_GrailsEvents")
eventSetClasspath = { msg ->
println "Custom Configuration"
ant.copy(todir:classesDirPath) {
fileset(dir:"${basedir}/config")
}
}
And I suppose you could use something very similar.
Relevant grails documentation is here
Update: as of Grails 1.3.6 one has access to the full domain from Gant scripts.
From the Grails 1.3.6 release notes:
You can now run one or more Groovy scripts from the commandline using the run-script command, e.g.
grails run-script [path-to-script-1] [path-to-script-2]...[path-to-script-n]
This works around the issue in Gant scripts where you can't conveniently access application classes since they're not available in the classpath when the scripts start.
Hi all,
I am new to using Grails (in a real project) and I have a one-off script I need to execute that reads a file and then populates my database.
I wanted the script to run in the context of my grails app, so I used the create-script command. I now understand that makes it a 'Gant' script. The reason for doing so was that I thought it would allow me easy access to all the grails domain good-ness, so that i would be able to do something like this easily:
Car car = new Car(model: 'bar', brand: 'Ford')
car.save()
Here, Car is one of my domain classes and the strings 'bar' and 'Ford' I have retrieved from my file.
The start of my script looks like this:
import com.foo.Car
grailsHome = Ant.project.properties."environment.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )
target(main: "a script for storing cars") {
depends(bootstrap, classpath) // code dealing with the file with cars follows
Surprisingly, groovy gives me a java.lang.NoClassDefFoundError: com.foo.Car when I execute the script with the command grails LoadCars
Am I taking the wrong approach, or is there something more simple I am doing wrong?
Any help is appreciated
i know the scripts are useful, and I will probably get hate mail for even suggesting it, but I have just incorporating this kinda of stuff directly into my application in the past.
I have a flag set in my configuration which indicates if the data should be bootstrapped, if so, the bootstrap code looks for a comma delimited file at startup and calls a service method to load up the data.
I've updated the grails run-script Gant script (referred to by Jared above) to work with grails 1.3.5. I'd been meaning to do it for a while, but this question nudged me into finally getting around to it).
Just download the script described in the post, save it in your grails "scripts" directory and you can then run your own groovy script to bootstrap data with:
grails run-script script-path/boostrapMyDataIntoApp.groovy
I've had to do this and you have to create a special script to allow you to access GORM from a standard grails script. See this question for more info. I'm not sure what the current status of the script is under grails 1.3 but the author of the script posted in the comments.
Hans, there are several choices here, assuming you are not out to polish the GANT scripting chops 8^)
So assume that you are doing some integration-mode TDD, correct?
Have you looked into the db-stuff plugin? Actually that one leverages the open source package (extension of the JUnit project) called dbUnit, which is also an outstanding choice, for both Java and Groovy projects.
*db-stuff <0.3.0> -- db schema managment and data import/export. Generate generic schema files and import or export base/seed/test data into your database.
I have traditionally done this as well in the BootStrap depending on the environment - and I try to never let those domain assumptions / constraints get too far out of synch. with my schema.
Here's the canon I'm talking about :
class BootStrap {
def init = { servletContext ->
if (GrailsUtil.environment.equals( GrailsApplication.ENV_DEVELOPMENT )) {
log.info( "Loading sample data for 2010 models..." );
new Car( manufacturer: new Manufacturer( name: "Toyota" ), model: "Prius" )
new Car( manufacturer: new Manufacturer( name: "GM" ), model: "Volt" )
//...