I have a gant script A with two targets
t1 - default target
t2 - another target
Even when I run
grails A t2
the default target is run? How can I run the non-default target?
I have tried grails A --target='t2' etc. but doesn't work.
I'm not sure if there's a proper way to do it, but you can write a second script ("T2.groovy") that loads this one and sets that target as its default, e.g.
includeTargets << new File("path/to/YourScript")
setDefaultTarget("t2")
A tweak to argsParsing approach is to run through elements from the argsMap and iteratively depend on them. So you could call your script something like:
grails myScript do-this do-that do-the-other
scriptName = 'myScriptName'
includeTargets << grailsScript("_GrailsArgParsing")
snip
target(main: "Default Target") {
depends(parseArguments)
if(argsMap?.size() == 0) {
depends(scriptError)
}
argsMap.each() {
if (it.value) {
println "${scriptName} building: ${it.value}"
depends(it.value)
}
else {
depends(scriptError)
}
}
}
snip
target(help: "Print a help message") {
println "${scriptName}: possible targets are..."
println "\thelp - print this help message"
}
target(scriptError: "Print an error and die") {
println "${scriptName}: Please specify at least one target name"
depends(help)
exit 1
}
This is another approach that I took
includeTargets << grailsScript("_GrailsArgParsing")
snip
target(main: "a script") {
if(!argsMap.target)
throw new IllegalArgumentException("please specify target name with --target option")
depends(argsMap.target)
}
setDefaultTarget(main)
You run the script with a parameter. That parameter is the name of the method to run :) That method then get's executed.
Related
I would like to be able to wrap a 'stage' in Jenkins, so I can execute custom code at the start and end of a stage, so something like:
myStage('foo') {
}
I thought I could do this by using metaClass:
//Wrap stages to automatically trace
def originalMethod = this.metaClass.getMetaMethod("stage", null)
this.metaClass.myStage = { args ->
println "Beginning of stage"
println "Args: " + args
def result = originalMethod.invoke(delegate, args)
println "End of stage"
return result
}
But it appears the Groovy script itself is a Binding, which doesn't have a metaClass:
groovy.lang.MissingPropertyException: No such property: metaClass for class: groovy.lang.Binding
I'm still learning how Groovy and Jenkins Pipeline work, so perhaps I'm just missing something.
I am not familiar with the metaclass concept but I think that a simple solution to your problem is to define a wrapped stage as a function.
Here's an example of how you'd define such a function:
def wrappedStage(name, Closure closure) {
stage(name) {
echo "Beginning of stage"
def result = closure.call()
echo "End of stage"
return result
}
}
and this is how you would call it:
wrappedStage('myStage') {
echo 'hi'
}
The return value of wrappedStage would only make sense when the body of your stage actually returns something, for example:
If you call another job, eg:
wrappedStage('myStage') {
build job: 'myJob'
}
you will get back org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper which you can use to access info of the job you run, like result, variables etc
If you print something to the console, eg:
wrappedStage('myStage') {
echo 'hi'
}
you will get back null.
Note that in my example I am not printing args because the way I understand stage, it only takes 2 arguments; the stage name and the closure it should run. The name of the stage will already be printed in the log, and I don't know how much value you'd get from printing the code you're about to execute but if that's something you want to do, take a look at this.
If you have a more specific case in mind for what you'd want to wrap, you can add more params to the wrapper and print all the information you want through those extra parameters.
I am writing a custom grails script. I want custom help, options etc.
According to doc (
http://grails.github.io/grails-doc/latest/guide/commandLine.html#creatingCustomScripts), I just need to do:
description( "Generates a controller that performs CRUD operations and the associated views" ) {
usage "grails generate-all [DOMAIN CLASS]"
flag name:'force', description:"Whether to overwrite existing files"
argument name:'Domain Class', description:'The name of the domain class'
}
However when I add that to my script, I get:
Warning: Error caching created help for /server/scripts/ExecuteDBScript.groovy: No signature of method: ExecuteDBScript.description() is applicable for argument types: (java.lang.String, ExecuteDBScript$_run_closure1) values: [Generates a controller that performs CRUD operations and the associated views, ...]
My script looks like:
includeTargets << grailsScript("_GrailsInit")
description( "Generates a controller that performs CRUD operations and the associated views" ) {
usage "grails generate-all [DOMAIN CLASS]"
flag name:'force', description:"Whether to overwrite existing files"
argument name:'Domain Class', description:'The name of the domain class'
}
/**
* Script to execute the DB script.
*
*/
target(main: "This script executes DB Script") {
...
}
Any ideas?
Documentation is poor, but I found this solution:
includeTargets << grailsScript("_GrailsBootstrap")
USAGE = """
grails script-name [PARAM]
where
PARAM = Description
"""
target (default: "command description") {
//...
}
Your link (http://grails.github.io/grails-doc/latest/guide/commandLine.html#creatingCustomScripts) refers to the latest version of grails, a non-stable version (3.0.0.M2).
Probably you are using the latest stable version, 2.4.4, so the correct docs are here: http://grails.github.io/grails-doc/2.4.4/ref/Command%20Line/create-script.html
I'm trying to get familiar with Grails events which are defined in scripts/_Events.groovy file.
The problem is my events hooks are ignored.
The file is definitely compiled because Grails complains about syntax errors if they are.
But there is nothing more. I can't notice any difference in execution of commands like "grails war" and "grails run-app".
Grails version is 2.4.4
includeTargets << grailsScript('_GrailsPackage')
includeTargets << grailsScript('_GrailsEvents')
eventCompileStart = { kind ->
println "Triggered ${kind}"
throw new IllegalArgumentException()
}
eventPackagingEnd = {
println "PackaginEnd"
throw new IllegalArgumentException()
}
eventPackagingStart = {
println "PackaginStart"
throw new IllegalArgumentException()
}
eventCreateWarStart = {warName, stagingDir ->
println "eventCreateWarStart [${stagingDir}]"
throw new IllegalArgumentException()
}
eventCreateWarEnd = {warName, stagingDir ->
println " eventCreateWarEnd ${stagingDir}"
throw new IllegalArgumentException()
}
Since some time I figured out that _Events.groovy file should be 1 level upper in the project structure. So the right place for scripts folder is the root project folder rather than grails-app one.
My requirement is to invoke some processing from a Jenkins build server, to determine whether the domain model has changed since the last build. I've come to the conclusion that the way forward is to write a script that will invoke a sequence of existing scripts from the db-migration plugin. Then I can invoke it in the step that calls test-app and war.
I've looked in the Grails doc, and at some of the db-migration scripts, and I find I'm stuck - have no idea where to start trying things. I'd be really grateful if someone could point me at any suitable sources. BTW, I'm a bit rusty in Grails. Started to teach myself two years ago via proof of concept project, which lasted 6 months. Then it was back to Eclipse rich client work. That might be part of my problem, though I never go involved in scripts.
One thing I need in the Jenkins evt is to get hold of the current SVN revision number being used for the build. Suggestions welcome.
Regards, John
Create a new script by running grails create-script scriptname. The database-migration plugins scripts are configured to be easily reused. There are is a lot of shared code in _DatabaseMigrationCommon.groovy and each script defines one target with a unique name. So you can import either the shared script or any standalone script (or multiple scripts) and call the targets like they're methods.
By default the script generated by create-script "imports" the _GrailsInit script via includeTargets << grailsScript("_GrailsInit") and you can do the same, taking advantage of the magic variables that point at installed plugins' directories:
includeTargets << new File("$databaseMigrationPluginDir/scripts/DbmGenerateChangelog.groovy")
If you do this you can remove the include of _GrailsInit since it's already included, but if you don't that's fine since Grails only includes files once.
Then you can define your target and call any of the plugin's targets. The targets cannot accept parameters, but you can add data to the argsMap (this is a map Grails creates from the parsed commandline arguments) to simulate user-specified args. Note that any args passed to your script will be seen by the database-migration plugin's scripts since they use the same argsMap.
Here's an example script that just does the same thing as dbm-generate-changelog but adds a before and after message:
includeTargets << new File("$databaseMigrationPluginDir/scripts/DbmGenerateChangelog.groovy")
target(foo: "Just calls dbmGenerateChangelog") {
println 'before'
dbmGenerateChangelog()
println 'after'
}
setDefaultTarget foo
Note that I renamed the target from main to foo so it's unique, in case you want to call this from another script.
As an example of working with args, here's a modified version that specifies a default changelog name if none is provided:
println 'before'
if (!argsMap.params) {
argsMap.params = ['foo2.groovy']
}
dbmGenerateChangelog()
println 'after'
Edit: Here's a fuller example that captures the output of dbm-gorm-diff to a string:
includeTargets << new File("$databaseMigrationPluginDir/scripts/_DatabaseMigrationCommon.groovy")
target(foo: "foo") {
depends dbmInit
def configuredSchema = config.grails.plugin.databasemigration.schema
String argSchema = argsMap.schema
String effectiveSchema = argSchema ?: configuredSchema ?: defaultSchema
def realDatabase
boolean add = false // booleanArg('add')
String filename = null // argsList[0]
try {
printMessage "Starting $hyphenatedScriptName"
ByteArrayOutputStream baos = new ByteArrayOutputStream()
def baosOut = new PrintStream(baos)
ScriptUtils.executeAndWrite filename, add, dsName, { PrintStream out ->
MigrationUtils.executeInSession(dsName) {
realDatabase = MigrationUtils.getDatabase(effectiveSchema, dsName)
def gormDatabase = ScriptUtils.createGormDatabase(dataSourceSuffix, config, appCtx, realDatabase, effectiveSchema)
ScriptUtils.createAndPrintFixedDiff(gormDatabase, realDatabase, realDatabase, appCtx, diffTypes, baosOut)
}
}
String xml = new String(baos.toString('UTF-8'))
def ChangelogXml2Groovy = classLoader.loadClass('grails.plugin.databasemigration.ChangelogXml2Groovy')
String groovy = ChangelogXml2Groovy.convert(xml)
// do something with the groovy or xml here
printMessage "Finished $hyphenatedScriptName"
}
catch (e) {
ScriptUtils.printStackTrace e
exit 1
}
finally {
ScriptUtils.closeConnection realDatabase
}
}
setDefaultTarget foo
Based on this question, I thought I could define something like this in (for example) resources.groovy
def currentEnv = Environment.current
if (currentEnv == Environment.CUSTOM && currentEnv.name == 'mock') {
println 'Do some stuff for the mock env'
}
The code in the if-statement should be executed when I run (for example) grails run-app -Denv=mock but it isn't, what am I doing wrong?
You must use the method Environment.executeForCurrentEnvironment(), like this:
import grails.util.Environment
grails.util.Environment.executeForCurrentEnvironment {
development {
println 'Running in DEV mode.'
}
production {
println 'Running in production mode.'
}
mock {
println 'Running in custom "mock" mode.'
}
}
and call grails this way: grails -Dgrails.env=mock run-app
Take a look at this blogpost, from mrhaki.
Note that this may be a problem if you have multiple custom environments defined. I am using Grails 2.4.4. If I have a mytest and myqa environment defined, BOTH will be executed by Grails because both are Environment.CUSTOM, meaning some bean definitions are overwritten or misconfigured!
grails.util.Environment.executeForCurrentEnvironment {
development {
println 'Running in DEV mode.'
}
mytest {
println 'This will be evaluated because it is CUSTOM'
}
myqa {
println 'This will ALSO be evaluated because it is CUSTOM. Yikes!'
}
}
I don't know if that's a bug or by design. Anyway, here is what I do and this seems to work properly:
switch(Environment.current.name) {
case 'development':
println 'Running in DEV mode.'
break
case 'mytest':
println 'Running in mytest mode'
break
case 'myqa':
println 'Running in myqa mode'
break
}