Magnolia Schedule a Groovy Script - groovy

On Magnolia, I've created a Groovy script to delete unused users.
When I run the Groovy script directly from the "DEV > Groovy scripts" interface (on the admin central), it works fine.
Now, I'm trying to schedule the execution of that script.
So I've configured a Command and a Scheduler.
The command :
scheduler > config > commands > default > groovyDeleteUsers
with attributes:
- class = my.commandes.GroovyDeleteAllPublicUsersCommand
The Scheduler :
scheduler > config > jobs > deleteUsersJob
with attributes:
active=true
catalog=default
command=groovyDeleteUsers
cron=0 0 8 * * * *
Here is how my Groovy script is structured :
package my.commands;
import info.magnolia.commands.*;
import info.magnolia.context.MgnlContext;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
public class GroovyDeleteAllPublicUsersCommand extends MgnlCommand {
public boolean execute(Context ctx) {
....
}
}
The problem is that the scheduler job is not able to see my command.
Magnolia Can't find command [groovyDeleteUsers] for job in catalog [{default}]
I've try the JCR query : "select * from nt:base where jcr:path like '%/commands/%'" as specified in the documentation, and my newly created command is in the result.
[EDIT] It seems the problem come from the command.
When I try defining a command with an existing class like info.magnolia.commands.impl.ImportCommand the command is well registred by the applicaation.
But when I try with my my.commandes.GroovyDeleteAllPublicUsersCommand the application doesn't registrer my newly created command.
So do you have any idea?
Thanks for helping,
Regards,
Jimmy

Your problem is not about the setup which is totally correct except the command is not in correct place. Try to put your command definitions right under the module rather than config e.g. put it to ui-admincentral/commands
Edit: Apparently yet another problem was about the groovy command vs java one.
For more information and examples: this page should be sufficient.
Cheers,

As far as I know the catalog name must be unique in the system. "default" already exists in ui-admincentral/commands.

Related

Gradle ant build file not not available during configuration phase

I can't figure out how to execute ant target in case that ant build.xml file is not available during configuration phase. Because it's a remote resource (Maven Remote Resources Plugin).
So basically first I need to get this remote resource like this:
configurations {
remoteResources
}
dependencies.remoteResources 'group:my-remote-resource:version'
task getRemoteResources(type: Copy) {
from(zipTree(configurations.remoteResources.first()))
into("$buildDir/remote-resources")
// replace placeholders
filter(org.apache.tools.ant.filters.ReplaceTokens, , tokens: remotePlaceholders)
}
Only then I have build.xml in
"$buildDir/remote-resources"
But I can't use ant.importBuild as that expects build.xml to be available during the configuration, which is not my case.
I was thinking to move the remote resource "download" into initialization phase, but I have a multi-module project and although only some sub-projects are using this remote resource they all has it own placeholders to replace.
Is there any way how to execute ant targets in this special case?
EDIT: I found pretty nice solution utilising Ant's ProjectHelper and Project classes. So I guess that is my answer..
So here is the final solution. (as already mentioned credits go to groovy-almanac)
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
task executeAntTarget(dependsOn: getRemoteResources) << {
def antFile = new File("$buildDir/remote-resources/build.xml")
def antProject = new Project()
antProject.init()
ProjectHelper.projectHelper.parse(antProject, antFile)
antProject.executeTarget('<target-to-execute>');
}

Explain how to Create Cron Job in Hybris

I did my research but couldn't find the authentic answer.
Any inputs from hybris experts highly appreciated
Cronjob: The job to be performed. For this Create an item type extending from CronJob.
Job: Where the actual cronjob logic will be written. For this Create a class extending from AbstractJobPerformable<...abovegeneratedModel> and override the perform() method. Here perform method will contain actual job logic.
Define the above Job class as a bean in xxxcore-spring.xml.
Go to hmc-->System-->Right click on Cronjobs and Create your new cronjob.
Trigger: Holds cron expression when to fire cronjob. Add the trigger conditions through TimeSchedule tab.
Click StartCronJob Now to schedule the cronjob.
You can also use impex script to create trigger as thijsraets said.
INSERT_UPDATE Trigger;cronJob(code)[unique=true];cronExpression
;myCronJob;30 23 14 2 5 ? 2015
You probably want this cronJob to perform a custom action, for this you need to link up the cronJob with an actual action/task: the job itself. Create a bean that extends AbstractJobPerformable and implements the "perform" method. Now in the hMC you can create your Cron Job (System->CronJobs), under Job point to the bean you have created.
If you would like to do this from code you can use impex, for instance:
INSERT_UPDATE CronJob;code[unique=true];job(code);sessionLanguage(isocode);sessionCurrency(isocode)
;myCronJob;myJobBean;en;EUR
INSERT_UPDATE Trigger;cronJob(code)[unique=true];cronExpression
;myCronJob;30 23 14 2 5 ? 2015
Assign to a String and import this impex (or just execute in hac):
final CSVReader importReader = new CSVReader(impEx);
final Importer importer = new Importer(importReader);
importer.getReader().setDumpingAllowed(true);
try
{
importer.importAll();
}
catch (final ImpExException e)
{
e.printStackTrace();
}
importReader.closeQuietly();
importer.close();
(If you are using 5.5.1: the triggers do not work properly if you indicate multiple execution times. No problem if you only specify a single execution time , we hope SAP will solve this)

