Jenkins declarative pipeline with different triggers per branch - jenkins

I am looking to implement different cron triggers per branch in a declarative pipeline jenkins job. At the minute, I am only triggering hourly builds on our dev branch:
String cron_string = BRANCH_NAME == "dev" ? "#hourly" : ""
pipeline {
triggers {
cron(cron_string)
}
//stages, options and more code here...
}
My aim would be to have two separate cron strings that would trigger builds at different times in separate branches (eg: hourly builds in dev, every three hours builds in master), however the execution would be identical. My question is, can I do something like the code block below or should I take a different approach?
String cron_string_1 = BRANCH_NAME == "dev" ? "0 8/20 ? * MON-FRY" : ""
String cron_string_2 = BRANCH_NAME == "master" ? "0 8/20/3 ? * MON-FRY" : ""
pipeline {
triggers {
cron(cron_string)
}
//stages, options and more code here...
}

This worked for me (using scripted pipelines):
if (BRANCH_NAME == "dev") {
properties(
[
pipelineTriggers([cron('0 8,13,17 * * *')])
]
)
}

Related

Jenkins pipeline with a conditional trigger

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' }

conditional branch in groovy code based on state

I have a webhook in gitlab, that triggers a Jenkins job which run a groovy script.
Now I want that the branch to checkout will be conditional:
If the state is merged to take the target_branch and if not that the source_branch
I couldn't find exactly how to do it in the groovy code. The triggers are different for one is note and for the other is merge request
There are gitlab variables that are passed: https://github.com/jenkinsci/gitlab-plugin#defined-variables
so the following solved my issue:
// Distniguish between 2 types of webhook triggers
if(env.gitlabMergeRequestState != null) {
merge_status = "merged"
if (merge_status.equalsIgnoreCase(env.gitlabMergeRequestState)) {
echo "Merged Trigger, using: ${env.gitlabTargetBranch} branch"
branch = env.gitlabTargetBranch
} else {
echo "Note Trigger, using: ${env.gitlabSourceBranch} branch"
branch = env.gitlabSourceBranch
}
}

How i can trigger build from jenkinsfile using cron syntax?

im using multibranch jenkins style each branch has its own jenkinsfile, i have added triggers in jenkinsfile but it didnt trigger anything on the specified time (8pm), im not sure if im missing something
agent {
node {
label 'master'
}
}
triggers {
cron(env.APP_NAME == 'DICTIONARY' ? '00 20 * * *' : '')
}
stages {
stage('SCM Checkout') {
steps {
git(branch: 'test', url: 'https://gitlab.testral.ba/amramework.git', poll: true, credentialsId: 'GitlabCred')
}
}
For the change in cron to catch, you need to run your Jenkinsfile once manually in the correct branch. After that, check in "View Configuration" that your cron succeeded ("Build periodically" should be checked and contain the schedule).
If it has not, it could be that, at the time when triggers are evaluated, your env.APP_NAME differs from 'DICTIONARY'.
To debug the env, you may add the following:
println "env.APP_NAME is ${env.APP_NAME}" // will run before pipeline
pipeline {
agent {
node {
As a side-note, it's recommended using H instead of minutes, so not all hourly builds fall exactly on the hour:
triggers {
cron(env.APP_NAME == 'DICTIONARY' ? 'H 20 * * *' : '')
}

Separate triggers for different branches in Jenkinsfile

I'm working with a Multi-Branch Jenkins build, of which I want the develop branch to build periodically every two weeks and leave the master branch manual.
Our pipelines are pipelines as code, so I cannot set the config for the desired branches.
I'd like to build our develop branch once every 2 weeks on a sunday, so far I have found some different things.
Right now I've come to this schedule:
triggers {
cron('00 12 /2 7')
}
But I do not know how to make it branch specific.
I'm trying this right now to see if it works, should trigger a develop build every 5 mins or break.
triggers {
when (env.BRANCH_NAME == 'develop') {
cron('H/5 * * * *')
}
}
when is not allowed in the triggers block.
I have found a 'solution' on the Jenkins jira which is this:
String cron_string = BRANCH_NAME == "develop" ? "00 12 /2 7" : ""
pipeline {
agent none
triggers { cron(cron_string) }
stages {
// do something
}
}
I have found a 'solution' on the Jenkins jira which is this:
String cron_string = BRANCH_NAME == "develop" ? "00 12 /2 7" : ""
pipeline {
agent none
triggers { cron(cron_string) }
stages {
// do something
}
}

How to disable automatic build from scm change in Jenkinsfile

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
}

Resources