I have a Jenkins pipeline which is scheduled to trigger every 4 hours. However, my requirements is that once the build fails, I want the builds to happen more frequently and keep sending constant reminders that the build is broken. In short, the build schedule must depend on the status of the previous build.
Is that possible in Jenkins?
Thanks,
In Scripted Pipeline, you can do something like this :
def triggers = []
if(currentBuild.getPreviousBuild().result != 'SUCCESS') {
triggers << cron('0 */1 * * *') // every hour
} else {
triggers << cron('0 */4 * * *') // every 4 hours
}
properties ([
pipelineTriggers(triggers)
])
node {
...
}
I can't think of a direct way but you can have a workaround. You can have a replica of the same job(let's call it job 'B') and trigger it when the build of the first job fails(let's call it job 'A'). Now if B fails again then you can retrigger it(B) (adding some wait time) and send a notification after it fails, keep doing it until it passes. This will be done in a much easier way if you are using the scripted Jenkins pipeline. Hope this answer helps you in some way.
Related
My Jenkins pipeline is as follow:
pipeline {
triggers {
cron('H */5 * * *')
}
stages {
stage('Foo') {
...
}
}
}
The repository is part of a Github Organization on Jenkins - every branch or PR pushed results in a Jenkins job being created for that branch or PR.
I would like the trigger to only be run on the "main" branch because we don't need all branches and PRs to be run on a cron schedule; we only need them to be run on new commits which they already do.
Is it possible?
yes - it's possible. To schedule cron trigger only for a specific branch you can do it like this in your Jenkinsfile:
String cron_string = (scm.branches[0].name == "main") ? 'H */5 * * *' : ''
pipeline {
triggers {
cron(cron_string)
}
// whatever other code, options, stages etc. is in your pipeline ...
}
What it does:
Initialize a variable based on a branch name. For main branch it sets requested cron configuration, otherwise there's no scheduling (empty string is set).
Use this variable within pipeline
Further comments:
it's possible to use it also with parameterizedCron (in a case you'd want / need to).
you can use also some other variables for getting branch name, e.g: env.BRANCH_NAME instead of scm.branches[0].name. Whatever fits your needs...
This topic and solution is discussed also in Jenkins community: https://issues.jenkins.io/browse/JENKINS-42643?focusedCommentId=293221#comment-293221
EDIT: actually a similar question that leads to the same configuration - here on Stack: "Build Periodically" with a Multi-branch Pipeline in Jenkins
You can simply add a when condition to your pipeline.
when { branch 'main' }
Below is a simplified case.
I have one node named comp01. And I have a Jenkins job named Compatibility.
Compatibility is scheduled as follows:
0 12 * * 1 %IntegrationNode=Software_1
0 17 * * 1 %IntegrationNode=Software_2
0 22 * * 1 %IntegrationNode=Software_3
0 2 * * 2 %IntegrationNode=Software_4
0 7 * * 2 %IntegrationNode=Software_5
The jobs start as scheduled. But sometimes, because of some verification failure, the previous job takes more than expected time. So, the next job starts before the completion of the previous job.
Is there a way available in Jenkins, in which the next scheduled job stays in a queue until previous job is complete? Or can we schedule based on previous job status?
We have tried limiting executors for this job, but when more than a couple of jobs are queued, then the expected behavior is not observed.
We have also tried by creating resource-groups and adding multiple nodes to it, but still, expected behavior is not observed when multiple jobs are in queue.
EDIT-1:
We can't use options { disableConcurrentBuilds() } since we start the job concurrently on different nodes. Here we are struggling to ensure that when a job is started on a node, then the other scheduled jobs for the same node should wait till the current job completes.
Have you tried setting the below option?
options { disableConcurrentBuilds() }
Update
AFAIK there is no OOB solution for your problem. But you can definitely implement something. Without seeing your actual Pipelines I can't give a concrete answer. But here ae some options.
Option 01
Use Lockable Resources and create a resource per Jenkins IntegrationNode and acquire it when running the Job, the next build will wait until the lock is released.
lock(resource: 'IntegrationNode1', skipIfLocked: false) {
echo "Run your logic"
}
Option 02
You can implement a waiting logic to check the status of the previous Build. Here is an sample Pipeline and possible Groovy code you can leverage.
pipeline {
agent any
stages {
stage('Build') {
steps {
script {
echo "Waiting"
def jobName = "JobA"
def buildNum = "92"
waitUntil { !isPending(jobName, buildNum) }
echo "Actual Run"
}
}
}
}
}
def isPending(def JobName, def buildNumber) {
def buildA = Jenkins.instance.getItemByFullName(JobName).getBuild(buildNumber)
return buildA.isInProgress()
}
I am using the below Configure block for the scan by webhook functionality in Jenkins Job DSL.
Environment: Jenkins and Bitbucket
traits << 'com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger' {
token("TEST_HOOK")
}
The above block is not working.
But the below periodic trigger syntax is working with out any issues.
it / 'triggers' << 'com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger'{
spec '* * * * *'
interval "60000"
}
As we want to use the scan by webhook functionality. Kindly correct my scan by webhook syntax
The Job DSL Pipeline provides some declarative Parts for triggering a job either on changes or scheduled.
Another case can be the Multibranch Pipeline, where any branch is configured by the included Jenkinsfile. In order to create Jobs for a new branch, the Task "Scan Multibranch Pipeline Now" has to be executed either manually or scheduled. This can be programmatically(schedule) done via the configure block inside the Multibranch Pipeline Job:
multibranchPipelineJob("JobName") {
...
configure { node ->
def periodicFolderTrigger = node / triggers / 'com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger' {
spec('H H * * *')
//4 hours (60000(Milliseconds)*60(Minutes)*4(hours)
interval(60000*60*4)
}
}
}
The webhook Solution, is more elegant, but you need the Jenkins plugin https://plugins.jenkins.io/multibranch-scan-webhook-trigger/ to be installed. Programmatically you can activate this via the following way:
multibranchPipelineJob("JobName") {
...
configure { node ->
def webhookTrigger = node / triggers / 'com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger' {
spec('')
token("TESTTOKEN")
}
}
}
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.
We have a Jenkins server which is running somewhere between 20 and 30 jobs.
Since the build process is reasonably complex we're broken the actual build down into 1 sub-builds, some of which can run concurrently, others have to follow previous build steps. As a result we've grouped each of the build steps into 3 groups, which block while the builds are in pogress.
For example:
Main Build : GroupA : Builds A1, A2 & A3
: GroupB : Builds B1, B2 & B3
: GroupC : Builds C1, C2, C3, C4, C5 & C6
: GroupD : HW_Tests T1, T2, T3, T4 & T5
Builds B1, B2 & B3 rely on the output from A1, A2, A3 etc
Since there are builds and tests running pretty much 24/7, I am finding it difficult to schedule a restart of the Jenkins Master. Choosing "Prepare for shutdown" will mean new jobs are queued, but it will invariably block a running job since, to use my example above, if GroupB is active, builds C1, C2, etc will be queued also, and the Main Build will be blocked.
As a work around, I would like to disable the SCM polling on the server until all running jobs have finished. This will prevent new jobs from triggering but also allow the running jobs to finish. I can then restart Jenkins and , re-enable SCM polling, allowing normal service to resume.
The SCM we are using is Perforce.
I have not been able to find anywhere which suggests the above is possible, however, I am sure it must be feasible in System Groovy ... just not sure how. Does anyone here have any ideas please?
Many Thanks
You could disable only those jobs which have an SCM polling trigger. This groovy script will do that:
Hudson.instance.items.each { job ->
if ( job.getTrigger( hudson.triggers.SCMTrigger ) != null ) {
println "will disable job ${job.name}"
job.disable()
}
}
Re-enabling the jobs will be left as an exercise : )
Jenkins 2.204.1 + version of using the groovy script console to disable all jobs with an SCM trigger:
Jenkins.instance.getAllItems(Job.class).each{ job ->
if ( job.getSCMTrigger() != null ) {
println "will disable job ${job.name}"
job.setDisabled(true)
}
}
Try following Groovy script to comment out SCM Polling:
// WARNING: Use on your own risk! Without any warranty!
import hudson.triggers.SCMTrigger
import hudson.triggers.TriggerDescriptor
// from: https://issues.jenkins-ci.org/browse/JENKINS-12785
TriggerDescriptor SCM_TRIGGER_DESCRIPTOR = Hudson.instance.getDescriptorOrDie(SCMTrigger.class)
assert SCM_TRIGGER_DESCRIPTOR != null;
MAGIC = "#MAGIC# "
// comment out SCM Trigger
def disable_scmpoll_trigger(trig){
if ( !trig.spec.startsWith(MAGIC) ){
return new SCMTrigger(MAGIC + trig.spec)
}
return null
}
// enable commented out SCM Trigger
def enable_scmpoll_trigger(trig){
if ( trig.spec.startsWith(MAGIC) ){
return new SCMTrigger(trig.spec.substring(MAGIC.length()))
}
return null
}
Hudson.instance.items.each {
job ->
//println("Checking job ${job.name} of type ${job.getClass().getName()} ...")
// from https://stackoverflow.com/a/39100687
def trig = job.getTrigger( hudson.triggers.SCMTrigger )
if ( trig == null ) return
println("Job ${job.name} has SCMTrigger: '${trig.spec}'")
SCMTrigger newTrig = disable_scmpoll_trigger(trig)
// SCMTrigger newTrig = enable_scmpoll_trigger(trig)
if (newTrig != null ){
newTrig.ignorePostCommitHooks = trig.ignorePostCommitHooks
newTrig.job = job
println("Updating SCMTrigger '${trig.spec}' -> '${newTrig.spec}' for job: ${job.name}")
job.removeTrigger(SCM_TRIGGER_DESCRIPTOR)
job.addTrigger(newTrig)
job.save()
}
}
return ''
To enable SCM polling again just change these two lines
//SCMTrigger newTrig = disable_scmpoll_trigger(trig)
SCMTrigger newTrig = enable_scmpoll_trigger(trig)
Tested on Jenkins ver. 2.121.3
Known limitations:
supports single line "Schedule" (spec property) only
If it is one or 2 builds that are configured to do SCM polling, you can go into the configuration of each build and uncheck the box. It is that simple :)
If you are using jenkins job builder, it should be even easier to change the configuration of several jobs at a time.
If you using slaves or even on master, SCM polling is dependent on JAVA ? remove JAVA from the machine temporarily from the location where it is configured in master jenkins ;) The polling will fail :P This is a stupid hack ;)
I hope that helps !! ?