Jenkins Script to Restrict all builds to a given node

We've recently added a second slave node to our Jenkins build environment running a different OS (Linux instead of Windows) for specific builds. Unsurprisingly, this means we need to restrict builds via the "Restrict where this project can be run" setting. However we have a lot of builds (100+) so the prospect of clicking through them all to change this setting manually isn't thrilling me.
Can someone provide a groovy script to achieve this via the Jenkins script console? I've used similar scripts in the past for changing other settings but I can't find any reference for this particular setting.
Managed to figure out the script for myself based on previous scripts and the Jenkins source. Script is as follows:
import hudson.model.*
import hudson.model.labels.*
import hudson.maven.*
import hudson.tasks.*
import hudson.plugins.git.*
hudsonInstance = hudson.model.Hudson.instance
allItems = hudsonInstance.allItems
buildableItems = allItems.findAll{ job -> job instanceof BuildableItemWithBuildWrappers }
buildableItems.each { item ->
boolean shouldSave = false
item.allJobs.each { job ->
job.assignedLabel = new LabelAtom('windows-x86')
}
}
Replace 'windows-x86' with whatever your node label needs to be. You could also do conditional changes based on item.name to filter out some jobs, if necessary.
You could try the Jenkins Job-DSL plugin
which would allow you to create a job to alter your other jobs. This works by providing a build step in a groovy based DSL to modify other jobs.
This one here would add a label to the job 'xxxx'. I've cheated a bit by using the job itself as a template.
job{
using 'xxxx'
name 'xxxx'
label 'Linux'
}
You might need to adjust it if some of you jobs are different types

Jenkins Groovy Postbuild use static file instead of script

