What does the pollSCM trigger refer to in this Jenkinsfile? - jenkins

Consider the following setup using Jenkins 2.176.1:
A new pipeline project named Foobar
Poll SCM as (only) build trigger, with: H/5 * * * * ... under the assumption that this refers to the SCM configured in the next step
Pipeline script from SCM with SCM Git and a working Git repository URL
Uncheck Lightweight checkout because of JENKINS-42971 and JENKINS-48431 (I am using build variables in the real project and Jenkinsfile; also this may affect how pollSCM works, so I include this step here)
Said repository contains a simple Jenkinsfile
The Jenkinsfile looks approximately like this:
#!groovy
pipeline {
agent any
triggers { pollSCM 'H/5 * * * *' }
stages {
stage('Source checkout') {
steps {
checkout(
[
$class: 'GitSCM',
branches: [],
browser: [],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [
[
url: 'git://server/project.git'
]
]
]
)
stash 'source'
}
}
stage('OS-specific binaries') {
parallel {
stage('Linux') {
agent { label 'gcc && linux' }
steps {
unstash 'source'
echo 'Pretending to do a build here'
}
}
stage('Windows') {
agent { label 'windows' }
steps {
unstash 'source'
echo 'Pretending to do a build here'
}
}
}
}
}
}
My understanding so far was that:
a change to the Jenkinsfile (not the whole repo) triggers the pipeline on any registered agent (or as configured in the pipeline project).
said agent (which is random) uses the pollSCM trigger in the Jenkinsfile to trigger the pipeline stages.
But where does the pollSCM trigger poll (what SCM repo)? And if it's a random agent then how can it reasonably detect changes across poll runs?
then the stages are being executed on the agents as allocated ...
Now I am confused what refers to what. So here my questions (all interrelated which is why I keep it together in one question):
The pipeline project polls the SCM just for the Jenkinsfile or for any changes? The repository in my case is the same (for Jenkinsfile and source files to build binaries from).
If the (project-level) polling triggers at any change rather than changes to the Jenkinsfile
Does the pollSCM trigger in the Jenkinsfile somehow automagically refer to the checkout step?
Then ... what would happen, would I have multiple checkout steps with differing settings?
What determines what repository (and what contents inside of that) gets polled?
... or is this akin to the checkout scm shorthand and pollSCM actually refers to the SCM configured in the pipeline project and so I can shorten the checkout() to checkout scm in the steps?
Unfortunately the user handbook didn't answer any of those questions and pollSCM has a total of four occurrences on a single page within the entire handbook.

I'll take a crack at this one:
The pipeline project polls the SCM just for the Jenkinsfile or for any
changes? The repository in my case is the same (for Jenkinsfile and
source files to build binaries from).
The pipeline project will poll the repo for ANY file changes, not just the Jenkinsfile. A Jenkinsfile in the source repo is common practice.
If the (project-level) polling triggers at any change rather than
changes to the Jenkinsfile Does the pollSCM trigger in the Jenkinsfile
somehow automagically refer to the checkout step?
Your pipeline will be executed when a change to the repo is seen, and the steps are run in the order that they appear in your Jenkinsfile.
Then ... what would happen, would I have multiple checkout steps with
differing settings?
If you defined multiple repos with the checkout step (using multiple checkout SCM calls) then the main pipeline project repo would be polled for any changes and the repos you define in the pipeline would be checked out regardless of whether they changed or not.
What determines what repository (and what contents inside of that)
gets polled? ... or is this akin to the checkout scm shorthand and
pollSCM actually refers to the SCM configured in the pipeline project
and so I can shorten the checkout() to checkout scm in the steps?
pollSCM refers to the pipeline project's repo. The entire repo is cloned unless the project is otherwise configured (shallow clone, lightweight checkout, etc.).

The trigger defined as pollSCM polls the source-control-management (SCM), at the repository and branch in which this jenkinsfile itself (and other code) is located.
For Pipelines which are integrated with a source such as GitHub or BitBucket, triggers may not be necessary as webhooks-based integration will likely already be present. The triggers currently available are cron, pollSCM and upstream.
It works for a multibranch-pipeline as trigger to execute the pipeline.
When Jenkins polls the SCM, exactly this repository and branch, and detects a change (i.e. new commit), then this Pipeline (defined in jenkinsfile) is executed.
Usually then the following SCM Step checkout will be executed, so that the specified project(s) can be built, tested and deployed.
See also:
SCM Poll in jenkins multibranch pipeline
SehllHacks(2020): Jenkins: Scan Multibranch Pipeline Without Build

Related

Jenkins with Jenkinsfile Pipeline - Trigger Builds Remotely

