I want to modify a grails BuildConfig.groovy:
grails.project.dependency.resolution = {
plugins {
build ":tomcat:7.0.50"
// plugins for the compile step
compile ":scaffolding:2.0.1"
compile ':cache:1.1.1'
// plugins needed at runtime but not for compilation
runtime ":hibernate:3.6.10.7" // or ":hibernate4:4.1.11.6"
runtime ":database-migration:1.3.8"
runtime ":jquery:1.10.2.2"
runtime ":resources:1.2.1"
}
}
Especially I want to add a plugin and modify another one.
I tried it with ConfigSlurper:
def conf = new ConfigSlurper().parse(new File(buildConfig).toURL())
def plugins = conf.grails.project.dependency.resolution
println "found plugins: $plugins"
plugins.each {
println it
}
The access to conf.grails.project.dependency works fine but conf.grails.project.dependency.resolution is a closure and I don't know how to access or even modify this section.
I don't know grails enough to make some opinionated guess, but it seems to me this config file doesn't conform to ConfigSlurper expected syntax. If what you want to parse isn't very long, you can try intercepting it yourself:
class PluginConfig {
def compileLibs = []
def runtimeLibs = []
def version
def build(version) { this.version = version }
def compile(lib) { compileLibs << lib }
def runtime(lib) { runtimeLibs << lib }
}
def conf = new ConfigSlurper().parse(new File("BuildConfig.groovy").toURL())
def plugins = conf.grails.project.dependency.resolution
def lib = new PluginConfig()
plugins.delegate = lib // magick!!
plugins()
assert lib.compileLibs == [":scaffolding:2.0.1", ':cache:1.1.1']
assert lib.runtimeLibs == [
":hibernate:3.6.10.7",
":database-migration:1.3.8",
":jquery:1.10.2.2",
":resources:1.2.1"
]
assert lib.version == ":tomcat:7.0.50"
No idea how to rewrite this to a file (easily) after the change, though. Maybe using Grails own config parser might be a better idea; it must have a representation of the config when it parses the file.
As far as I know there is no perfect way for doing this: all available parsers/slurpers drop the comments of your configuration. So even if you would modify the result from the config slurper and write it back, it wouldn't be what you are looking for.
You also have t consider that people might use variables for version numbers and other unexpected stuff.
So I guess the best way to modify the config is to use some regular expressions and hope that you users have a standard configuration...
Related
I have a jenkins build that needs to get the filenames for all files checked in within a changeset.
I have installed groovy on the slave computer and configured Jenkins to use it. I am running the below script that should return the names (or so I assume as this may be wrong as well) and print to the console screen however I am getting this error:
groovy.lang.MissingPropertyException: No such property: paths for class: hudson.plugins.tfs.model.ChangeSet
Here is the Groovy System Script:
import hudson.plugins.tfs.model.ChangeSet
// work with current build
def build = Thread.currentThread()?.executable
// get ChangesSets with all changed items
def changeSet= build.getChangeSet()
def items = changeSet.getItems()
def affectedFiles = items.collect { it.paths }
// get file names
def fileNames = affectedFiles.flatten().findResults
fileNames.each {
println "Item: $it" // `it` is an implicit parameter corresponding to the current element
}
I am very new to Groovy and Jenkins so if its syntax issue or if I'm missing a step please let me know.
I don't know the version of jenkins you are using but according to the sourcecode of ChangeSet that you can find here I suggest you to replace line 9 with:
def affectedFiles = items.collect { it.getAffectedPaths() }
// or with the equivalent more groovy-idiomatic version
def affectedFiles = items.collect { it.affectedPaths }
Feel free to comment the answer if there will be more issues.
First, I came from a .NET background so please excuse my lack of groovy lingo. Back when I was in a .NET shop, we were using TypeScript with C# to build web apps. In our controllers, we would always receive/respond with DTOs (data xfer objects). This got to be quite the headache every time you create/modify a DTO you had to update the TypeScript interface (the d.ts file) that corresponded to it.
So we created a little app (a simple exe) that loaded the dll from the webapp into it, then reflected over it to find the DTOs (filtering by specific namespaces), and parse through them to find each class name within, their properties, and their properties' data types, generate that information into a string, and finally saved as into a d.ts file.
This app was then configured to run on every build of the website. That way, when you go to run/debug/build the website, it would update your d.ts files automatically - which made working with TypeScript that much easier.
Long story short, how could I achieve this with a Grails Website if I were to write a simple groovy app to generate the d.ts that I want?
-- OR --
How do I get the IDE (ex IntelliJ) to run a groovy file (that is part of the app) that does this generation post-build?
I did find this but still need a way to run on compile:
Groovy property iteration
class Foo {
def feck = "fe"
def arse = "ar"
def drink = "dr"
}
class Foo2 {
def feck = "fe2"
def arse = "ar2"
def drink = "dr2"
}
def f = new Foo()
def f2 = new Foo2()
f2.properties.each { prop, val ->
if(prop in ["metaClass","class"]) return
if(f.hasProperty(prop)) f[prop] = val
}
assert f.feck == "fe2"
assert f.arse == "ar2"
assert f.drink == "dr2"
I've been able to extract the Domain Objects and their persistent fields via the following Gant script:
In scripts/Props.groovy:
import static groovy.json.JsonOutput.*
includeTargets << grailsScript("_GrailsBootstrap")
target(props: "Lists persistent properties for each domain class") {
depends(loadApp)
def propMap = [:].withDefault { [] }
grailsApp.domainClasses.each {
it?.persistentProperties?.each { prop ->
if (prop.hasProperty('name') && prop.name) {
propMap[it.clazz.name] << ["${prop.name}": "${prop.getType()?.name}"]
}
}
}
// do any necessary file I/O here (just printing it now as an example)
println prettyPrint(toJson(propMap))
}
setDefaultTarget(props)
This can be run via the command line like so:
grails props
Which produces output like the following:
{
"com.mycompany.User": [
{ "type": "java.lang.String" },
{ "username": "java.lang.String" },
{ "password": "java.lang.String" }
],
"com.mycompany.Person": [
{ "name": "java.lang.String" },
{ "alive": "java.lang.Boolean" }
]
}
A couple of drawbacks to this approach is that we don't get any transient properties and I'm not exactly sure how to hook this into the _Events.groovy eventCompileEnd event.
Thanks Kevin! Just wanted to mention, in order to get this to run, here are a few steps I had to make sure to do in my case that I thought I would share:
-> Open up the grails BuildConfig.groovy
-> Change tomcat from build to compile like this:
plugins {
compile ":tomcat:[version]"
}
-> Drop your Props.groovy into the scripts folder on the root (noting the path to the grails-app folder for reference)
[application root]/scripts/Props.groovy
[application root]/grails-app
-> Open Terminal
gvm use grails [version]
grails compile
grails Props
Note: I was using Grails 2.3.11 for the project I was running this on.
That gets everything in your script to run successfully for me. Now to modify the println portion to generate Typescript interfaces.
Will post a github link when it is ready so be sure to check back.
I have a singleton class
#Singleton
class CustomerBundleSingleton {
def grailsApplication = Holders.getGrailsApplication()
String projName
private CustomerBundleSingleton() {
line 10: projName = // how to get sub-project name here ???
}
}
application.properties // my project is running
-----------------------
app.name = MyNewProject
application.properties // located in sub project
-----------------------
app.name = MySubProject
I tried grailsApplication.metadata['app.name'] in "line 10:" it returns "MyNewProject".Whereas I want a way to get the project name of the UserBundleSingleton located (MySubProjectName). Something like grailsApplication.current.metadata['app.name'] ???? .
So that it can give me back MySubProjectName instead of MyNewProject??
I have 3 suggestions depending on your requirements and your 'bundling'.
1) You don't have a bundle marker/descriptor
Assuming that you know the sub-project(Grails plugin) name, your life gets easier, instead of having to loop through all plugins...
You can probably use something among these lines.
// Plugin name is 'hibernate' in this example
import org.codehaus.groovy.grails.plugins.PluginManagerHolder
def hibernateVersion = PluginManagerHolder.pluginManager.getGrailsPlugin('hibernate').version
// Loop through all plugins
// PluginManagerHolder.pluginManager.getAllPlugins()
2) Using custom plugin properties to lookup plugins of interest
Other strategy, if you must lookup the bundle dynamically.
Create a custom marker property in each of your plugin descriptors
def specialProperty = "whatever"
Then inside your CustomerBundleSingleton
PluginManagerHolder.pluginManager.getAllPlugins().each {
if (it.properties.specialProperty) {
def subProjectName = it.name
def subProjectVersion = it.version
}
}
3) Custom bundle info resolution
You may also want to consider some metadata via META-INF/MANIFEST.MF or similar mechanism.
Hope it helps...
I have a configuration parameter in my BuildConfig.groovy that requires I put a lot of directories in for each plugin I have. I like to create a simple method that will generate all of those directories for me. I know groovy config files are groovy code, but I can't seem to find any information related to the preferred method for creating helper methods. (for example mavenRepo, grailsPlugins(), grailsHome(), etc). If I want to create my own helper method where would I put it so I can call it like so:
someProperty = myHelperMethod()
A bit of an update. I wrote this method directly in my BuildConfig.groovy file and it works! But I'd like to move it out and organize it better. How do I write such methods and expose those to config files like BuildConfig.groovy?
def pluginDirs() {
List dirs = []
String trash = "[:]/"
grails.plugin.location.each() { name, plugin ->
if( plugin.startsWith(trash) ) {
plugin = plugin.substring(trash.length())
}
dirs << "${plugin}/src/groovy" <<
"${plugin}/grails-app/controllers" <<
"${plugin}/grails-app/domain" <<
"${plugin}/grails-app/services" <<
"${plugin}/grails-app/taglib" <<
"${plugin}/grails-app/utils"
}
return dirs
}
Extra-credit: Some of these plugins use ${basedir} to define their path, but when I run one of my scripts ${basedir} isn't defined to it puts [:] trash in my URLs. That's why that ugly code is in there.
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