Is it possible to load an external groovy script into the groovy post build plugin instead of pasting the script content into each job? We have approximately 200 jobs so updating them all is rather time consuming. I know that I could write a script to update the config files directly (as in this post: Add Jenkins Groovy Postbuild step to all jobs), but these jobs run 24x7 so finding a window when I can restart Jenkins or reload the config is problematic.
Thanks!
Just put the following in the "Groovy script:" field:
evaluate(new File("... groovy script file name ..."));
Also, you might want to go even further.
What if script name or path changes?
Using Template plugin you can create a single "template" job, define call to groovy script (above line) in there, and in all jobs that need it add post-build action called "Use publishers from another project" referencing this template project.
Update: This is what really solved it for me: https://issues.jenkins-ci.org/browse/JENKINS-21480
"I am able to do just that by doing the following. Enter these lines in lieu of the script in the "Groovy script" box:"
// Delegate to an external script
// The filename must match the class name
import JenkinsPostBuild
def postBuild = new JenkinsPostBuild(manager)
postBuild.run()
"Then in the "Additional groovy classpath" box enter the path to that file."
We do it in the following fashion.
We have a file c:\somepath\MyScriptLibClass.groovy (accessible for Jenkins) which contains code of a groovy class MyScriptLibClass. The class contains a number of functions designed to act like static methods (to be mixed in later).
We include this functions writing the following statement in the beginning of sytem groovy and postbuild groovy steps:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
This could look a bit ugly but you need to write it only once for script. You could include more than one script and also use inheritance between library classes.
Here you see that all methods from the library class are mixed in the current script. So if your class looks like:
class MyScriptLibClass {
def setBuildName( String str ){
binding?.variables['manager'].build.displayName = str
}
}
in Groovy Postbuild you could write just:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
setBuildName( 'My Greatest Build' )
and it will change your current build's name.
There are also other ways to load external groovy classes and it is not necessary to use mixing in. For instance you can take a look here Compiling and using Groovy classes from Java at runtime?
How did I solve this:
Create file $JENKINS_HOME/scripts/PostbuildActions.groovy with following content:
public class PostbuildActions {
void setBuildName(Object manager, String str ){
binding?.variables['manager'].build.displayName = str
}
}
In this case in Groovy Postbuild you could write:
File script = new File("${manager.envVars['JENKINS_HOME']}/scripts/PostbuildActions.groovy")
Object actions = new GroovyClassLoader(getClass().getClassLoader()).parseClass(script).newInstance();
actions.setBuildName(manager, 'My Greatest Build');
If you wish to have the Groovy script in your Code Repository, and loaded onto the Build / Test Slave in the workspace, then you need to be aware that Groovy Postbuild runs on the Master.
For us, the master is a Unix Server, while the Build/Test Slaves are Windows PCs on the local network. As a result, prior to using the script, we must open a channel from the master to the Slave, and use a FilePath to the file.
The following worked for us:
// Get an Instance of the Build object, and from there
// the channel from the Master to the Workspace
build = Thread.currentThread().executable
channel = build.workspace.channel;
// Open a FilePath to the script
fp = new FilePath(channel, build.workspace.toString() + "<relative path to the script in Unix notation>")
// Some have suggested that the "Not NULL" check is redundant
// I've kept it for completeness
if(fp != null)
{
// 'Evaluate' requires a string, so read the file contents to a String
script = fp.readToString();
// Execute the script
evaluate(script);
}
I've just faced with the same task and tried to use #Blaskovicz approach.
Unfortunately it does not work for me, but I find upgraded code here (Zach Auclair)
Publish here with minor changes:
postbuild task
//imports
import hudson.model.*
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import java.io.File;
// define git file
def postBuildFile = manager.build.getEnvVars()["WORKSPACE"] + "/Jenkins/SimpleTaskPostBuildReporter.GROOVY"
def file = new File(postBuildFile)
// load custom class from file
Class groovy = this.class.classLoader.parseClass(file);
// create custom object
GroovyObject groovyObj = (GroovyObject) groovy.newInstance(manager);
// do report
groovyObj.report();
postbuild class file in git repo (SimpleTaskPostBuildReporter.GROOVY)
class SimpleTaskPostBuildReporter {
def manager
public SimpleTaskPostBuildReporter(Object manager){
if(manager == null) {
throw new RuntimeException("Manager object can't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}
I haven't tried this exactly.
You could try the Jenkins Job DSL plugin which allows you to rebuild jobs from within jenkins using a Groovy DSL and supports post build groovy steps directly from the wiki
Groovy Postbuild
Executes Groovy scripts after a build.
groovyPostBuild(String script, Behavior behavior = Behavior.DoNothing)
Arguments:
script The Groovy script to execute after the build. See the plugin's
page for details on what can be done. behavior optional. If the script
fails, allows you to set mark the build as failed, unstable, or do
nothing. The behavior argument uses an enum, which currently has three
values: DoNothing, MarkUnstable, and MarkFailed.
Examples:
This example will run a groovy script that prints hello, world and if
that fails, it won't affect the build's status:
groovyPostBuild('println "hello, world"') This example will run a
groovy script, and if that fails will mark the build as failed:
groovyPostBuild('// some groovy script', Behavior.MarkFailed) This example
will run a groovy script, and if that fails will mark the
build as unstable:
groovyPostBuild('// some groovy script', Behavior.MarkUnstable) (Since 1.19)
There is a facility to use a template job (this is the bit I haven't tried) which could be the job itself so you only need to add the post build step. If you don't use a template you need to recode the whole project.
My approach is to have a script to regenerate or create all jobs from scratch just so I don't have to apply the same upgrade multiple times. Regenerated jobs keep their build history
I was able to get the following to work (I also posted on this jira issue).
in my postbuild task
this.class.classLoader.parseClass("/home/jenkins/GitlabPostbuildReporter.groovy")
GitlabPostbuildReporter.newInstance(manager).report()
in my file on disk at /home/jenkins/GitlabPostbuildReporter.groovy
class GitlabPostbuildReporter {
def manager
public GitlabPostbuildReporter(manager){
if(manager == null) {
throw new RuntimeException("Manager object musn't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}

What is the best way to import constants into a groovy script?

I have been setting up a scripting envrionment using Groovy. I have a groovy script called FrameworkiDatabase.groovy which contains a class of the same name. This works fine. I also have another file called connections.groovy which contains maps like the following:
SUPPORT2=[
host:"host.name",
port:"1521",
db:"support2",
username:"username",
password:"password",
dbType:"oracle"
]
This holds a collection of database bookmarks, a bit like an oracle tnsnames file, so I don't need to remember all the parameters when connecting to databases.
When using groovysh, I can import this using the load command, and it is available in current scope. How can I load it as part of a script the same way? It has no class definition around it - does it need one? I have tried doing that, and adding a static import, but that didn't work...
I tried something like this, but no luck:
testFrameworkiDatabase.groovy:
import static connections
def db = new FrameworkiDatabase(SUPPORT2)
db.listInvalidObjects()
db.getDBSchemaVersion()
db.getFWiVersion()
db.getSPVersion()
db.getFileloaderVersion()
db.getAdminToolVersion()
db.getReportsVersion()
So I want to load those connections as constants - is there any way I can do this easily?
Not sure if it's the best way, but one way would be to write this into Connections.groovy
class Connections {
static SUPPORT2 = [
host:"host.name",
port:"1521",
db:"support2",
username:"username",
password:"password",
dbType:"oracle"
]
}
Then, compile this with groovyc Connections.groovy to generate a class file
Then, in your test script or on the groovysh prompt, you can do:
import static Connections.*
println SUPPORT2
To get the output:
[host:host.name, port:1521, db:support2, username:username, password:password, dbType:oracle]
If compiling the Connections.groovy class isn't good enough, I think you're going to be looking at loading the source into a Binding object by using one of the Groovy embedding techniques

Resources