I trigger a build called testAUT with parameter FRACTURE_NO = 15. I trigger the same build with the same parameter.
I want when that happens that the earlier build gets killed. How can I do that using Jenkins? I want to be able to end a build with the same parameter as the current build.
If you're OK with using the Groovy Plugin and Jenkins Rest Api, here are the steps needed to do what you want.
Install the Groovy Plugin.
Go to the job's configure page.
Add the 'fracture_no' build parameter with default value of 125.
Enable 'Execute concurrent builds if necessary' in the General section
Add a 'Execute Groovy script' build step as the first step in the job
Add the following code to the groovy step
def parameterName = "fracture_no";
def jenkinsUrl = System.getenv('JENKINS_URL');
def buildNumber = System.getenv('BUILD_NUMBER').toInteger();
def jobUrl = jenkinsUrl + "job/" + System.getenv('JOB_NAME');
def buildNumberUrl = jobUrl + "/" + buildNumber;
def myParameter = System.getenv(parameterName);
def projectXml = new XmlSlurper().parseText(new URL(jobUrl + "/api/xml").getText());
projectXml.build.each {
def previousBuildNumber = it.number.text().toInteger();
if(previousBuildNumber < buildNumber)
{
def previousBuildNumberUrl = jobUrl + "/" + previousBuildNumber;
def jobXml = new XmlSlurper().parseText(new URL(previousBuildNumberUrl + "/api/xml").getText());
if(jobXml.building.text() == "true")
{
jobXml.action.parameter.each {
if(it.name.text() == parameterName) {
if(it.value.text() == myParameter) {
def url = new URL(previousBuildNumberUrl + "/stop");
def connection = url.openConnection();
connection.setRequestMethod("POST");
connection.connect();
connection.content.text;
println "Stopping " + previousBuildNumber;
}
}
}
}
}
}
Add another build step that takes a long time. If you just want to test, then add the following Windows Batch Command step that sleeps for 100 seconds.
ping 127.0.0.1 -n 100 > nul
Kick off the job twice using the default parameter value of 125 (or as many times as you want).
Everything but the latest build should be stopped.
Related
I have a Jenkins instance with multiple teams using it. It gets cluttered frequently and people don't delete their test jobs after testing. Is there a way to delete unused jobs (not run in the last 6 months) including their workspace?
You can use the following Groovy script for this. Comment out the delete part and test it before using just to make sure it's what you need :)
def deleteBefore = "2022/07/01"
Jenkins.instance.getAllItems(Job.class).each { jobitem ->
def jobName = jobitem.getFullName()
def deleteBeforeTime = new Date(deleteBefore).getTime()
def build = jobitem.getLastBuild()
if(build == null || build.getTimeInMillis() <= deleteBeforeTime){ // If no builds, build is null
println build == null ? "Job " + jobName + " has never run, deleting the Job" : "Job " + jobName + " last ran on (" + build.getTime() + ") hence deleting"
jobitem.delete()
}
}
I'm attempting to set up a script to kill/abort all Jenkins jobs with a certain name in them. I've had trouble finding documentation on Jenkins classes and what's contained in them.
I know there are plugins available, but I've been directed not to use them. Otherwise, I've referred to a few semi-related questions here (How to stop an unstoppable zombie job on Jenkins without restarting the server?), (Cancel queued builds and aborting executing builds using Groovy for Jenkins), and I attempted to rework some of the code from those, however it doesn't quite result in killed jobs:
import hudson.model.*
def jobList = Jenkins.instance.queue
jobList.items.findAll { it.task.name.contains('searchTerm') }.each { jobList.kill(it.task) }
I've also tried the following:
def jobname = ""
def buildnum = 85
def job = Jenkins.instance.getItemByFullName(jobname)
for (build in job.builds) {
if (buildnum == build.getNumber().toInteger()){
if (build.isBuilding()){
build.doStop();
build.doKill();
}
}
}
Instead of hard-killing jobs, the first script does nothing, while the second throws a NullPointerException:
java.lang.NullPointerException: Cannot get property 'builds' on null object
I managed to get it working; my second example wasn't working because I brainfarted and the job I was testing it on had no builds. :(
def searchTerm = ""
def matchedJobs = Jenkins.instance.items.findAll { job ->
job.name.contains(searchTerm)
def desiredState = "stop"
if (desiredState.equals("stop")) {
println "Stopping all current builds ${job.name}"
for (build in job.builds) {
if (build.isBuilding()){
build.doStop();
println build.name + " successfully stopped!"
}
}
}
In a Jenkins job, I want to trigger another Jenkins job from a Groovy script :
other_job.scheduleBuild();
But other_job is not launched on the same node than the parent job. How can I modify my script to launch other_job on the same node than the parent job ?
I used to do that with the "Trigger/call builds on other project" and "NodeLabel Parameter" plugins but I would like now to do that inside a script.
Firstly, check Restrict where this project can be run option in 'other_job' configuration - you must specify the same node name there.
Then, this should work:
import hudson.model.*
def job = Hudson.instance.getJob('other_job')
job.scheduleBuild();
If you don't want to use this option in your 'other_job', then you can use NodeLabel Parameter Plugin (which you already used) and pass the NodeLabel parameter to downstream job.
In this case, see example from Groovy plugin page how to start another job with parameters (you need to use NodeParameterValue instead of StringParameterValue):
def job = Hudson.instance.getJob('MyJobName')
def anotherBuild
try {
def params = [
new StringParameterValue('FOO', foo),
]
def future = job.scheduleBuild2(0, new Cause.UpstreamCause(build), new ParametersAction(params))
println "Waiting for the completion of " + HyperlinkNote.encodeTo('/' + job.url, job.fullDisplayName)
anotherBuild = future.get()
} catch (CancellationException x) {
throw new AbortException("${job.fullDisplayName} aborted.")
}
println HyperlinkNote.encodeTo('/' + anotherBuild.url, anotherBuild.fullDisplayName) + " completed. Result was " + anotherBuild.result
If it's not working, probably the issue is with node restrictions (e.g., there is only one executor for the node).
NOTE: I prefer to use Jenkins pipelines for job configurations. It allows you to store your build configs in Jenkinsfiles which can be loaded from repository (e.g., from GitLab). See example of triggering job with NodeParameterValue.
Based on the answer of biruk1230, here is a full solution :
import hudson.model.*;
import jenkins.model.Jenkins
import java.util.concurrent.*
import hudson.AbortException
import org.jvnet.jenkins.plugins.nodelabelparameter.*
def currentBuild = Thread.currentThread().executable
current_node = currentBuild.getBuiltOn().getNodeName()
def j = Hudson.instance.getJob('MyJobName')
try {
def params = [
new NodeParameterValue('node', current_node, current_node),
]
def future = j.scheduleBuild2(0, new Cause.UpstreamCause(build), new ParametersAction(params))
println "Waiting for the completion of " + j.getName()
anotherBuild = future.get()
} catch (CancellationException x) {
throw new AbortException("aborted.")
}
I have a jenkins job A to select any choices from parameters while building job , the same parameters values that i have selected on job A should be picked by job B automatically every time when i try to build job B . Where job B should not be downstream job of job A.
My workaround: I tried to copy the parameters that i select on job A to a file .
On job B ,i was unable to find the option in jenkins, to select the variable value to be picked up from a file in parameters section.
Any suggestions and different approaches will be greatly appreciated.
You can do this using a System Groovy script. You find the most recent job A build, and copy the parameter values into Job B.
import hudson.model.*
def hif = Hudson.instance
//Get build variables for this build
def buildMap = build.getBuildVariables()
//get most recent build of project A
def a = hif.getItems(hudson.model.Project).find {it.displayName.toUpperCase()=='PROJECT A'}.getBuilds().first()
//Add parameter to the build variables for this build
buildMap['MYPARAM']=a.buildVariableResolver.resolve('MYPARAM')
println(buildMap['MYPARAM'])
//Assign the new parameters back to job B
setBuildParameters(buildMap)
def setBuildParameters(map) {
def npl = new ArrayList<StringParameterValue>()
for (e in map) {
npl.add(new StringParameterValue(e.key.toString(), e.value.toString()))
}
def newPa = null
def oldPa = build.getAction(ParametersAction.class)
if (oldPa != null) {
build.actions.remove(oldPa)
newPa = oldPa.createUpdated(npl)
} else {
newPa = new ParametersAction(npl)
}
build.actions.add(newPa)
}
I try to launch a job from a parametrized trigger and I would compute the name from a given variable.
Is it possible to set in field :
Build Triggers Projects to build
a value like this
${RELEASE}-MAIN-${PROJECT}-LOAD_START
?
Unfortunately, this isn't possible with the Build Triggers. I looked for a solution for this "higher order build job" that would allow you to create a dynamic build name with a one of the parameterized build plugins, but I couldn't find one.
However, using the Groovy Postbuild Plugin, you can do a lot of powerful things. Below is a script that can be modified to do what you want. In particular, notice that it gets environmental variables using build.buildVariables.get("MY_ENV_VAR"). The environmental variable TARGET_BUILD_JOB specifies the name of the build job to build. In your case, you would want to build TARGET_BUILD_JOB using these two environmental variables:
build.buildVariables.get("RELEASE")
build.buildVariables.get("PROJECT")
The script is commented so that if you're not familiar with Groovy, which is based off Java, it should hopefully make sense!
import hudson.model.*
import hudson.model.queue.*
import hudson.model.labels.*
import org.jvnet.jenkins.plugins.nodelabelparameter.*
def failBuild(msg)
{
throw new RuntimeException("[GROOVY] User message, exiting with error: " + msg)
}
// Get the current build job
def thr = Thread.currentThread()
def build = thr?.executable
// Get the parameters for the current build job
// For ?:, see "Elvis Operator" (http://groovy.codehaus.org/Operators#Operators-ElvisOperator)
def currentParameters = build.getAction(ParametersAction.class)?.getParameters() ?:
failBuild("There are no parameters to pass down.")
def nodeName = build.getBuiltOnStr()
def newParameters = new ArrayList(currentParameters); newParameters << new NodeParameterValue("param_NODE",
"Target node -- the node of the previous job", nodeName)
// Retrieve information about the target build job
def targetJobName = build.buildVariables.get("TARGET_BUILD_JOB")
def targetJobObject = Hudson.instance.getItem(targetJobName) ?:
failBuild("Could not find a build job with the name $targetJobName. (Are you sure the spelling is correct?)")
println("$targetJobObject, $targetJobName")
def buildNumber = targetJobObject.getNextBuildNumber()
// Add information about downstream job to log
def jobUrl = targetJobObject.getAbsoluteUrl()
println("Starting downstream job $targetJobName ($jobUrl)" + "\n")
println("======= DOWNSTREAM PARAMETERS =======")
println("$newParameters")
// Start the downstream build job if this build job was successful
boolean targetBuildQueued = targetJobObject.scheduleBuild(5,
new Cause.UpstreamCause(build),
new ParametersAction(newParameters)
);
if (targetBuildQueued)
{
println("Build started successfully")
println("Console (wait a few seconds before clicking): $jobUrl/$buildNumber/console")
}
else
failBuild("Could not start target build job")