I am getting the following error when trying to run my jenkins job. Any help would be much appreciated
java.lang.IllegalArgumentException: Expected named arguments but got
[org.jenkinsci.plugins.workflow.cps.CpsClosure2#33c7c4a6,
org.jenkinsci.plugins.workflow.cps.CpsClosure2#79505a8c,
org.jenkinsci.plugins.workflow.cps.CpsClosure2#6a96df3,
org.jenkinsci.plugins.workflow.cps.CpsClosure2#1a0cb771,
org.jenkinsci.plugins.workflow.cps.CpsClosure2#17e3a262] at
org.jenkinsci.plugins.workflow.cps.DSL.singleParam(DSL.java:606) at
org.jenkinsci.plugins.workflow.cps.DSL.parseArgs(DSL.java:594) at
org.jenkinsci.plugins.workflow.cps.DSL.parseArgs(DSL.java:534) at
org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:219) at
org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:178) at
org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
at sun.reflect.GeneratedMethodAccessor102.invoke(Unknown Source)
My code is:
node("dvsacvsmgmt") {
stage("Build") {
def buildJobs = []
for (BACKEND_SERVICE in BACKEND_SERVICES) {
SVC = BACKEND_SERVICE.replaceAll('-','_')
switch (BRANCH_SVC) {
case ["develop","master"]:
def buildJob = {
build "${ROOT_FOLDER}/2_Build/Backend/${SVC}/job_build_backend_" + BRANCH_SVC + "_" + SVC +".groovy"
}
buildJobs.add(buildJob)
break
default:
def buildJob = {
build "job_${SVC}": "${ROOT_FOLDER}/2_Build/Backend/${SVC}/job_build_backend_" + BRANCH_SVC + "_" + SVC +".groovy",
parameters: [gitParameter(name: "BRANCH", value: BRANCH_SVC)]
}
buildJobs.add(buildJob)
break
}
}
parallel(buildJobs)
}
}
NOTE: My variables are defined at the top,
BRANCH, BRANCH_SVC, ROOT_FOLDER, BACKEND_SERVICES
You see this exception because buildJobs in your example is a list of closures and it should be a map instead. It would make sense to use backend service name as a key for the map you pass to parallel() method. Consider the following changes to your code:
node("dvsacvsmgmt") {
stage("Build") {
def buildJobs = [:]
for (BACKEND_SERVICE in BACKEND_SERVICES) {
SVC = BACKEND_SERVICE.replaceAll('-','_')
switch (BRANCH_SVC) {
case ["develop","master"]:
def buildJob = {
build "${ROOT_FOLDER}/2_Build/Backend/${SVC}/job_build_backend_" + BRANCH_SVC + "_" + SVC +".groovy"
}
buildJobs.put(BACKEND_SERVICE, buildJob)
break
default:
def buildJob = {
build "job_${SVC}": "${ROOT_FOLDER}/2_Build/Backend/${SVC}/job_build_backend_" + BRANCH_SVC + "_" + SVC +".groovy",
parameters: [gitParameter(name: "BRANCH", value: BRANCH_SVC)]
}
buildJobs.put(BACKEND_SERVICE, buildJob)
break
}
}
parallel(buildJobs)
}
}
It invokes
buildJobs.put(BACKEND_SERVICE, buildJob)
instead
buildJobs.add(buildJob)
to create a map that is seen as named arguments in parallel method call.
Related
I'm changing my jenkins job's SCM url from, lets say gitlab to github by using Groovy script. Is there any way to minimize the complexity of this code ?
I have used Jenkins.instance.items.each {} which traverses through all the jobs in my jenkins
import hudson.plugins.git.*
import jenkins.*
import jenkins.model.*
def modifyGitUrl(url) {
def newurl = url.replace("source", "destination")
return newurl
}
def modifyGitID(credentialsId) {
def newID = ("Jenkins User ID")
return newID
}
Jenkins.instance.items.each {
if(it.name == "expected name"){
if (it.scm instanceof GitSCM) {
def oldScm = it.scm
def newUserRemoteConfigs = oldScm.userRemoteConfigs.collect {
new UserRemoteConfig(modifyGitUrl(it.url), it.name, it.refspec, modifyGitID(it.credentialsId))
}
def newScm = new GitSCM(newUserRemoteConfigs, oldScm.branches, oldScm.doGenerateSubmoduleConfigurations,
oldScm.submoduleCfg, oldScm.browser, oldScm.gitTool, oldScm.extensions)
it.scm = newScm
it.save()
}
}
}
I am trying to augment the 'load' pipeline step function and I keep getting an error. I have found the code it executes based on the stack trace but I can't for the life of me figure out why it wouldn't just call the code as written.
I have written lots-and-lots of Java code so I know what it's trying to do. I just don't understand why it's trying to do it or how to convince it to stop! The groovy sample works perfectly! BTW: if there is an idiomatic way to do this in groovy/jenkins, I am all in.
Jenkins version: 2.176.1
Groovy plugin: 2.2
test.groovy
def someFunction(def params){
println("someFunction ${params}")
}
def someFunction2(def params){
println("someFunction2 ${params}")
}
def mainFunc(def stuff){
}
def somemainThingrunFunmain(){
}
def ___cps___21685(){
}
def ___cps___21688(){
}
this
main.groovy
def loaded = evaluate('test.groovy' as File)
def toAugment = loaded.class.declaredMethods*.name.findAll { !(it =~ '^(main|run)$|^[$]|^(___cps___)') }
def proxy = new Script(this.binding) {
#Override
Object run() {
monad.run()
}
}
toAugment.each {
proxy.metaClass."${it}" = { "logging ${it}".tap { println(it)} } >> loaded.&"${it}"
}
proxy.someFunction('hello world1')
proxy.someFunction2('hello world2')
outputs:
called
someFunction hello world1
called
someFunction2 hello world2
Now in Jenkins:
Jenkinsfile:
library 'common-libraries#chb0'
node('java') {
stage('SCM') {
checkout scm
}
def loaded = load('test.groovy')
stage('experiment') {
loaded.someFunction('hello world1')
loaded.someFunction2('hello world2')
}
}
adapted library (in common-library:vars/load.groovy):
def call(String path) {
def loaded = steps.load(path)
def proxy = new Script(this.getBinding()) { // error here
#Override
Object run() {
loaded.run()
}
}
// remove groovy and jenkins generated functions. Don't touch those
def toAugment = loaded.class.declaredMethods*.name.findAll { !(it =~ '^(main|run)$|^[$]|^(___cps___)') }
toAugment.each {
proxy.metaClass."${it}" = { "logging ${it}".tap { println(it) } } >> loaded.&"${it}"
}
}
exception:
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: load$1(load, Script1, groovy.lang.Binding)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1732)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1532)
at org.codehaus.groovy.runtime.callsite.MetaClassConstructorSite.callConstructor(MetaClassConstructorSite.java:49)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.constructorCall(DefaultInvoker.java:25)
How can I join strings nicely into a path when programming Jenkins Groovy pipeline? So that I can join('http://example.com/', '/r', 'some.html') -> 'http://example.com/r/some.html'
This note suggests using new File(dir1, dir2) or Paths.get(dir1, dir2) in "pure" Groovy.
However in Jenkins pipeline, import java.nio.file.Paths gives me
No such static method found: staticMethod java.nio.file.Paths get java.lang.String org.codehaus.groovy.runtime.GStringImpl.
and with new File I get
Scripts not permitted to use new java.io.File java.lang.String java.lang.String. Administrators can decide whether to approve or reject this signature.
and I kinda agree with Jenkins on this do not want to allow this. Is there another way?
bad idea to build url with Paths or File objects because under windows you'll get wrong result.
you can build url with simple string concatenation and use URI.normalize() to remove extra slashes:
def u = new URI(['http://example.com/', '/r', 'some.html'].join('/')).normalize().toString()
Try this:
def join_two_urls(url1, url2) {
if (url1 == "" || url2 == "") {
println "Error: must provde two invalid urls."
return ""
}
println "Joining ${url1} and ${url2} ..."
if (url1 ==~ /.*\/$/) {
url1 = url1.substring(0, url1.length() - 1)
}
if (url2 ==~ /^\/.*/) {
url2 = url2.substring(1, url2.length())
}
return url1 + "/" + url2
}
def join_paths(String[] urls) {
if (urls.size() <= 1) {
println "Error: invalid urls."
return ""
}
conbined_url = ""
pre_url = ""
for (url in urls) {
if (pre_url == "") {
pre_url = url
continue
}
conbined_url += join_two_urls(pre_url, url)
}
return conbined_url
}
println join_paths("xx/", "xxx/" , "/fsdsdfsdf")
I am bit stuck on why when I run the following script in Jenkins Scriptler and the Script Console it works, yet when used in the Dynamic Choice Parameter (Scriptler), it fails with the error:
Error: groovy.lang.MissingPropertyException: No such property: com for class: Script1
I can only assume that it is to do with the used class com.cloudbees.plugins.credentials.CredentialsProvider is called.
Here is the script:
/*** BEGIN META {
"name" : "GetRemoteNasFolderList",
"comment" : "Retrieve a list of folder names (in reverse order) from a remote NAS location.",
"parameters" : [ 'ENVIRONMENT', 'SHARE_PATH', 'FOLDER_PATH' ],
"core": "1.565",
"authors" : [{
name : "Authors Name"
}]
} END META**/
import jenkins.model.Jenkins
try {
// params
def env = ENVIRONMENT // 'DEV" or 'TEST' or 'PROD'
def share_path = SHARE_PATH
def folder_path = FOLDER_PATH
String user_domain = ''
String nas_path = ''
switch (env) {
case 'DEV':
user_domain = 'dev';
nas_path = 'nas_host.dev.company.com.au';
break;
case 'TEST':
user_domain = 'test';
nas_path = 'nas_host.test.company.com.au';
break;
case 'PROD':
default:
user_domain = 'prod';
nas_path = 'nas_host.prod.company.com.au';
}
String user_name = 'myUserName'
def full_name = user_domain + '\\' + user_name
String pass_word = ''
def found = false
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance,
null,
null
);
for (c in creds) {
if (c.username == full_name) {
pass_word = c.password
found = true
}
}
if (found == true) {
url = "smb://" + nas_path + "/" + share_path + "/" + folder_path;
println("Url: "+url)
// println(user_domain+"\\"+user_name+", "+pass_word)
auth = new jcifs.smb.NtlmPasswordAuthentication(user_domain, user_name, pass_word);
dir = new jcifs.smb.SmbFile(url, auth);
folders = []
for (jcifs.smb.SmbFile f : dir.listFiles())
{
folders.push(f.getName().replace('/',''))
}
return folders.sort().reverse()
} else {
print("Credential entry not found for ( " + full_name + " )")
}
} catch (e) {
return ["Error: "+e]
} finally {
}
Any thoughts, anyone.
Error: groovy.lang.MissingPropertyException: No such property: xx for class: yy
Typical error message if your missing an import reference, have you tried referencing everything?
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*;
Perhaps this is what the Jenkins Scriptler and the Script Console do by default, where as the Dynamic Choice Parameter (Scriptler) doesn't.
Ref: https://github.com/chef-cookbooks/jenkins/issues/174
Switched to using a different plugin (Active Choices Parameter) that makes use of Scriptler scripts and is now working.
I want to use Logback as my logging framework within Grails. therefore I set up everything in place to work but my implementation fails on the configuration file itself. the reason is, as I guess, somewhere whithin the scoping of Groovy Script but I'm not able to figure it out...
if I define my String properties without any identifier which I want to use later I get a warning that it may not be accessed. For example:
LOG_DIR = 'c:/temp/myproject/logs/'
BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
I get the following error message from Logback, which I'm pretty sure is indicating that both LOG_DIR and BACKUP_DIR can not be reached:
13:33:32,036 |-ERROR in ch.qos.logback.classic.gaffer.AppenderDelegate#6fd00b - Appender [F_MAIN] of type [ch.qos.logback.core.rolling.RollingFileAppender] has no appplicable [LOG_DIR] property
13:33:32,068 |-ERROR in ch.qos.logback.classic.gaffer.ComponentDelegate#788ac3 - Component of type [ch.qos.logback.core.rolling.FixedWindowRollingPolicy] has no appplicable [BACKUP_DIR] property
I also tried the following approach by declaring both variables with the #Field tag, but it still does not work:
#Field String LOG_DIR = 'c:/temp/myproject/logs/'
#Field String BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
what am I doing wrong here?
oh my!
after searching and a lot of trial/error I found the solution and it was so close and definitely seems obvious now: I had to declare both variables with def, so now they are visible throughout the whole script ;)
For example, this is working code:
def LOG_DIR = 'c:/temp/myproject/logs/'
def BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
now, I'm also able to use a function like this within my script:
def createFilename(String directory, String name, boolean isBackupFile) {
String filename = ''
if(isBackupFile) {
filename = "${directory}backup/MyProject-${name}.%d{yyyy-MM-dd}.%i.log.zip"
} else {
filename = "${directory}MyProject-${name}.log"
}
return filename
}
def fileAppenderLog = createFilename(LOG_DIR, 'output', false)
def fileAppenderLogBackup = createFilename(LOG_DIR, 'output', true)
appender('F_MAIN', RollingFileAppender) {
file = fileAppenderLog
rollingPoliciy(FixedWindowRollingPolicy) {
fileNamePattern = fileAppenderLogBackup
// .... and so on
}
}
which is pretty useful, I think :), especially if you want to declare a bunch of different logfiles and even if you want to declare temporary logfiles which are created when Logback is rescanning this file ...