I am having a jenkinsfile where I have defined "CascadeChoiceParameter" parameter and this parameter will return values like "ABC","PQR" and "WRQ". Now, I want to show all this parameter values and store it as a list.
So, I know in extended choice parameter we can import below plugins and write a code to get all jenkins parameter values as shown below.
import hudson.model.*
import org.jenkinsci.plugins.workflow.job.*
import com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
def param = getParam(JOB_NAME, "Services")
def all_param_values = param.getValue().replaceAll("\\s","").tokenize(',').tail()
def service_name = ("${SERVICE_NAME}".replace('Services:', '')).toString().tokenize(',[]')
So, in my case to get all jenkins parameter values for "CascadeChoiceParameter" parameter I have imported below plugins and written below code:-
import hudson.model.*
import org.jenkinsci.plugins.workflow.job.*
import org.biouno.unochoice.CascadeChoiceParameter
#NonCPS
def getJob(name) {
def hi = Hudson.instance
return hi.getItemByFullName(name, Job)
}
#NonCPS
def getParam(String jobName, String paramName) {
def job = getJob(jobName)
def prop = job.getProperty(ParametersDefinitionProperty.class)
for (param in prop.getParameterDefinitions()) {
if (param.name == paramName) {
return param
}
}
return null
}
def param = getParam(JOB_NAME, "Test")
def all_param_values = param.getValue().replaceAll("\\s","").tokenize(',').tail()
def Test_name = ("${TEST_NAME}".replace('Test:', '')).toString().tokenize(',[]')
But, while running jenkins job I am getting below error.
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.biouno.unochoice.CascadeChoiceParameter.getValue() is applicable for argument types: () values: []
Can anyone assist?
Related
Somewhere in my shared library I got a helper class like this:
class Helper {
def script
Helper(script) {
this.script = script
}
void sendTemplate(String webhook, String template, Map<String, String> values, TemplateMapper mapper) {
def body = mapper.map(template, values)
def resp = script.httpRequest(contentType: 'APPLICATION_JSON', httpMode: 'POST',
requestBody: body, url: webhook)
if (resp.status != 200) {
throw new UnableToNotifyException()
}
}
}
I'm trying to test said class like so:
class HelperSpec extends JenkinsPipelineSpecification {
def helper
def setup() {
helper = new Helper(this)
}
def "a test"() {
setup:
def webhook = 'aWebhook'
def template = '%replaceMe'
def values = ['%replaceMe': 'hello world!']
def mapper = new SimpleTemplateMapper()
getPipelineMock('httpRequest')(_) >> [status: 200]
when:
helper.sendTemplate(webhook, template, values, mapper)
then:
1 * getPipelineMock('httpRequest')(_)
}
}
I'm using gradle and my build.gradle file has
testImplementation 'org.jenkins-ci.plugins:http_request:1.10#jar'
Other steps' tests run perfectly but with this one I always get
java.lang.IllegalStateException: There is no pipeline step mock for [httpRequest].
1. Is the name correct?
2. Does the pipeline step have a descriptor with that name?
3. Does that step come from a plugin? If so, is that plugin listed as a dependency in your pom.xml?
4. If not, you may need to call explicitlyMockPipelineStep('httpRequest') in your test's setup: block.
And when I use explicitlyMockPipelineStep('httpRequest') I get a null pointer exception, because, I presume, the default mock returns a null.
Is there anything I'm missing in the test to get it working? Thanks in advance!!!
I have two groovy files.
First.groovy:
class First {
def getContent() {
content = ["one", "two"]
}
}
return this
And second.groovy:
{
node(label) {
def listClass = this.class.classLoader.parseClass("First.groovy")
def CONTENT=listClass.getContent()
}
I get error from jenkins when I run the job:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.lang.Class.getContent() is applicable for argument types: () values: []
kindly advice on efficient way to import a list from one groovy file to another.
Jenkins offers the method load(filepath) for your case so you don't have to juggle with all the classloader methods.
You don't necessarely need the class in your First.groovy so simply remove it.
First.groovy
def getContent() {
def content = ["one", "two"]
return content
}
return this;
And call it like:
def first = load 'First.groovy'
def content = first.getContent()
I'm trying to create a JobGenerator class that will pass a build step down to the calling instance. I'm running into an issue where if I get this error when I try to run this:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.workflow.cps.CpsClosure2.build() is applicable for argument types: (java.util.LinkedHashMap) values: [[job:FooJob]]
class BuildGenerator implements Serializable {
static def generateJob() {
return [
"TestJob",
{ ->
build(
job: 'FooJob'
)
},
]
}
}
node(){
def tasks = [:]
def label
def task
stage("Build") {
def generator = new BuildGenerator()
tasks["Testing"] = generator.generateJob()[1]
parallel tasks
}
}
If I remove the generateJob function outside of the class then it works fine. What am I doing wrong with closures here? I'm new to groovy/jenkins world.
Well... This is the way Groovy/Jenkins pipeline work. build is available inside node as the rest of steps and functions. If you wish to access these you have to pass the CPS instance to the method, like this (or use constructor to pass the instance only once):
class BuildGenerator implements Serializable {
static def generateJob(script) {
return [
"TestJob",
{ ->
script.build(
job: 'FooJob'
)
},
]
}
}
node(){
def tasks = [:]
def label
def task
stage("Build") {
def generator = new BuildGenerator()
tasks["Testing"] = generator.generateJob(this)[1]
parallel tasks
}
}
My parameterized Freestyle job got one string parameter. MAIL_PARAM with the default value FREESTYLE_ERROR.
I am able to print the value with:
println "MAIL_PARAM=$Mail_Param"
Inside an Groovy execute Script. Now I want to change the value of this parameter based on some conditions. But I am not able to change it. I tried:
MAIL_PARAM = 'String'
$MAIL_PARAM ='String'
${MAIL_PARAM} ='String'
def params = new StringParameterValue('MAIL_PARAM', 'String')
and some more, but none of them are working. I have to change it because based on some results my groovy script has, I need different Strings inside of my parameter.
After the groovy script I need to pass this parameter to the next job. This works fine. But I only get the default value.
If I understand correctly, replaceAction should do the trick (there is also addOrReplaceAction):
import hudson.model.ParametersAction
import hudson.model.ParameterValue
import hudson.model.StringParameterValue
def newMailParameter = new StringParameterValue('MAIL_PARAM', '...')
build.replaceAction(new ParametersAction(newMailParameter))
Edit : if you get error "current build does not have any parameter" then please try "build.addOrReplaceAction" in place of "build.replaceAction".
modify from setBuildParameters: http://jenkins-ci.361315.n4.nabble.com/Modifying-a-builds-parameters-in-a-system-Groovy-script-td4636966.html
def addOrReplaceParamValue = { String name,String value ->
def build = currentBuild.getRawBuild();
def npl = new ArrayList<StringParameterValue>()
def pv = new hudson.model.StringParameterValue(name,value);
npl.add(pv);
def newPa = null
def oldPa = build.getAction(hudson.model.ParametersAction.class)
if (oldPa != null) {
build.actions.remove(oldPa)
newPa = oldPa.createUpdated(npl)
} else {
newPa = new hudson.model.ParametersAction(npl)
}
build.actions.add(newPa);
};
addOrReplaceParamValue("P1","p1");
Here's a more complete example if you need to modify based in the original value:
import hudson.model.ParametersAction
import hudson.model.ParameterValue
import hudson.model.StringParameterValue
def transformJobParameter(Closure transform) {
build.getActions(ParametersAction).each { paramAction ->
List<ParameterValue> overrides = []
paramAction.each { param ->
// Transformation takes a ParameterValue object but returns only its new value object, if any.
def newValue = transform(param)
if (newValue != null && newValue != param.value) {
// Create whatever the original object type was, but with a new value.
def newParam = param.class.newInstance([param.name, newValue, param.description] as Object[])
overrides << newParam
println("INFO - Transformed ${param.name} parameter from '${param.value}' to '$newValue'.")
}
}
if (!overrides.empty) {
def mergedParamAction = paramAction.merge(new ParametersAction(overrides))
build.replaceAction(mergedParamAction)
}
}
}
transformJobParameter { param ->
if (param instanceof StringParameterValue) {
def value = param.value.trim()
if (param.name == 'MAIL_PARAM') {
'String'
} else {
value
}
}
}
From the called build flow job, I've tried both:
build.environment['AOEU'] = 'aoeu' // callee would `println called.environment['AOEU']`
and:
upstream.environment['AOEU'] = 'aoeu' // callee would `println build.environment['AOEU']`
with no luck.
I fought a lot with that too and found no clean way to do it. I finally used EnvInjectPlugin in some ugly way to do this.
def buildEnv = build.getEnvVars();
varsToAdd = [:]
// add here your custom properties
buildEnv.putAll(varsToAdd)
import org.jenkinsci.plugins.envinject.EnvInjectPluginAction
def envInjectAction = build.getAction(EnvInjectPluginAction.class);
envInjectAction.overrideAll(buildEnv)
... the EnvInject plugin did the magic
I first tried to implement EnvironmentContributingAction
and add it as build.addAction(...) but did not work for me for unknown reason.
Be sure to set 'Flow run needs a workspace' in the called job.
#NoelYap: I can't comment on Hristo's answer, but it's the correct answer. The missing detail is that importing EnvInject only works if your job has the 'Flow run needs a workspace' option selected.
A simpler version based on Michael's solution
import hudson.model.*
def setEnvVariable(final String key, final String value) {
Thread.currentThread().getCurrentExecutable()
.addAction(new ParametersAction(new StringParameterValue(key, value))
);
}
setEnvVariable("THIS_ENV_VAR", "Hello World")
The variable is then available in the post-build actions.
An old question I know, but this is how i get around it. The beautiful part is this code works well in Jenkins both within the system evaluated groovy and within the Build FLow Job DSL.
Just drop the import statements when running it from the System Groovy job/console as they are already available.
As a bonus this class also helps get the environment variable regardless of the Groovy context. Still in the build flow you should favor build.environment.get it is more natural.
Note: 'Flow run needs a workspace' should be checked.
//Import the required bindings for a Build Flow DSL
import hudson.model.AbstractBuild
import hudson.model.EnvironmentContributingAction
import hudson.EnvVars
//Drop the above if running with a System Groovy Console/Job
class Job {
static def getVariable(String key) {
def config = new HashMap()
def thr = Thread.currentThread()
def build = thr?.getCurrentExecutable()
def envVarsMap = build.parent.builds[0].properties.get("envVars")
config.putAll(envVarsMap)
return config.get(key)
}
static def setVariable(String key, String value) {
def build = Thread.currentThread().getCurrentExecutable()
def action = new VariableInjectionAction(key, value)
build.addAction(action)
build.getEnvironment()
}
static def setVariable(String key, Integer value) {
setVariable(key, value.toString())
}
}
class VariableInjectionAction implements EnvironmentContributingAction {
private String key
private String value
public VariableInjectionAction(String key, String value) {
this.key = key
this.value = value
}
public void buildEnvVars(AbstractBuild build, EnvVars envVars) {
if (envVars != null && key != null && value != null) {
envVars.put(key, value);
}
}
public String getDisplayName() { return "VariableInjectionAction"; }
public String getIconFileName() { return null; }
public String getUrlName() { return null; }
}
Job.setVariable("THIS_ENV_VAR", "Hello World")
Will set the environment variable THIS_ENV_VAR to "Hello World"