I use Jenkins to execute tests whenever a PR is created or updated.
The tests take about 20 minutes, and quite often a PR is created, but 4-5 minutes later is updated by another commit. In that case, I want to cancel the previous test run as it is no longer valuable.
I tried implementing it using a groovy script
import hudson.model.Result
import jenkins.model.CauseOfInterruption
import hudson.model.ParametersAction
import hudson.model.Job
import jenkins.model.Jenkins
//iterate through current project runs
build.getProject()._getRuns().iterator().each{ run ->
def exec = run.getExecutor()
//if the run is not a current build and it has executor (running) then stop it
if(run != build && exec != null) {
def other_run_params = run.actions.find{ it instanceof ParametersAction }?.parameters
def current_build_params = build.actions.find{ it instanceof ParametersAction }?.parameters
def should_cancel = true
other_run_params.each { other_run_param ->
current_build_params.each { current_build_param ->
if (other_run_param.name == current_build_param.name && other_run_param.dump() != current_build_param.dump()) {
should_cancel = false
}
}
}
// Cancelling all subprojects. If I skip this loop and just cancel 'exec', the subprojects continue to run
if (should_cancel) {
println("Attempting to cancel previous build!")
// prepare the cause of interruption
def cause = { "interrupted by build #${build.getId()}" as String } as CauseOfInterruption
// Cancel all child objects
def buildingJobs = Jenkins.instance.getAllItems(Job.class).findAll { it.isBuilding() }
buildingJobs.each { job ->
allRuns = job._getRuns().iterator().each { child_run ->
upstream = child_run.getCause(hudson.model.Cause.UpstreamCause.class)?.upstreamRun
while (upstream != null) {
if (upstream == run) {
def child_exec = child_run.getExecutor()
if (child_exec != null) {
println("Cancelling child job!")
child_exec.interrupt(Result.ABORTED, cause)
}
}
upstream = upstream.getCause(hudson.model.Cause.UpstreamCause.class)?.upstreamRun
}
}
}
// Cancel the root
exec.interrupt(Result.ABORTED, cause)
}
}
}
But currently, I have in Jenkins about 30 jobs, each one with a history of about 5k, so this execution takes about 10 minutes to run. Can I do it more efficiently?
EDIT: If I just skip the second loop and just abort the second run, it does not stop all subprojects.