NPE after grails clean - grails

The application works just fine, but after grails clean it starts throwing an error if I execute grails war or grail web-app:
|Loading Grails 2.4.3
|Configuring classpath
.
|Environment set to production
.................................
|Packaging Grails application
..
|Compiling 18 source files
.Error
|
Compilation error: startup failed:
General error during class generation: NPE while processing BcvjobService.groovy
groovy.lang.GroovyRuntimeException: NPE while processing BcvjobService.groovy
at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:252)
at org.codehaus.groovy.control.CompilationUnit$16.call(CompilationUnit.java:805)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1047)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:583)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:561)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:538)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:517)
at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:59)
at org.codehaus.groovy.tools.FileSystemCompiler.doCompilation(FileSystemCompiler.java:215)
at org.codehaus.groovy.ant.Groovyc.runCompiler(Groovyc.java:1161)
at org.codehaus.groovy.ant.Groovyc.compile(Groovyc.java:1212)
at org.codehaus.groovy.grails.compiler.Grailsc.compile(Grailsc.java:78)
at org.codehaus.groovy.ant.Groovyc.execute(Groovyc.java:827)
...
Googling didn't help in the least, so I can't even understand where to start, and any help would be greatly appreciated.
Here is BcvjobService.groovy:
package bcvapp
import grails.transaction.Transactional
import groovy.lang.Closure;
import groovy.io.FileType
import groovy.util.AntBuilder
import java.awt.event.ItemEvent;
import java.util.List;
import java.util.regex.Pattern;
import grails.util.Mixin
import grails.util.Holders
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
#Transactional
#Mixin(ServiceCategory)
class BcvjobService {
def mailService
def holderService
def servletContext = SCH.servletContext
def String absPath = getAbsPath()
def String configPath = servletContext.getRealPath("/pipeline/bcvrun.prj.xml")
def outputMap = [:]
def prepareDirectory(Bcvjob job, String sessionId, List fileList, List directionList, Integer queueSize){
def configFile = new File (configPath)
def defaultConfig = new XmlParser().parse(configFile)
// Create directory structure
def inputLine = defaultConfig.BCV_Input
def input = inputLine.text().replaceAll(Pattern.compile('[\\.\\/\\\\]'), '')
def outputLine = defaultConfig.BCV_Output
def output = outputLine.text().replaceAll(Pattern.compile('[\\.\\/\\\\]'), '')
def folderPath = "${absPath}${sessionId}"
def inputPath = folderPath + "/" + input
def outputPath = folderPath + "/" + output
addResultsPath(sessionId, outputPath)
inputLine[0].value = inputPath
outputLine[0].value = outputPath
def inpath = defaultConfig.InPath // why there are two almost identical lines in bcv config?
inpath[0].value = inputPath
new File (inputPath).mkdirs()
new File (outputPath).mkdir()
new File(outputPath + "/simple_results.html").createNewFile()
File res = new File(outputPath + "/simple_results.html")
if (queueSize > 2 ){
res << ("Your task was submitted at ${new Date()}<p>")
res << ("Waiting in queue..<p>")
res << ("Please, bookmark this page to see the results later. Refresh the page to check if they are ready.")
}
else {
res << ("Your task was submitted at ${new Date()}<p>")
res << ("Running..<p>")
res << ("Please, bookmark this page to see the results later. Refresh the page to check if they are ready.")
}
res << ("<script>")
res << ("var interval = setInterval('location.reload()', '30000');")
res << ("</script>")
for (f in fileList){
new File (outputPath + "/" + f.getOriginalFilename().replaceAll(Pattern.compile('\\..*'), '').replaceAll("\\s+", "_")).mkdir()
}
uploadFiles(inputPath, fileList)
// Write custom configuration file
def vocabulary = defaultConfig.Vocabulary
def vocabularyPath = vocabulary[0].text().substring(0, vocabulary[0].text().lastIndexOf("/")+1)
def vocabularyName = job.vocabulary.replaceAll(/\s+/, "_")
vocabulary[0].value = vocabularyPath + vocabularyName + ".seq.fas"
def reads = defaultConfig.READS.find{'READS'}
reads.children.clear()
def counter = 0
for (f in fileList){
def stringDirection
if (directionList.get(counter) == "r"){
stringDirection = "reverse"
}
else stringDirection = "forward"
reads.appendNode('Read', [name:f.getOriginalFilename().replaceAll("\\s+", "_")]).appendNode('Direction', stringDirection)
counter++
}
def taxdb = defaultConfig.Database
if (job.taxdb == "full"){
taxdb[0].value = "all"
}
else if (job.taxdb == "named isolates"){
taxdb[0].value = "named"
}
def distance = defaultConfig.DistanceThreshold
distance[0].value = job.distance.toFloat()
def email = defaultConfig.Email
email[0].value = job.email
def mode = defaultConfig.Mode
mode[0].value = "PIPELINE"
def writer = new StringWriter()
def printer = new XmlNodePrinter(new PrintWriter(writer))
printer.with {
preserveWhitespace = true
expandEmptyElements = true
}
printer.print(defaultConfig)
def result = writer.toString()
new File(folderPath + "/bcvrun.prj.xml").write(result)
return outputPath
}
def Closure getWaitingPipeline = {Bcvjob job ->
def queueSize = Bcvjob.countByDateCreatedLessThanEquals(job.dateCreated) + Stapjob.countByDateCreatedLessThanEquals(job.dateCreated)
if(queueSize > 2){
println (" bcv waiting in queue; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
while (queueSize > 2){ // 1 running task + our task
sleep(5000)
queueSize = Bcvjob.countByDateCreatedLessThanEquals(job.dateCreated) + Stapjob.countByDateCreatedLessThanEquals(job.dateCreated)
}
println (" bcv finished waiting in queue; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
def res = new File(getResults(job.sessionId)).newWriter()
res.write("Your task was submitted at ${new Date()}<p>")
res.write("Running..<p>")
res.write("Please, bookmark this page to see the results later. Refresh the page to check if they are ready.")
res.close()
}
def returnCode = runPipeline(job.sessionId)
println (" bcv waiting pipeline finished; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
if (returnCode != 143){
zipResults(job.sessionId)
println (" bcv waiting results zipped; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
if (returnCode == 0){
if (job.email) {
sendResults(job.email, job.sessionId)
println (" bcv waiting results sent; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
}
else {
if (job.email) {
sendLogs(job.email, job.sessionId)
println (" bcv bad news sent; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
else if (returnCode != 143) {
sendLogs(job.sessionId) // send to weidewind
}
else {
println (" user left; sessionId ${job.sessionId} ")
}
}
def sessionId = job.sessionId
job.delete(flush:true)
holderService.setDone(sessionId)
}
def Closure getPipeline = {Bcvjob job ->
def returnCode = runPipeline(job.sessionId)
println (" bcv pipeline finished; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
if (returnCode != 143){
zipResults(job.sessionId)
println (" bcv results zipped; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
if (returnCode == 0){
if (job.email) {
sendResults(job.email, job.sessionId)
println (" bcv results sent; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
}
else {
if (job.email) {
sendLogs(job.email, job.sessionId, returnCode)
println (" bcv bad news sent; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
else if (returnCode != 143) {
sendLogs(job.sessionId) // send to weidewind
}
else {
println (" user left; sessionId ${job.sessionId} ")
}
}
def sessionId = job.sessionId
job.delete(flush:true)
holderService.setDone(sessionId)
}
private def addResultsPath(String sessionId, String outputPath){
outputMap.putAt(sessionId, outputPath)
}
def runPipeline(String sessionId){
println (" going to run bcv pipeline, sessionId ${sessionId}")
def command = "perl /store/home/popova/Programs/BCV_pipeline/pipeline.pl ${absPath}${sessionId} bcvrun.prj.xml >${absPath}pipelinelog.txt >2${absPath}pipelinerr.txt"// Create the String
holderService.procs[sessionId] = command.execute() // Call *execute* on the string
holderService.procs[sessionId].consumeProcessOutput( System.out, System.err ) //31.10
holderService.procs[sessionId].waitFor() // Wait for the command to finish
def exitValue = holderService.procs[sessionId].exitValue()
println "return code " + exitValue
holderService.deleteProc(sessionId)
return exitValue
}
def uploadFiles(String uploadPath, List fileList){
for (f in fileList){
if(f instanceof org.springframework.web.multipart.commons.CommonsMultipartFile){
def fileName = f.getOriginalFilename().replaceAll("\\s+", "_")
new FileOutputStream(uploadPath + "/" + fileName).leftShift( f.getInputStream() )
} else {
log.error("wrong attachment type [${f.getClass()}]");
}
}
}
def uploadSequenceFiles(String uploadPath, List fileList){
for (f in fileList){
if(f instanceof org.springframework.web.multipart.commons.CommonsMultipartFile){
def fileName = f.getOriginalFilename().replaceAll("\\s+", "_")
new FileOutputStream(uploadPath + "/" + fileName.replaceAll(Pattern.compile('\\..*'), '') + "/" + fileName).leftShift( f.getInputStream() )
} else {
log.error("wrong attachment type [${f.getClass()}]");
}
}
}
def sendResults(String email, String sessionId) {
def results = getZipResults(sessionId)
println "going to send files, sessionID ${sessionId} resultsPath ${results} time ${System.currentTimeMillis()}"
mailService.sendMail {
multipart true
to email
subject "BCV results"
body "Thanks for using BCV!\n Here are your results. \n Have a nice day!"
attachBytes 'results.zip','application/zip', new File(results).readBytes()
}
}
def sendExampleResults(String email, String folderName){
def results = getStorePath() + folderName + "/results.zip"
println "going to send files, folderName ${folderName} resultsPath ${results} time ${System.currentTimeMillis()}"
mailService.sendMail {
multipart true
to email
subject "Example BCV results"
body "Thanks for using BCV!\n Here are your example results. \n Have a nice day!"
attachBytes 'results.zip','application/zip', new File(results).readBytes()
}
}
def sendLogs(String email, String sessionId) {
//def logs = "${absPath}${sessionId}logfile"
def results = getZipResults(sessionId)
println "going to send logs, sessionID ${sessionId} logPath ${logs} time ${System.currentTimeMillis()}"
mailService.sendMail {
multipart true
to email
subject "BCV failed"
body "We are very sorry, but something has gone amiss. Here are some of your results, though."
attachBytes 'results.zip','application/zip', new File(results).readBytes()
}
//just in case there is no results at all and results.zip does not exist. Todo: catch mailService or zip exception
//else user left, auto-termination
mailService.sendMail {
multipart true
to "weidewind#gmail.com"
subject "BCV failed"
body "Achtung! email: ${email}, sessionId: ${sessionId}"
}
mailService.sendMail {
multipart true
to "weidewind#gmail.com"
subject "BCV failed"
body "Achtung! email: ${email}, sessionId: ${sessionId}"
attachBytes 'results.zip','application/zip', new File(results).readBytes()
}
println (" bcv bad news sent to webmaster; sessionId ${job.sessionId} time ${System.currentTimeMillis()}")
}
def sendLogs(String sessionId){
//just in case there is no results at all and results.zip does not exist. Todo: catch mailService or zip exception
mailService.sendMail {
multipart true
to "weidewind#gmail.com"
subject "BCV failed"
body "Achtung! sessionId: ${sessionId}"
}
println (" bcv bad news sent to webmaster; sessionId ${sessionId} time ${System.currentTimeMillis()}")
}
def zipResults(String sessionId){
def output = getOutput(sessionId)
def results = getZipResults(sessionId)
println "going to zip files, sessionID ${sessionId} time ${System.currentTimeMillis()}"
println (output)
def p = ~/.*\.(svg|html|with_names|cluster\.fasta)/
def filelist = []
def outputDir = new File(output)
outputDir.eachDir { chrom ->
def chromDir = new File(chrom.absolutePath)
chromDir.eachFileMatch(FileType.FILES, p){ tree ->
def splittedPath = tree.absolutePath.split('/')
println ("going to add ${splittedPath[splittedPath.size()-2]}/${splittedPath[splittedPath.size()-1]} from ${output} to zip list; sessionId ${sessionId}")
filelist.add("${splittedPath[splittedPath.size()-2]}/${splittedPath[splittedPath.size()-1]}")
}
}
filelist.add("simple_results.html")
println("results will be placed here ${results}")
def zipFile = new File("${results}")
new AntBuilder().zip( basedir: output,
destFile: zipFile.absolutePath,
includes: filelist.join( ' ' ) )
}
def getResults (String sessionId){
return outputMap.getAt(sessionId) + "/simple_results.html"
}
def getOutput(String sessionId){
return outputMap.getAt(sessionId)
}
def getZipResults(String sessionId){
return outputMap.getAt(sessionId) + "/results.zip"
}
def getExampleFolderName(List fileList){
def exampleFileNames = []
for (f in fileList){
exampleFileNames.add(f.name)
}
exampleFileNames.sort()
def folderName = ""
for (f in exampleFileNames){
folderName = folderName + (f.replaceAll(Pattern.compile('\\..*'), ''))
}
println folderName
return folderName
}
def checkInput(Bcvjob job, List fileList){
String errorMessage = ""
if (!job.validate()) {
errorMessage = "Some errors occured: "
job.errors.each {
errorMessage += "<p>" + it + "</p>"
}
//if (!isFloat(job.distance) || job.distance.toFloat() < 0 || job.distance.toFloat() > 0.1){
if ( job.distance < 0 || job.distance > 0.1){
errorMessage += "<p> Maximum distance must not be less than 0 or more than 0.1 </p>"
}
if (job.errors.hasFieldErrors("email")){
errorMessage += "<p>Your e-mail does not seem valid </p>"
}
if (job.errors.hasFieldErrors("files") || (fileList.size() == 0 & job.isExample == "false")){
errorMessage += "<p>Select at least one file </p>"
}
}
if (fileList.size() > 10){
errorMessage += "<p>Please, do not select more than 10 files at once. </p>"
}
if (job.isExample == "false"){
for (f in fileList) {
def name = f.getOriginalFilename()
int dot= name.lastIndexOf(".");
if (name.substring(dot+1) != "ab1"){
errorMessage += "<p>Unsupported extension: ${name} </p>"
}
def bytes = f.getBytes()
if (bytes[0] != 'A' || bytes[1] != 'B' || bytes[2] != 'I' || bytes[3] != 'F' || !(bytes[4]+bytes[5] >= 101)){
errorMessage += "<p>Not ABI: ${name} </p>"
}
}
}
return errorMessage
}
def isFloat(String value)
{
try
{
Float.parseFloat(value);
return true;
} catch(NumberFormatException nfe)
{
return false;
}
}
def getAbsPath(){
return Holders.config.absPath
}
def getStorePath(){
return Holders.config.storePath
}
def talkWork(){
ServiceCategory.talkWork()
}
def talkQueue(){
ServiceCategory.talkQueue()
}
}

Related

Active choices reactive parameter doesn't show desired default branch

I want to use Jenkins' active choices reactive parameter to use Groovy script to show all branches in the repository.
I have the following code sample to get all branches of a repository and since that there are hundreds of branches, I want the default to be master branch.
Even though I specifically inserted the defaultBranch variable, it shows the first item as the default and not the branch I written to.
Code:
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import jenkins.model.Jenkins
def git_url ="url"
def getAllBranches(url, credentialID, activeChoice = false, defaultBranch = 'master') {
def jenkinsCredentials = CredentialsProvider.lookupCredentials(
com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey,
Jenkins.instance
);
def key = jenkinsCredentials.findResult { it.id == credentialID ? it.privateKey : null }
if( !key ) {
return 'Error: credentials not found'
}
Process process = ['ssh-agent','bash','-c', "echo '" + key + "' | ssh-add - 2> /dev/null && git ls-remote -t -h " + url].execute()
def out = new StringBuilder()
def err = new StringBuilder()
process.consumeProcessOutput( out, err )
process.waitFor()
if( err.size() > 0 ) return err
if( out.size() > 0 ) {
def branches = out.readLines().collect { it.split()[1].replaceAll('refs/heads/', '') }
if( activeChoice ) {
def defaultBranchIndex = branches.indexOf(defaultBranch)
if( defaultBranchIndex >= 0 ) branches.set(defaultBranchIndex, defaultBranch + ':selected')
}
return branches
}
}
return getAllBranches(git_url, "efa7bed9-56a0-42ac-8fa3-a68fe7700801")
You have set default for activeChoice to false in the getAllBranches method and do not set while calling it, thus the if-branch that adds the :selected is never entered.
I changed activeChoice method's value from false to true and it solved my issue:
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import jenkins.model.Jenkins
def git_url ="url"
def getAllBranches(url, credentialID, activeChoice = true, defaultBranch = 'master') {
def jenkinsCredentials = CredentialsProvider.lookupCredentials(
com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey,
Jenkins.instance
);
def key = jenkinsCredentials.findResult { it.id == credentialID ? it.privateKey : null }
if( !key ) {
return 'Error: credentials not found'
}
Process process = ['ssh-agent','bash','-c', "echo '" + key + "' | ssh-add - 2> /dev/null && git ls-remote -t -h " + url].execute()
def out = new StringBuilder()
def err = new StringBuilder()
process.consumeProcessOutput( out, err )
process.waitFor()
if( err.size() > 0 ) return err
if( out.size() > 0 ) {
def branches = out.readLines().collect { it.split()[1].replaceAll('refs/heads/', '') }
if( activeChoice ) {
def defaultBranchIndex = branches.indexOf(defaultBranch)
if( defaultBranchIndex >= 0 ) branches.set(defaultBranchIndex, defaultBranch + ':selected')
}
return branches
}
}
return getAllBranches(git_url, "efa7bed9-56a0-42ac-8fa3-a68fe7700801")

Jenkins RoleBasedAuthorizationStrategy add user to Role Groovy Script

I am trying to find a groovy script to add an existing user to a Role using RoleBasedAuthorizationStrategy. Any help would be greatly appreciated.
I ran into the same need. After doing some web searching and looking at the plugin's code from GitHub, I found one link that provided some insight: https://issues.jenkins-ci.org/browse/JENKINS-23709. Based on that I hacked together a quick Groovy script that assigns a specific user to a specific role. Been awhile since I've done Groovy, so pardon the dust. Feel free to use this as an example for your own needs.
import jenkins.model.*
import hudson.security.*
import java.util.*
import com.michelin.cio.hudson.plugins.rolestrategy.*
import java.lang.reflect.*
def roleName = "guest"
def userName = "bot-release"
def findGuestRoleEntry(grantedRoles, roleName)
{
for (def entry : grantedRoles)
{
Role role = entry.getKey()
if (role.getName().equals(roleName))
{
return entry
}
}
return null
}
def authStrategy = Jenkins.instance.getAuthorizationStrategy()
if(authStrategy instanceof RoleBasedAuthorizationStrategy){
RoleBasedAuthorizationStrategy roleAuthStrategy = (RoleBasedAuthorizationStrategy) authStrategy
// Make constructors available
Constructor[] constrs = Role.class.getConstructors();
for (Constructor<?> c : constrs) {
c.setAccessible(true);
}
// Make the method assignRole accessible
Method assignRoleMethod = RoleBasedAuthorizationStrategy.class.getDeclaredMethod("assignRole", String.class, Role.class, String.class);
assignRoleMethod.setAccessible(true);
def grantedRoles = authStrategy.getGrantedRoles(RoleBasedAuthorizationStrategy.GLOBAL);
if (grantedRoles != null)
{
// println "Got grantedRoles for " + RoleBasedAuthorizationStrategy.GLOBAL
def roleEntry = findGuestRoleEntry(grantedRoles, roleName);
if (roleEntry != null)
{
// println "Found role " + roleName
def sidList = roleEntry.getValue()
if (sidList.contains(userName))
{
println "User " + userName + " already assigned to role " + roleName
} else {
println "Adding user " + userName + " to role " + roleName
roleAuthStrategy.assignRole(RoleBasedAuthorizationStrategy.GLOBAL, roleEntry.getKey(), userName);
println "OK"
}
Jenkins.instance.save()
} else {
println "Unable to find role " + roleName
}
} else {
println "Unable to find grantedRoles for " + RoleBasedAuthorizationStrategy.GLOBAL
}
} else {
println "Role Strategy Plugin not found!"
}

How to get the changes since the last successful build in jenkins pipeline?

Anyone have a Jenkins Pipeline script that can stuff all the changes since the previous successful build in a variable? I'm using git and a multibranch pipeline job.
Well I managed to cobble something together. I'm pretty sure you can iterate the arrays better but here's what I've got for now:
node('Android') {
passedBuilds = []
lastSuccessfulBuild(passedBuilds, currentBuild);
def changeLog = getChangeLog(passedBuilds)
echo "changeLog ${changeLog}"
}
def lastSuccessfulBuild(passedBuilds, build) {
if ((build != null) && (build.result != 'SUCCESS')) {
passedBuilds.add(build)
lastSuccessfulBuild(passedBuilds, build.getPreviousBuild())
}
}
#NonCPS
def getChangeLog(passedBuilds) {
def log = ""
for (int x = 0; x < passedBuilds.size(); x++) {
def currentBuild = passedBuilds[x];
def changeLogSets = currentBuild.rawBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
log += "* ${entry.msg} by ${entry.author} \n"
}
}
}
return log;
}
Based on the answer from CaptRespect I came up with the following script for use in the declarative pipeline:
def changes = "Changes:\n"
build = currentBuild
while(build != null && build.result != 'SUCCESS') {
changes += "In ${build.id}:\n"
for (changeLog in build.changeSets) {
for(entry in changeLog.items) {
for(file in entry.affectedFiles) {
changes += "* ${file.path}\n"
}
}
}
build = build.previousBuild
}
echo changes
This is quite useful in stage->when->expression parts to run a stage only when certain files were changed. I haven't gotten to that part yet though, I'd love to create a shared library from this and make it possible to pass it some globbing patterns to check for.
EDIT: Check the docs btw, in case you want to delve a little deeper. You should be able to convert all the object.getSomeProperty() calls into just entry.someProperty.
This is what I've used:
def listFilesForBuild(build) {
def files = []
currentBuild.changeSets.each {
it.items.each {
it.affectedFiles.each {
files << it.path
}
}
}
files
}
def filesSinceLastPass() {
def files = []
def build = currentBuild
while(build.result != 'SUCCESS') {
files += listFilesForBuild(build)
build = build.getPreviousBuild()
}
return files.unique()
}
def files = filesSinceLastPass()
There's the Changes Since Last Success Plugin that could help you with that.
For anyone using Accurev here is an adaptation of andsens answer. andsens answer can't be used because the Accurev plugin doesn't implement getAffectedFiles. Documentation for the AccurevTransaction that extends the ChangeLogSet.Entry class can be found at here.
import hudson.plugins.accurev.*
def changes = "Changes: \n"
build = currentBuild
// Go through the previous builds and get changes until the
// last successful build is found.
while (build != null && build.result != 'SUCCESS') {
changes += "Build ${build.id}:\n"
for (changeLog in build.changeSets) {
for (AccurevTransaction entry in changeLog.items) {
changes += "\n Issue: " + entry.getIssueNum()
changes += "\n Change Type: " + entry.getAction()
changes += "\n Change Message: " + entry.getMsg()
changes += "\n Author: " + entry.getAuthor()
changes += "\n Date: " + entry.getDate()
changes += "\n Files: "
for (path in entry.getAffectedPaths()) {
changes += "\n " + path;
}
changes += "\n"
}
}
build = build.previousBuild
}
echo changes
writeFile file: "changeLog.txt", text: changes
In order to return the changes as a list of strings, instead of just printing them, you may use this function (based on #andsens answer):
def getChangesSinceLastSuccessfulBuild() {
def changes = []
def build = currentBuild
while (build != null && build.result != 'SUCCESS') {
changes += (build.changeSets.collect { changeSet ->
(changeSet.items.collect { item ->
(item.affectedFiles.collect { affectedFile ->
affectedFile.path
}).flatten()
}).flatten()
}).flatten()
build = build.previousBuild
}
return changes.unique()
}

Grails NumberFormatException

I am receiving NumberFormatException error in my Grails code which is to sort movies into a database. The error suggests it is from the cron plugin. I have done my research and I have been trying to catch the error by using NumberFormatException but to no avail. I think the problem lies in the IndexService. Any help would be much appreciated.
The exact error is:
2014-07-25 10:09:07,779 [quartzScheduler_Worker-1] ERROR listeners.ExceptionPrinterJobListener - Exception occurred in job: Grails Job
Message: java.lang.NumberFormatException: For input string: "N/A"
I am using:
Grails version: 2.4.2
Groovy version: 2.3.3
JVM version: 1.7.0_51
quartz - 1.0.2
My code:
IndexService
package movie
import groovy.io.FileType
import groovy.json.JsonSlurper
class IndexService {
static transactional = false
def grailsApplication
private cleanText(String title)
{
//split string into array via .,+,[,] etc...
def splitTitle=(title.toLowerCase()).tokenize('+.[]!£$%^+=~#:; \t \n \r \f / \\ { } # & - ( )')
//Get rid of extention
splitTitle.remove(splitTitle.size()-1)
//Get rid of Dvdrip and author
//unwanted phrases
def unwanted=["dvdrip","eng","www","torentz","3xforum","bugz","ro","maxspeed","xvid","720p","bluray","yify","1080p","hd","x264","RARBG","mp3","mp4","flv","brrip","rip"]
//Get rid of dates
//get 2000 to current date to put into the unwanted list
for(i in 2000..3000){unwanted.add(i.toString())}
//def empty string to put all our cleaned up text into
def cleanedText = ""
//cleaning up word mess...
splitTitle.each {word->
if(!unwanted.contains(word))
{
cleanedText=cleanedText+word+" "
}
}
//returning with +'s
return (cleanedText[0..-2]).replaceAll("\\s","+")
}
def getInfo(String title)
{
//returned nice with +
def cleanTitle=cleanText(title)
//define my reader
def scan = new JsonSlurper()
def scanner =scan.parseText(("http://www.omdbapi.com/?i=&plot=full&t="+cleanTitle).toURL().text)
if(scanner.Response=="True")
{
/*
organisied like this:
String artwork
String title
Date dateReleased
String userRated
String lengthOfFilm
String genre
String plot
float rating
*/ //returns our info we have scraped
return [
true,
scanner.Poster,
scanner.Title,
new Date(scanner.Released),
scanner.Rated,
scanner.Runtime,
scanner.Genre,
scanner.Plot,
scanner.imdbRating.toFloat()/10
]
}
else
{
return [null,cleanTitle]
}
}
def indexFiles()
{
//returns fileLocation
def fileLocation=grailsApplication.config.grails.movie.location
//Setup as file object
def dir = new File(fileLocation)
//recurse all files
dir.eachFileRecurse (FileType.FILES) { file ->
println(file)
//only create a record if no file test if record exists
if(!Record.findByPathToFile(file.getCanonicalPath())) {
//get record propreties set
def record = new Record()
record.pathToFile = file.getCanonicalPath()
//call to get data of a film returns as a list
def info = getInfo(file.getName())
//check if everthing is alright
info.each{print(it)}
if (info[0] == null) {
try {
//set fallback propeties
record.artwork = null
record.title = info[1].replaceAll("\\+"," ")
record.genre = null
record.dateReleased = new Date(file.lastModified())
record.lengthOfFilm = null
record.plot = null
record.rating = 0
record.userRated = null
record.save(failOnError: true)
}
catch (NumberFormatException e) {
//catch any errors
log.error("Error caught :${e} \n")
}
}
else
{
try
{
//set good propeties
record.artwork = info[1]
record.title = info[2]
record.genre = info[6]
record.dateReleased = info[3]
record.lengthOfFilm = info[5]
record.plot = info[7]
print(info[8])
record.rating = info[8]
record.userRated = info[4]
record.save(failOnError: true)
}
catch (NumberFormatException e) {
//catch any errors
info.each
{
print(it)
}
log.error("Error caught :${e} \n")
}
}
}
}
}
}
Record domain
package movie
class Record {
//static searchable = true
//data will be recieved via http://www.omdbapi.com/
String artwork
String title
Date dateReleased
String pathToFile
String userRated
String lengthOfFilm
String genre
String plot
float rating
static constraints = {
artwork nullable: true
title nullable: false, unique: true
dateReleased nullable: false
pathToFile nullable: false
userRated nullable: true
lengthOfFilm nullable: true
genre nullable: true
plot nullable: true, maxSize: 2000
rating nullable: true
}
}
And finally IndexJob
package movie
class IndexJob {
static triggers = {
/*
cronExpression: "s m h D M W Y"
| | | | | | `- Year [optional]
| | | | | `- Day of Week, 1-7 or SUN-SAT, ?
| | | | `- Month, 1-12 or JAN-DEC
| | | `- Day of Month, 1-31, ?
| | `- Hour, 0-23
| `- Minute, 0-59
`- Second, 0-59
*/
cron name: "indexTrigger", cronExpression: "0 0/1 * * * ? *"
}
def indexService
def execute() {
indexService.indexFiles()
}
}
Try this:
package movie
import groovy.io.FileType
import groovy.json.JsonSlurper
class IndexService {
static transactional = false
def grailsApplication
private cleanText(String title)
{
//split string into array via .,+,[,] etc...
def splitTitle=(title.toLowerCase()).tokenize('+.[]!£$%^+=~#:; \t \n \r \f / \\ { } # & - ( )')
//Get rid of extention
splitTitle.remove(splitTitle.size()-1)
//Get rid of Dvdrip and author
//unwanted phrases
def unwanted=["dvdrip","eng","www","r5","unique","torentz","3xforum","bugz","ro","maxspeed","xvid","720p","bluray","yify","1080p","hd","x264","RARBG","mp3","mp4","flv","brrip","rip"]
//Get rid of dates
//get 2000 to current date to put into the unwanted list
for(i in 2000..3000){unwanted.add(i.toString())}
//def empty string to put all our cleaned up text into
def cleanedText = ""
//cleaning up word mess...
splitTitle.each {word->
if(!unwanted.contains(word))
{
cleanedText=cleanedText+word+" "
}
}
//returning with +'s
return (cleanedText[0..-2]).replaceAll("\\s","+")
}
def getInfo(String title)
{
//returned nice with +
def cleanTitle=cleanText(title)
//define my reader
def scan = new JsonSlurper()
def scanner =scan.parseText(("http://www.omdbapi.com/?i=&plot=full&t="+cleanTitle).toURL().text)
if(scanner.Response=="True")
{
/*
organisied like this:
String artwork
String title
Date dateReleased
String userRated
String lengthOfFilm
String genre
String plot
float rating
*/ //returns our info we have scraped
def imdb = scanner.imdbRating
if (imdb.equalsIgnoreCase("n/a")) {
imdb = "0"
}
return [
true,
scanner.Poster,
scanner.Title,
new Date(scanner.Released),
scanner.Rated,
scanner.Runtime,
scanner.Genre,
scanner.Plot,
imdb.toFloat()/10
]
}
else
{
return [null,cleanTitle]
}
}
def indexFiles()
{
//returns fileLocation
def fileLocation=grailsApplication.config.grails.movie.location
//Setup as file object
def dir = new File(fileLocation)
//recurse all files
dir.eachFileRecurse (FileType.FILES) { file ->
//only create a record if no file test if record exists
if(Record.findByPathToFile(file.getCanonicalPath())==null) {
//get record propreties set
def record = new Record()
record.pathToFile = file.getCanonicalPath()
//call to get data of a film returns as a list
def info = getInfo(file.getName())
//check if everthing is alright
if (info[0] == null) {
try {
//set fallback propeties
record.artwork = null
record.title = info[1].replaceAll("\\+"," ")
record.genre = null
record.dateReleased = new Date(file.lastModified())
record.lengthOfFilm = null
record.plot = null
record.rating = 0
record.userRated = null
record.save(failOnError: true)
}
catch (Exception e) {
//catch any errors
//log.error("Error caught :${e} \n")
}
}
else
{
try
{
//set good propeties
record.artwork = info[1]
record.title = info[2]
record.genre = info[6]
record.dateReleased = info[3]
record.lengthOfFilm = info[5]
record.plot = info[7]
record.rating = info[8]
record.userRated = info[4]
record.save(failOnError: true)
}
catch (Exception e) {
catch any errors
log.error("Error caught :${e} \n")
}
}
}
}
}
}
It took me an hour to work that out!

Redirect to external site does not terminate current execution flow

I'm using grails 1.3.7.
I have the following filter setup:
class MyFilters {
def userService
def springSecurityService
def filters = {
all(controller: '*', action: '*') {
before = {
String userAgent = request.getHeader('User-Agent')
int buildVersion = 0
// Match "app-/{version}" where {version} is the build number
def matcher = userAgent =~ "(?i)app(?:-\\w+)?\\/(\\d+)"
if (matcher.getCount() > 0)
{
buildVersion = Integer.parseInt(matcher[0][1])
log.info("User agent is from a mobile with build version = " + buildVersion)
log.info("User agent = " + userAgent)
String redirectUrl = "https://anotherdomain.com"
if (buildVersion > 12)
{
if (request.queryString != null)
{
log.info("Redirecting request to anotherdomain with query string")
redirect(url:"${redirectUrl}${request.forwardURI}?${request.queryString}",params:params)
}
return
}
}
}
after = { model ->
if (model) {
model['currentUser'] = userService.currentUser
}
}
afterView = {
}
}
}
}
A problem occurs in that the redirect does not happen at the point I would have thought.
I want all execution to stop and redirect to the exaact url I have given it at this point.
When i debug to the "redirect" line, it continues past this line exectuting other lines and jumping to another controller.
In order to prevent the normal processing flow from continuing, you need to return false from your before filter:
if (buildVersion > 12)
{
if (request.queryString != null)
{
log.info("Redirecting request to anotherdomain with query string")
redirect(url:"${redirectUrl}${request.forwardURI}?${request.queryString}",params:params)
return false
}
}
This is mentioned in passing at the very end of section 6.6.2 of the user guide, but it isn't particularly prominent:
Note how returning false ensure that the action itself is not executed.

Resources