I have a Jenkinsfile setup for our CI/CD pipeline, and it runs through the pipeline on git actions like Pull Requests, Branch Creation, Tag Pushes, etc..
Prior to this setup, I was used to setting up Jenkins build jobs in the Jenkins UI. The advantage of this, was that I could setup dedicated build jobs that I could trigger remotely, and independently of git webhook actions. I could do a POST to the job endpoint with parameters to trigger various actions.
Documentation for this process would be referenced here - see "Trigger Builds Remotely"
I could also hit the big button that says "Build", or "Build with Parameters" in the UI, which was super nice.
How would one do this with a Jenkinsfile? Is this even possible to define build jobs in a pipeline definition within a Jenkinsfile? I.E. define functions / build jobs that have dedicated URLs that could be called on the Jenkins URL independent of webhook callbacks?
What's the best practice here?
Thanks for any tips, references, suggestions!
I would recommend starting with Multibranch pipelines. In general you get all the things you mentioned, but a little better. Because thhe paramteres can be defined within your Jenkinsfile. In short just do it like this:
Create a Jenkinsfile an check this into a Git Repository.
To create a Multibranch Pipeline: Click New Item on Jenkins home page.
Enter a name for your Pipeline, select Multibranch Pipeline and click OK.
Add a Branch Source (for example, Git) and enter the location of the repository.
Save the Multibranch Pipeline project.
A declarative Jenkinsfile can look like this:
pipeline {
agent any
parameters {
string(name: 'Greeting', defaultValue: 'Hello', description: 'How should I greet the world?')
}
stages {
stage('Example') {
steps {
echo "${params.Greeting} World!"
}
}
}
}
A good tutorial with screenshhots can be found here: https://www.jenkins.io/doc/book/pipeline/multibranch/

Jenkins multibranch pipeline with Jenkinsfile from different repository

