How to "Scan Repository Now" from a Jenkinsfile - jenkins

I can call another jenkins job using the build command. Is there a way I can tell another job to do a branch scan?
A multibranch pipeline job has a UI button "Scan Repository Now". When you press this button, it will do a checkout of the configured SCM repository and detect all the branches and create subjobs for each branch.
I have a multibranch pipeline job for which I have selected the "Suppress automatic SCM triggering" option because I only want it to run when I call it from another job. Because this option is selected, the multibranch pipeline doesn't automatically detect when new branches are added to the repository. (If I click "Scan Repository Now" in the UI it will detect them.)
Essentially I have a multibranch pipeline job and I want to call it from another multibranch pipeline job that uses the same git repository.
node {
if(env.BRANCH_NAME == "the-branch-I-want" && other_criteria) {
//scanScm "../my-other-multibranch-job" <--- scanScm is a fake command I made up
build "../my-other-multibranch-job/${env.BRANCH_NAME}"
I get an error on that build line, because the target multibranch pipeline job does not yet know that BRANCH_NAME exists. I need a way to trigger an SCM re-scan in the target job from this current job.

Similar to what you figured out yourself, I can contribute my optimization that actually waits until the scan has finished (but is subject to Script Security):
// Helper functions to trigger branch indexing for a certain multibranch project.
// The permissions that this needs are pretty evil.. but there's currently no other choice
//
// Required permissions:
// - method jenkins.model.Jenkins getItemByFullName java.lang.String
// - staticMethod jenkins.model.Jenkins getInstance
//
// See:
// https://github.com/jenkinsci/pipeline-build-step-plugin/blob/3ff14391fe27c8ee9ccea9ba1977131fe3b26dbe/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/BuildTriggerStepExecution.java#L66
// https://stackoverflow.com/questions/41579229/triggering-branch-indexing-on-multibranch-pipelines-jenkins-git
void scanMultiBranchAndWaitForJob(String multibranchProject, String branch) {
String job = "${multibranchProject}/${branch}"
// the `build` step does not support waiting for branch indexing (ComputedFolder job type),
// so we need some black magic to poll and wait until the expected job appears
build job: multibranchProject, wait: false
echo "Waiting for job '${job}' to appear..."
while (Jenkins.instance.getItemByFullName(job) == null || Jenkins.instance.getItemByFullName(job).isDisabled()) {
sleep 3
}
}

Ended up figuring this out shortly after posting the question. Calling build against the base multibranch pipeline job as opposed to a branch causes it to re-scan. The solution to my above snippet would have ended up looking something like...
node {
if(env.BRANCH_NAME == "the-branch-I-want" && other_criteria) {
build job: "../my-other-multibranch-job", wait: false, propagate: false // scan for branches
sleep 2 // scanning takes time
build "../my-other-multibranch-job/${env.BRANCH_NAME}"
The wait: false is important because otherwise you get "ERROR: Waiting for non-job items is not supported". The multibranch "parent" job is closer to a folder than a job, but it's a folder that supports the build command, and it does so by scanning the SCM.
But solving this just led to another problem, which is that with wait: false we have no way of knowing when the SCM Scan finished. If you have a large repository (or you're short on jenkins agents), the branch won't get discovered until after the second build command has already failed due to the branch not existing. You could bump the sleep time even higher, but that doesn't scale.
Fortunately, it turns out manually initiating the SCM scan isn't even needed if you have github webhooks set up for your jenkins. The branch will be discovered more-or-less instantly, so for my purposes this is solved another way. The reason I was running into it is we don't have webhooks set up in our dev jenkins, but once I move this code to prod it will work fine.
If you're trying to use JobDSL to set up multibranches calling multibranches and you don't have webhooks or something equivalent, the better path is probably to abandon multibranch for your second tier of jobs and use JobDSL to create folders and manage the branch jobs yourself.

Related

Jenkins simple pipeline not triggered by github push

I have created a jenkins pipeline job called "pipelinejob" with the below script:
pipeline {
agent any
stages {
stage ('Setup'){
steps{
//echo "${BRANCH_NAME}"
echo "${env.BRANCH_NAME}"
//echo "${GIT_BRANCH}"
echo "${env.GIT_BRANCH}"
}
}
}
}
Under General, I have selected "GitHub project" and inserted my company's github in the form:
https://github.mycompany.com/MYPROJECTNAME/MY_REPOSITORY_NAME/
Under Build Triggers, i have checked "GitHub hook trigger for GITScm polling
I have created a simple job called "simplejob" with same configuration as 1) and 2)
In my company's Github, i have created a webhook like "jenkins_url/jenkins/github-webhook/"
I commit a change in "mybranch" in "MY_REPOSITORY_NAME"
My simple job "simplejob" is triggered and built successfully
My pipeline job "pipelinejob" is not triggered
In Jenkins log i see the below:
Sep 12, 2019 2:42:45 PM INFO org.jenkinsci.plugins.github.webhook.subscriber.DefaultPushGHEventSubscriber$1 run
Poked simplejob
Nothing regarding my "pipelinejob".
Could you please point me to the right directions as to what to check next?
P.S. I have manually executed my "pipelinejob" successfully
I wasted two days of work on this, as none of the previous solutions worked for me. :-(
Eventually I found the solution on another forum:
The problem is that if you use a Jenkinsfile that is stored in GitHub, along with your project sources, then this trigger must be configured in the Jenkinsfile itself, not in the Jenkins or project configuration.
So add a triggers {} block like this to your Jenkinsfile:
pipeline {
agent any
triggers {
githubPush()
}
stages {
...
}
}
Then...
Push your Jenkinsfile into GitHub
Run one build manually, to let Jenkins know about your will to use this trigger.
You'll notice that the "GitHub hook trigger for GITScm polling" checkbox will be checked at last!
Restart Jenkins.
The next push should trigger an automated build at last!
On the left side-pane of your pipeline job, click GitHub Hook log. If it says 'Polling has not run yet', you will need to manually trigger the pipeline job once before Jenkins registers it to poke on receiving hooks.
Henceforth, the job should automatically trigger on GitHub push events.
I found an answer to this question with scripted pipeline file. We need to declare the Github push event trigger in Jenkins file as follows.
properties([pipelineTriggers([githubPush()])])
node {
git url: 'https://github.com/sebin-vincent/Treasure_Hunt.git',branch: 'master'
stage ('Compile Stage') {
echo "compiling"
echo "compilation completed"
}
stage ('Testing Stage') {
echo "testing completed"
echo "testing completed"
}
stage("Deploy") {
echo "deployment completed"
}
}
}
The declaration should be in the first line.
git url: The URL on which pipeline should be triggered.
branch: The branch on which pipeline should be triggered. When you specify the branch as master and make changes to other branches like develop or QA, that won't trigger the pipeline.
Hope this could help someone who comes here for an answer for the same problem with Jenkins scripted pipeline :-(.
The thing is whenever you create a pipeline job for git push which is to be triggered by github-webhook, first you need to build the pipeline job manually for one time. If it builds successfully, then Jenkins registers it to poke on receiving hooks. And from the next git push, your pipeline job will trigger automatically.
Note: Also make sure that the pipeline job built manually for the first time should be built successfully, otherwise Jenkins will not poke it. If it fails to build, you can never trigger the job again.

Notifications on jenkins job failures - with pipeline from scm

We have several jenkins pipeline jobs setup as "pipeline from scm" that checkout a jenkins file from github and runs it. There is sufficient try/catch based error handling inside the jenkinsfile to trap error conditions and notify the right channels.This blog post goes into a quite a bit of depth about how to achieve this.
However, if there is issue fetching the jenkinsfile in the first place, the job fails silently. How does one generate notifications from general job launch failures before the pipeline is even started?
Jenkins SCM pipeline doesn't have any execution provision similar to catch/finally that will be called if Jenkinsfile load is failed, And I don't think there will be any in future.
However there is this global-post-script which runs groovy script after every build of every job on Jenkins. You have to place that script in $JENKINS_HOME/global-post-script/ directory.
Using this you can send notifications or email to admins based on project that failed and/or reason/exceptions of failure.
Sample code that you can put in script
if ("$BUILD_RESULT" != 'SUCCESS') {
def job = hudson.model.Hudson.instance.getItem("$JOB_NAME")
def build = job.getBuild("$BUILD_NUMBER")
def exceptionsToHandle = ["java.io.FileNotFoundException","hudson.plugins.git.GitException"]
def foundExection = build
.getLog()
.split('\n')
.toList()
.stream()
.filter{ line ->
!line.trim().isEmpty() && !exceptionsToHandle.stream().filter{ex -> line.contains(ex)}.collect().isEmpty()
}
.collect()
.size() > 0;
println "do something with '$foundExection'"
}
You can validate your Jenkinsfile before pushing it to repository.
Command-line Pipeline Linter
There are some IDE Integrations as well
Apparently this is an open issue with Jenkins: https://issues.jenkins.io/browse/JENKINS-57946
I have decided not to use Yogesh answer mentioned earlier. For me it is simpler to just copy the content of the Jenkinsfile directly into the Jenkins project instead of pointing Jenkins to the GIT location of the Jenkinsfile. However, in addition I keep the Jenkinsfile in GIT. But make sure to keep the GIT and the Jenkins version identical.

How do I configure "Scan Multibranch Pipeline Triggers" in my jenkinsfile?

Right now I manually configure my all my multibranch pipeline jobs and set "Scan Multibranch Pipeline Triggers" to 3 minutes.
How do I put this in my Jenkinsfile? I can't find examples of this. Is "Scan Multibranch Pipeline Triggers" available in the triggers{} block?
The settings on the multibranch configuration page only configure the multibranch scan job itself, not the individual jobs created inside the multibranch "folder".
The option under "Scan Multibranch Pipeline Triggers" that says "Periodically if not otherwise run" is only a trigger for when the multibranch job will scan for new branches. If changes are found to existing branches, or if new branches are discovered with a Jenkinsfile that match your branch specifications, a new build will be triggered, but this is not intended to be the way a job is triggered.
Actually, you can disable the automatic build when changes are found by adding a property to the SCM configuration to "Disable automatic SCM Triggering". Then then you will see the multibranch scan trigger, but the jobs themselves won't build, even if there are changes found.
To trigger jobs, ideally you should use a webhook if you can. If you use a git hook using the git plugin (not the github plugin), then you need to enable the PollSCM trigger (though you can set it to only poll rarely, or not at all).
If you just want normal triggering options, as of 2.22, you can configure the either cron or pollSCM triggers.
pipeline {
triggers {
cron('H/4 * * * 1-5')
pollSCM('0 0 * * 0')
}
Then I believe you can configure webhooks to inform your multibranch job when to do a scan. I haven't tried that. I just tell it to scan every hour or a couple times per day using the "Periodically if not otherwise run".
Note, the same thing applies for the build discarder and other things you configure in your multibranch job. In the web UI, you can only configure the multibranch job itself, not the individual jobs created from it. You have to use Pipeline to configure the jobs.
If your're using the JobDSL Jenkins plugin for creating jobs, then you can add following lines to configure "Scan Multibranch Pipeline Triggers":
configure {
it / 'triggers' << 'com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger'{
spec '* * * * *'
interval "60000"
}
}
Using the JobDSL Jenkins Plugin for multibranch pipeline job, the periodic folder trigger can be configured as given below. In this example, the maximum amount of time since the last indexing that is allowed to elapse before an indexing is triggered will be seven days.
multibranchPipelineJob('my-awesome-job') {
triggers {
periodicFolderTrigger {
interval("7d")
}
}
}

How to set Jenkins pipeline job to always build 'default' branch but only build other branches over night

Given a Jenkins multibranch pipeline job that uses a property strategy to "suppress automatic SCM triggering" for all branches but 'default', how do you allow Jenkins to wait until night (say 7pm-6am) to build every other branch?
We used to be able to set the Poll SCM strategy for each job individually, which worked well.
Pipeline scripts allow you to set a pollSCM pipeline trigger property. However it won't get set unless the job has run at least once and there seems to be a defect where jobs are continuously triggered by scm changes, making it less useful.
Jenkinsfile properties can (now) configure polling triggers and override the default triggering behaviour. This example enables daily builds for everything except 'default' and release branches (which are always built)
def alwaysBuild = (env.BRANCH_NAME == "default" || env.BRANCH_NAME ==~ /release-.*/);
properties([
overrideIndexTriggers(alwaysBuild),
pipelineTriggers([pollSCM('#daily')])
]);
NOTE: As of 2016-Sept, there seems to be a bug where pollSCM triggers multiple builds per change. Possibly this bug: https://issues.jenkins-ci.org/browse/JENKINS-38443

Multibranch Pipeline vs Pipeline job

Now that the Multibranch Pipeline job type has matured, is there any reason to use the simple Pipeline job type any longer? Even if you only have one branch today, it's probably wise to account for the possibility of multiple branches in the future, so what would the motivation be to use the Pipeline job type for your Jenkins Pipeline vs. always using the Multibranch Pipeline job type, assuming you are storing your Jenkinsfile in SCM? Is there feature parity between the two job types now?
In my experience with multibranch pipelines, the ONLY downside is that you can't see the last success/failure/duration columns on the Jenkins main page. They just show "NA" on the Jenkins front page since it's technically a 'folder' of sub-jobs.
Other than that I can't think of any other "cons" to using multibranch.
I disagree with the other answer.... that case was that multibranch sends changes for "any" branch. That's not necessarily true. If a Jenkinsfile exists on a random feature branch, but that branch is not defined in the pipeline then you can just not do anything with it using typical if/else conditionals.
For example:
node {
checkout scm
def workspace = pwd()
if (env.BRANCH_NAME == 'master') {
stage ('Some Stage 1 for master') {
sh 'do something'
}
stage ('Another Stage for Master') {
sh 'do something else here'
}
}
else if (env.BRANCH_NAME == 'stage') {
stage ('Some stage branch step') {
sh 'do something'
}
stage ('Deploy to stage target') {
sh 'do something else'
}
}
else {
sh 'echo "Branch not applicable to Jenkins... do nothing"'
}
}
Multibranch Pipeline works well if your Jenkins job deals with a single git repository. On the other hand, the pipeline job can be repository-neutral and branch-neutral and very flexible when working with multiple git repositories with a single Jenkins job.
For example, assume you have artifact-1 from repo-1, artifact-2 from repo-2, and integration tests from repo-3. And artifact-2 depends on artifact-1. A Jenkins job has to build artifact-1, then build artifact-2, and finally run integration tests from repo-3. And assume your code change goes to a feature-1 branch of repo-1 and feature-1 branch for new tests in repo-3. In this case, the Jenkins job builds feature-1 for artifact-1, then uses 'dev' branch as default from repo-2 (if feature-1 is not detected in repo-2), and runs 'feature-1' from repo-3 for new integration tests. As you can see, the job works well with three git repositories. A repo-neutral/branch-neutral pipeline job is ideal in this setting.
In a CI/CD situation, it may not be desirable to send every branch to the target environment. Using pipeline and specifying a single branch would allow you to filter, and send only /master to Staging or Production environments. Multibranch would be useful for sending any change on any branch specifically to a test environment.
On the other hand, if the QA/AutomatedTesting process is thorough enough, the risk with sending any branch to Production could be acceptable.
If you are still developing your flow, the simple pipeline has the added advantage of supporting parameterized projects. This feature is useful for developing the declarative pipelines in the jenkins gui, using the parameter to control what branch/repository you are targeting.

Resources