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!"
}
}
}
I have hundreds of jenkins jobs(multibranch pipeline) with trigger enabled to periodically scan respective repositories every 5 mins. I'm trying to disable "scan multibranch pipeline triggers" on all the existing jobs in a particular folder(development/microservice). I'm running below script from Jenkins script console and getting exception at removeTrigger
import hudson.model.*
import hudson.triggers.*
import jenkins.model.*
import com.cloudbees.hudson.plugins.folder.Folder
for (it in Jenkins.instance.getAllItems(jenkins.branch.MultiBranchProject.class)) {
if(it.fullName.length() > 25 && it.fullName.substring(0,25) ==
'development/microservice/' && it.fullName.split("/").length == 3) {
println it.fullName
it.triggers.each { descriptor, trigger ->
it.removeTrigger(descriptor)
it.save()
}
}
}
Can someone please help me how to disable triggers on multibranch pipeline jobs programmatically.
It seems one just needs to iterate over the triggers, and pass the right part to removeTrigger(); that means passing the trigger rather than the descriptor:
for (p in Jenkins.instance.getAllItems(jenkins.branch.MultiBranchProject.class)) {
p.triggers.each { descriptor, trigger ->
//println descriptor
//println trigger
p.removeTrigger(trigger)
}
}
Output sample for a single trigger, when println statements are not commented out:
com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger$DescriptorImpl#30f35b28
com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger#3745f994
Many thanks for your question, your almost working code helped me a lot. ;)
I am trying to create a cron job which run some smoke tests every 10 minutes, my seedjob looks like this :
multiBranchJobs.each { currentJob ->
multibranchPipelineJob(currentJob.name) {
branchSources {
git {
remote(currentJob.projectGitUrl)
credentialsId(currentJob.credentials)
includes(currentJob.includes)
}
}
orphanedItemStrategy {
discardOldItems {
numToKeep(20)
}
}
triggers {
cron "H/5 * * * *"
periodic 60
}
}
}
the problem with the current approach is that it will get executes only if it detects changes in the SCM, which is not the case for the smoke tests. I need to run it every 5 minutes regardless of commits in source control. Any clue ?
I'm not entirely sure how to solve your problem, but I think the cron trigger you have is not doing what you think it is. I THINK this will set this trigger on the multibranch indexing job itself. In the UI that is not even an option. Apparently it isn't throwing an error, but I have to wonder if it is actually setting the trigger.
The jobs that get created from the multibranch job must have a Jenkinsfile, right? You can set the triggers in those Jenkinsfiles.
I haven't built jobs using code, so take that into consideration when you review my answer. But it SEEMS to me that you are setting the trigger in the wrong place.
I have a Jenkinsfile that I've set up with a cron for a pipelineTriggers parameter. I can't seem to figure out how to disable the job from building from a merge to the master branch of the repo. Is there a way in the Jenkinsfile to disable the automatic build from an scm change?
If you're using a Multibranch Pipeline, you should be able to do this on the job's Configure page:
Scroll down to "Branch Sources"
Under "Property strategy", choose "Named branches get different properties"
Click "Add exception", enter "master" as the branch name
Click "Add property", choose "Suppress automatic SCM triggering"
Save
That would prevent changes to the master branch from triggering a build of the corresponding job.
For declarative pipelines, use the when directive with a triggeredBy condition, e.g.
when { triggeredBy 'TimerTrigger' }
With the multibranch pipeline, I could not figure out a way to prevent the next build being triggered. As a workaround, I added the following code to my Jenkinsfile (using scripted syntax), to abort the following build if the only changes contain "[ci-skip]" in the commit message:
def abortBuildIfTriggeredBySkippableCommit() {
def changeSetCount = 0;
def ciSkipCount = 0;
if (currentBuild.changeSets != null) {
for (changeSetList in currentBuild.changeSets) {
for (changeSet in changeSetList) {
changeSetCount++;
if (changeSet.msg.contains('[ci-skip]')) {
ciSkipCount++;
}
}
}
}
if (changeSetCount > 0 && changeSetCount == ciSkipCount) {
currentBuild.result = 'NOT_BUILT'
error("Stopping to prevent auto trigger. All commits contained [ci-skip]")
}
}
Note that this code assumes you are using the git plugin, and that the objects in currentBuild.changeSets will be GitChangeSetList.
In a jenkins job you can navigate to advanced source code management
Select behavior Dont trigger build on commit notification
This disables the Started by an SCM change
For people still looking for a solution, go to configuration for the multi branch pipeline, under Property Strategy, choose "Suppress Automatic SCM Triggering".
Note: This is available on cloudbees version of Jenkins. I am not sure, if it matters.
https://support.cloudbees.com/hc/en-us/articles/360026953651-Preventing-builds-from-getting-triggered-when-creating-a-new-multibranch-Pipeline-or-Organization-Folder?page=29
This is what I came up with. I was hoping for something less messy, but this does seem to work:
I have this as the build's properties:
properties([
pipelineTriggers([cron('H H 7 * *')])
])
I then have this function that defines the source of the build:
// check if the job was started by a timer
#NonCPS
def jobStartedByWhat() {
def startedByWhat = ''
try {
def buildCauses = currentBuild.rawBuild.getCauses()
for ( buildCause in buildCauses ) {
if (buildCause != null) {
def causeDescription = buildCause.getShortDescription()
echo "shortDescription: ${causeDescription}"
if (causeDescription.contains("Started by timer")) {
startedByWhat = 'timer'
}
if (causeDescription.contains("Started by user")) {
startedByWhat = 'user'
}
}
}
} catch(theError) {
echo "Error getting build cause: ${theError}"
}
return startedByWhat
}
def startedByWhat = jobStartedByWhat()
I can then evaluate the function at runtime so that if a build gets triggered because of a merge to master, it will not actually run:
node {
try {
checkout scm
if (env.BRANCH_NAME == 'master') {
if (startedByWhat == 'timer' || startedByWhat == 'user') {
..... RUN THE BUILD .....
} else {
.... EXIT WITHOUT RUNNING THE BUILD ....
I stumbled upon this as well. IMO an acceptable solution would be a filter for commit messages when checking out source code - this feature exists for regular Jobs but is missing for multibranch pipelines, see https://issues.jenkins-ci.org/browse/JENKINS-48296.
For those not using the git plugin, this method is a workaround for scripted pipelines (inspired by scarswell's answer):
def abortBuildIfTriggeredBySkippableCommit() {
lastCommitMessage = sh(
script: "${gitBinary} --no-pager log -1 --pretty=%B",
returnStdout: true
)
if (lastCommitMessage != null &&
lastCommitMessage.toString().contains('[maven-release-plugin]')) {
currentBuild.result = 'ABORTED'
error("Stopping build, it was triggered by the maven release plugin")
}
}
For declarative pipelines, there is a much more simple answer now. From the docs:
overrideIndexTriggers
Allows overriding default treatment of branch indexing triggers. If branch indexing triggers are disabled at the multibranch or organization label, options { overrideIndexTriggers(true) } will enable them for this job only. Otherwise, options { overrideIndexTriggers(false) } will disable branch indexing triggers for this job only.
It's a little backwards conceptually, but assuming your jobs are triggering off github webhooks by default, you set overrideIndexTriggers(false) to disable the automatic triggering.
If you are using Pipeline script from SCM then comment out the triggers section(either SCMPoll/BuildPeriodically option ) in Jenkins file as shown below.
//triggers {cron ('H/15 * * * *')}
//pipelineTriggers([pollSCM('H/15 * * * *')])
If you are using Pipeline script then disable the PollSCM/Build periodically(whichever is used) option.
One could disable the scm build trigger by disabling the webhook notification from git.
if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause') || currentBuild.getBuildCauses().toString().contains('Branch event')) {
print "INFO: Build skipped due to trigger being Branch Indexing"
currentBuild.result = 'ABORTED' // optional, gives a better hint to the user that it's been skipped, rather than the default which shows it's successful
return
}
timestamps{
node
{
stage('Getting Build Parameters')
{
print('build job')
}
}
}
if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause') || currentBuild.getBuildCauses().toString().contains('Branch event')) {
print "INFO: Build skipped due to trigger being Branch Indexing"
currentBuild.result = 'ABORTED' // optional, gives a better hint to the user that it's been skipped, rather than the default which shows it's successful
return
}
if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause') || currentBuild.getBuildCauses().toString().contains('Branch event')) {
print "INFO: Build skipped due to trigger being Branch Indexing"
currentBuild.result = 'ABORTED' // optional, gives a better hint to the user that it's been skipped, rather than the default which shows it's successful
return
}
I have a project, named Demo, which doesn't do anything in particular.
I have a DSL script, like the following:
def gitUrl = 'GIT_URL'
job('unit-tests') {
scm {
git(gitUrl)
}
triggers {
buildResult('H/* * * * *') {
combinedJobs()
triggerInfo('Demo', BuildResult.SUCCESS, BuildResult.UNSTABLE)
}
}
}
Now what I'm wanting to do, is that when the Demo project runs successfully (it checks out a PHP application from Github), I want the unit-tests job to run.
Currently, when the Demo project is built, the unit-tests job never gets run.
I'm guessing my DSL script is incorrect, but I'm not sure why
I can reproduce your problem. The check box is not set when running the seed job for the first time. But it's set after running the seed job a second time. Must be a problem in the BuildResultTrigger plugin. Please file a bug report in the Jenkins JIRA: https://issues.jenkins-ci.org/projects/JENKINS
But you do not necessarily need to use the BuildResultTrigger plugin. You can use the built-in "Build after other projects are built" option, see https://jenkinsci.github.io/job-dsl-plugin/#path/job-triggers-upstream.
job('unit-tests') {
triggers {
upstream('Demo', 'UNSTABLE')
}
}
Use upstream which adds the "Build after other projects are built" trigger. see https://jenkinsci.github.io/job-dsl-plugin/#path/job-triggers-upstream
def gitUrl = 'GIT_URL'
job('unit-tests') {
scm {
git(gitUrl)
}
triggers {
buildResult('H/* * * * *') {
upstream('Demo', 'UNSTABLE')
}
}
}