I have a Git repository with code I'd like to build but I'm not "allowed" to add a Jenkinsfile in its root (it is a Debian package so I can't add files to upstream source). Is there a way to store the Jenkinsfile in one repository and have it build code from another repository? Since my code repository has several branches to build (one for each Debian release) this should be a multibranch pipeline. Commits in either the code or Jenkinsfile repositories should trigger a build.
Bonus complexity: I have several code/packaging repositories like this and I'd like to reuse the same Jenkinsfile for all of them. Thus it should somehow dynamically fetch the right Git URL to use. The branches to build have the same names across all repositories.
Short answer is : you cannot do that with a multibranch pipeline. Multibranch pipelines are only designed (at least for now) to execute a specific pipeline in Pipeline script from SCM style, with a fixed Jenkinsfile at the root of the project.
You can however use the Multi-Branch Project plugin made for multibranch freestyle projects. First, you need to define your multibranch freestyle configuration just like you would with a multibranch pipeline configuration.
Select this new item like shown below :
This type of configuration will behave exactly same as the multibranch pipeline type, i.e. it will create you a folder with the name of your configuration and a sub-project for each branch it automatically detected.
The implementation should then be a piece of cake :
Specify your SCM repository in the multibranch configuration
Call another build as part of your build/post-build as you would do in a standard freestyle project, except that you have to call a parameterized job (let's call it build-job) and give it your repository information, i.e. Git URL and current branch (you can use the pre-defined variables $GIT_URL and $GIT_BRANCH for this purpose)
In your build-job, just define either an inline pipeline or a pipeline script checked out from SCM, and inside this script do a SCM checkout and go on with the steps you need to build. Example of build-job pipeline content :
.
node() {
stage 'Checkout'
checkout scm: [$class: 'GitSCM', branches: [[name: '*/${GIT_BRANCH}']], userRemoteConfigs: [[url: '${GIT_URL}']]]
stage 'Build'
// Build steps...
}
Of course if your different multibranches projects need to be treated a bit differently, you could also use intermediate projects (let's say build-project-A, build-project-B, ...) that would in turn call the generic build-job pipeline)
The one, major drawback of this solution is that you will only have one job responsible for all of your builds, making it harder to debug. You would still have your multibranch projects going blue/red in case of success/error but you will have to go back to called build-job to find the real problem of your build.
The best way I have found is to use the Remote Jenkinsfile Provider plugin. https://plugins.jenkins.io/remote-file/
This will add an option "by Remote Jenkinsfile Provider plugin" under Build Configuration>Mode then you can point to another repo where the Jenkinsfile is. I find this to be a much better solution than the Pipeline Multibranch Defaults Plugin, which makes you store the Jenkins file in Jenkins itself, rather than in source control.
U can make use of this plugin
https://github.com/jenkinsci/pipeline-multibranch-defaults-plugin/blob/master/README.md
Where we need to configure the jenkinsfile on jenkins rather than having it on each branch of your repo
I have version 2.121 and you can do this two ways:
Way 1
In the multibranch pipeline configuration > Build Configuration > Mode > Select "Custom Script" and put in "Marker File" below the name of a file you will use to identify branches that you want to have builds for.
Then, below that in Pipeline > Definition select "Pipeline Script from SCM" and enter the "SCM" information for how to find the "Jenkinsfile" that holds the script you want to run. It can be in the same repo you are finding branches in to create the jobs (if you put in the same GitHub repo's info) but I can't find a way to indicate that you just use the same branch for the file.
Way 2
Same as above, in the multibranch pipeline configuration > Build Configuration > Mode > Select "Custom Script" and put in "Marker File" below the name of a file you will use to identify branches that you want to have builds for.
Then, below that in Pipeline > Definition select "Pipeline Script" and put a bit of Groovy in the text box to load whatever you want or to run some script that already got loaded into the workspace.
In my case, i have an escenario whith a gitlab project based on gradle who has dependencies on another gitlab preject based on gradle too (same dashboard, but differents commits, differents developers).
I have added the following lines into my Jenkinsfile (the one which depends)
stage('Build') {
steps {
git branch: 'dev', credentialsId: 'jenkins-generated-ssh-key', url: 'git#gitlab.project.com:root/coreProject.git'
sh './gradlew clean'
}
}
Note: Be awark on the order on the sentences.
If you have doubt on how to create jenkins-generated-ssh-key please ask me

How to load another groovy script in the same Jenkins node?

When loading a pipeline script from another pipeline script, the two pipelines don't get executed on the same node : the first one is executed on my master node and the second gets executed on a slave node.
I'm using Jenkins pipelines with Pipeline Script from SCM option for a lot of jobs in this way :
Each of my jobs defines their corresponding Git repo URL with Poll SCM option so that the repository gets automatically polled when a change is made to my code (basic job usage).
Each of my jobs define a simple Jenkinsfile at the root of their repository, and the pipeline script inside does basically nothing but loading a more generic pipeline.
E.g. :
node {
// --- Load the generic pipeline ---
checkout scm: [$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: 'http://github/owner/pipeline-repo.git']]]
load 'common-pipeline.groovy'
}()
My common-pipeline.groovy pipeline does the actual stuff such as building, releasing or deploying artifacts, e.g. :
{ ->
node() {
def functions = load 'common/functions.groovy'
functions.build()
functions.release()
functions.deploy()
}
}
Now I don't want to force the node for each job so both pipelines have node("master") or node("remote") because I really don't want to be handling that manually, however I'd like that once the first pipeline runs on a specific node (either master, slave1, slave2, slave3) the second/loaded pipeline gets executed on the same node, because otherwise my actual Git repository code is not available from other node's workspace...
Is there any way I can specify that I want my second pipeline to be executed on the same node as the first, or maybe pass an argument when using the load step ?
How about stashing the workspace after the checkout and before the script load?:
e.g.
stash includes: '**', name: "source"
and then unstash it in another node(){} section:
e.g.
unstash "source"
That way it will be available in the other node
Don't forget to clean up the workspace though
Or how about creating a common function that contains the logic for the checkout too (maybe passing in branches as a param). Then you can discard the node(){} in the Jenkins file and just use node(){} entries in your shared groovy script?
e.g. Jenkinsfile
load 'common-pipeline.groovy'
createWorlflow("*/master")
common-pipeline.groovy:
def createWorkflow(branches){
node() {
def functions = load 'common/functions.groovy'
functions.checkout(branches)
functions.build()
functions.release()
functions.deploy()
}
}
You can make a parameterized job for the second pipeline and use the parameter to control the node when triggering the second job.
The second pipeline would look like this:
node(runhereParam) {
}

Jenkins multi-branch pipeline and specifying upstream projects

We currently generate a lot of Jenkins jobs on a per Git branch basis using Jenkins job DSL; the multi-branch pipeline plugin looks like an interesting way to potentially get first-class job generation support using Jenkinsfiles and reduce the amount of Job DSL we maintain.
For example we have libwidget-server and widget-server develop branch projects. When the libwidget-server build finishes then the widget-server job is triggered (for the develop branch). This applies to other branches too.
This makes use of the Build after other projects are built to trigger upon completion of an upstream build (e.g. libwidget-server causes widget-server to be built).
It seems that the multi-branch pipeline plugin lacks the Build after other projects are built setting - how would we accomplish the above in the multi-branch pipeline build?
You should add the branch name to your upstream job (assuming you are using a multi-branch pipeline for the upstream job too).
Suppose you have a folder with two jobs, both multi-branch pipeline jobs: jobA and jobB; jobB should trigger after jobA's master.
You can add this code snippet to jobB's Jenkinsfile:
properties([
pipelineTriggers([
upstream(
threshold: 'SUCCESS',
upstreamProjects: '../jobA/master'
)
])
])
(Mind that any branch of jobB here will trigger after jobA's master!)
I'm currently trying to get this to work for our deployment.
The closest I've got is adding the following to the downstream Jenkinsfile;
properties([
pipelineTriggers([
triggers: [
[
$class: 'jenkins.triggers.ReverseBuildTrigger',
upstreamProjects: "some_project", result: hudson.model.Result.SUCCESS
]
]
]),
])
That at least gets Jenkins to acknowledge that it should be triggering when
'some_project' get's built i.e it appears in the "View Configuration" page.
However so far builds of 'some_project' still don't trigger the downstream
project as expected.
That being said maybe you'll have more luck.
Let me know if it works for you.
(Someone else has asked a similar question here -> Jenkins: Trigger Multi-branch pipeline on upstream change )

Trigger workflow on Github push - Pipeline plugin - Multibranch configuration

We are using the pipeline plugin with multibranch configuration for our CD.
We have checked in the Jenkinsfile which works off git.
git url: "$url",credentialsId:'$credentials'
The job works fine, but does not auto trigger when a change is pushed to github.
I have set up the GIT web hooks correctly.
Interestingly, when I go into a branch of the multibranch job and I click "View Configuration", I see that the "Build when a change is pushed to Github" is unchecked. There is no way to check it since I can not modify the configuration of the job (since it takes from parent) and the same option is not there in parent.
Any ideas how to fix this?
For declarative pipelines try:
pipeline {
...
triggers {
githubPush()
}
...
}
For me this enables the checkbox "GitHub hook trigger for GITScm polling", but polling is not actually required. This requires the GitHub plugin.
I found a way to check the checkbox "Build when a change is pushed to Github".
This line did the trick:
properties([pipelineTriggers([[$class: 'GitHubPushTrigger'], pollSCM('H/15 * * * *')])])
I think the polling is needed to make it work. Would be nice if no polling is needed.
Here's a Jenkinsfile example with this implemented:
#!/usr/bin/env groovy
node ('master'){
stage('Build and Test') {
properties([pipelineTriggers([[$class: 'GitHubPushTrigger'], pollSCM('H/15 * * * *')])])
checkout scm
env.PATH = "${tool 'Maven 3'}/bin:${env.PATH}"
sh 'mvn clean package'
}
}
For declarative pipelines, try this:
pipeline {
agent any
triggers {
pollSCM('') //Empty quotes tells it to build on a push
}
}
If you use Stash for example you can register a Post-Receive WebHook where you have to insert your URL form Jenkins like : http://jenkinsHost:9090/git/notifyCommit?url=ssh://git#gitHost:1234/test.git
In your jenkins Job you have to set at least the Build trigger "Poll SCM".
And set a polling time of e.g 5 mins.
This enables also the automatic branch indexing for your multibranch project configuration.
Resorting to polling adds latency - time that it takes for a build to start and hence finish giving back a result.
It seemed to me that the basic plugins have a low level of abstraction, so I switched to the Github Organization Folder plugin, which depends on all of them and sets up an organization hook for triggering builds branches and/or pull requests.
Before I start, I would like to emphasize that I had no previous experience with Jenkins so far, so there might be a bunch of better solutions out there.
What I wanted to achieve in a nutshell:
After every push made to a Bitbucket repo(test2), on every branch,
pull and build another Bitbucket repo(test1), from an identical
branch name and right after that, build test2 using test1 as a
dependency.
How I managed to achieve that?
I started a new job with type 'Multibranch Pipeline'
I added the following Jenkinsfile to test2:
pipeline {
agent any
stages {
stage('build') {
steps {
dir('test1') {
git branch: BRANCH_NAME, url: 'git#bitbucket.org:user/test1.git', credentialsId: 'credentials_id'
}
sh('build_process')
}
}
}
}
I come across the issue that you can't set up a Bitbucket hook for pipelines
I added Bitbucket Branch Source Plugin to Jenkins
I selected Bitbucket at 'Branch Sources' when setting up the job
I added credentials and put a checkmark to Auto-register webhook
Under 'Scan Multibranch Pipeline Triggers' I put a checkmark to Periodically if not otherwise run, with an interval of 1 min
I added a webhook to my Bitbucket repo
I updated all my plugins, restarted Jenkins and it's ready to go
Other plugins I have installed: Bitbucket Plugin, Pipeline plugin. Hope this helps for somebody, I did manage to solve it this way after hours of struggling without the Bitbucket Branch Source Plugin.
node{
stage('Build and Test') {
properties([pipelineTriggers([[$class: 'GitHubPushTrigger'], pollSCM('* * * * *')])])
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'xxx-xxx-xxxx[your credentails Id]', url: 'https://github.com/git']]])
echo 'Build and Test has been done'
}
}

Resources