Jenkins Multibranch pipeline pull request - jenkins

I am using multibranch pipeline for pullrequest. When a pr is created it triggers the pullrequest job. Is there anyway to trigger the job only on specific pull requests instead of all.
example: I have three branches develop, fb and master. I want to trigger the job only when I create a pull request from develop to master, not when I create a pullrequest from fb to develop or fb to master.

In this case you may want to run your pipeline, analyze the base branch, and stop if the base branch is not to your liking.
The environment variable CHANGE_ID is set by the github branch source plugin in case the branch is a pull request.
If it's set, you can explore the global object named pullRequest, e.g. like this:
if (env.CHANGE_ID) {
echo("Looking for PR: PR detected, change id is ${env.CHANGE_ID}")
def prBase = pullRequest.base
if (prBase != 'master') {
currentBuild.result = 'ABORTED'
error("This PR is over ${prBase} branch, not 'master'. Aborting.")
}
}

Related

How to "Scan Repository Now" from a Jenkinsfile

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.

Triggering job on github pr to a specific branch

I am using the github branch source plugin: https://github.com/jenkinsci/github-branch-source-plugin to trigger jobs from github pr.
I would like jenkins trigger a build only when a pr to the master branch is made. I tried to use the branch filter plugin but it doesn't trigger at any pr. I guess it doesnt work on prs, only on direct push to branches.
is that possible?
this should to the trick. (there is a downside though as this condition is not on a plugin level, so the build will be triggered on other events too)
stage('build') {
when {
allOf {
branch 'PR-*'
environment name: 'CHANGE_TARGET', value: 'master'
}
}
steps {
sh 'building pr on master'
}
}

Skipping stages in Jenkins pipeline on a Commit but not a PR

We are currently using the Jenkins/Groovy pipeline method for CI.
I'm trying to create a single pipeline for building packages and running unit tests on a branch (and let me know if this is bad practice).
The problem is on a commit I don't want to execute my test steps (due to the large number of commits and time to execute the full pipeline), but I still want the packaging stage to run for our manual testers to be able to pull and install on instances.
Is there any way to distinguish between a run for a PR vs a commit in the pipeline steps or in the job configuration?
Using the (assuming github, but theres bitbucket equiv as well)
https://wiki.jenkins.io/display/JENKINS/GitHub+Branch+Source+Plugin to discover Repositories to build branches and PR's will allow you to fall back on Jenkins ENV variables.
This allows simple if statement to determine if the build is for a branch, or for a PR, as PR's are built on a 'branch' of PR-n
Once a PR is open however, all commits would be built.
https://go.cloudbees.com/docs/cloudbees-documentation/cje-user-guide/index.html#github-branch-source
you can use the changeRequest built-in condition from Jenkins.
Executes the stage if the current build is for a "change request" (a.k.a. Pull Request on GitHub and Bitbucket, Merge Request on GitLab, Change in Gerrit, etc.). When no parameters are passed the stage runs on every change request, for example: when { changeRequest() }.
stage('Run only for pull requests to master branch or at the master branch') {
when {
anyOf {
branch 'master'
changeRequest target: 'master'
}
}
steps {
// this is a very long step for integration test that we don't want to execute often, but we need to execute before to merge to master
sh "${mvn} " +
"clean " +
"test-compile " +
"failsafe:integration-test failsafe:verify"
}
}

Jenkins: how to trigger pipeline on git tag

We want to use Jenkins to generate releases/deployments on specific project milestones. Is it possible to trigger a Jenkins Pipeline (defined in a Jenkinsfile or Groovy script) when a tag is pushed to a Git repository?
We host a private Gitlab server, so Github solutions are not applicable to our case.
This is currently something that is sorely lacking in the pipeline / multibranch workflow. See a ticket around this here: https://issues.jenkins-ci.org/browse/JENKINS-34395
If you're not opposed to using release branches instead of tags, you might find that to be easier. For example, if you decided that all branches that start with release- are to be treated as "release branches", you can go...
if( env.BRANCH_NAME.startsWith("release-") ) {
// groovy code on release goes here
}
And if you need to use the name that comes after release-, such as release-10.1 turning into 10.1, just create a variable like so...
if( env.BRANCH_NAME.startsWith("release-") ) {
def releaseName = env.BRANCH_NAME.drop(8)
}
Both of these will probably require some method whitelisting in order to be functional.
I had the same desire and rolled my own, maybe not pretty but it worked...
In your pipeline job, mark that "This project is parameterized" and add a parameter for your tag. Then in the pipeline script checkout the tag if it is present.
Create a freestyle job that runs a script to:
Checkout
Run git describe --tags --abbrev=0 to get the latest tag.
Check that tag against a running list of builds (like in a file).
If the build hasn't occurred, trigger the pipeline job via a url passing your tag as a parameter (in your pipeline job under "Build Triggers" set "Trigger builds remotely (e.g. from scripts) and it will show the correct url.
Add the tag to your running list of builds so it doesn't get triggered again.
Have this job run frequently.
if you use multibranch pipeline, there is a discover tag. Use that plus Spencer solution

How to check if a pipeline is triggered from a pull request

I'm using Jenkins pipeline to build Pull Requests branches using the GitHub Organization plugin.
I can build them fine, but I want to avoid some steps (such as publishing the artifacts). Checking git's current branch gives me the PR's target since the PR branch is being merged into the target before the build is attempted.
How can I check if the build is being initiated from a PR vs than a regular branch build?
At least on Jenkins 2.16 env.BRANCH_NAME gives the source branch not the target branch. You could do something like:
if (env.BRANCH_NAME == "master") {
sh "./publish.sh"
}
Other env vars that could be useful are the CHANGE_* variables. E.g.,
CHANGE_AUTHOR='me'
CHANGE_ID='6'
CHANGE_TARGET='master'
CHANGE_TITLE='Update README.md'
CHANGE_URL='https://github.com/test-org/test-repo/pull/6'
For documentation on these and more: https://ci.eclipse.org/webtools/env-vars.html/
The env variable CHANGE_ID only exists when the build is triggered from a Pull Request check.
For a multibranch project corresponding to some kind of change request, this will be set to the change ID, such as a pull request number, if supported; else unset.
To specifically detect GitHub pull requests, this can be used:
script {
if (env.BRANCH_NAME == 'master') {
sh 'make'
} else if (env.BRANCH_NAME.startsWith('PR')) {
// do actions for pull request
} else {
// some other branch
}
}
Of course, if you expect to have branches starting with PR on your main repository this wouldn't be reliable. The nice thing about it is that script can be used also in post not just stages, which is useful since when is not allowed in post. If you don't care about that it's worth looking into the when directive. There is some documentation from Cloudbees and Jenkins with some examples.

Resources