GitLab pipelines for merge requests in Jenkins - jenkins

I'm working on a CI integration between GitLab and Jenkins where I want to do specific validation depending on the target branch of an opened merge request (MR).
To be more specific, we have a repository containing Flyway database migrations and we'd like to validate inside a Docker container whether the migrations can be applied successfully against different environments. The target environment can be deduced by the target branch of a merge request.
Now, my problem is this. I'd like to reject MRs that don't build successfully, but I couldn't find way of rejecting MRs, only commits.
The way our integration is set up is that Jenkins receives webhook notifications for both commit and MR events. So, when someone pushes a new commit to an MR, two Jenkins builds will be triggered — one for the whole MR and one for the commit. The MR build will fail, but the commit build will succeed and due to race conditions in how the builds are run, the MR pipeline in GitLab will be marked as successful although it shouldn't be.
Is there a way to mark merge requests as failed in a Jenkins-GitLab integration?
I believe this feature is called pipelines for merge requests in GitLab's built-in CI/CD support, but can it be simulated with Jenkins?
Here's a sketch of the Jenkinsfile I'm using:
def isMergeRequest() {
gitlabActionType == 'MERGE' && gitlabTargetBranch != gitlabSourceBranch
}
pipeline {
agent any
stages {
stage('Validate') {
when {
expression {
isMergeRequest()
}
}
steps {
gitlabCommitStatus('Validate') {
sh "jenkins/validate_mr.py $gitlabTargetBranch $gitlabSourceBranch"
}
}
}
}
}

Related

In Jenkins, Is there a way to execute a pipeline when the source branch of a PR is updated?

This is my Jenkinsfile:
pipeline {
agent { docker { image 'node:10.16' } }
stages {
stage('PR To Dev') {
when {
changeRequest target: 'dev'
}
steps {
sh 'npm install'
sh 'npm run lint'
}
}
}
}
I'm trying to run linting upon every PR made (on Github). This pipeline works and runs as intended when I make the initial PR to the dev branch. However, subsequent commits to the open PR are ignored by Jenkins, which defeats the usefulness of the initial lint check. How can I configure Jenkins to lint upon any updates to a branch that has an open PR to the dev (or any arbitrary) branch?
Achieving this goal is possible. It depends greatly on the plugin that you are using to integrate GitHub with Jenkins, and how you configure GitHub to use Jenkins' webhooks.
On the GitHub end, you can configure to trigger the webhook on different events. Default config is Push events (to any branch, whether on PR or not), All events (these can have many false positives), and the option to Select individual events (find your right balance between events coverage and false positives)
On the Jenkins end, some plugins will offer more customization options to discard unnecessary triggers, for example to avoid triggering a project on PR updates of the title or description (instead of code), etc.
I, personally, use the Generic Webhook Plugin on the Jenkins end and then I analyze the json of the webhook to determine whether to run a job or not

Jenkins Pipeline Multibranch doesn't run post steps if there is merge conflicts

I have a multibranch pipeline with the following behaviors:
And the following Jenkinsfile:
pipeline {
agent {
label 'apple'
}
stages {
stage('Lint') {
when {
changeRequest()
}
steps {
sh 'fastlane lint'
}
}
}
post {
success {
reportSuccess()
}
failure {
reportFailure()
}
}
}
I use a slave to run the actual build, but the master still needs to checkout the code to get the Jenkinsfile. For that, it seems to use the same behaviors as the one defined in the job even though it really only needs the Jenkinsfile.
My problem is that I want to discover pull requests by merging the pull request with the current target branch revision, but when there is a merge conflict the build will fail before the Jenkinsfile is executed. This prevents any kind of reporting done in post steps.
Is there a way to have the initial checkout not merge the target branch, but still have it merged when actually running the Jenkinsfile on a slave?
You may want to check out using "Current Pull Request revision" strategy, and then on a successful build issue a git merge command.

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

Publish Jenkins Job build status to Gitlab commit from Jenkins

I'm new to jenkins. I'm using Jenkins 2.77 and GitLab Enterprise Edition 9.5.5. I see a strange issue happening.
I've created 3 Jenkins freestyle jobs and have built a pipeline view for those jobs [1 ~> 2 ~> 3]. I am able to trigger builds with Gitlab webhook and publish the status of job 3 to Gitlab without any issues . All these were done manually.
I have to create these 3 jobs for about 100 projects. So I chose to generate these jobs via jenkins job DSL. I am able to generate the jobs and build a pipeline view. Also triggering the builds (for a particular project) from Gitlab webhook works fine. In the pipeline view I am able to see the builds too. But unfortunately due to some reason, I'm not getting feedback to Gitlab.
The strange thing I observed is, if open the "job 3" in jenkins and just click save without even changing anything, it auto-magically sends the feedback from the next builds.
I've no clue what is going on.
DSL of job 3:
job("SyntaxCheck") {
logRotator {
numToKeep(10)
artifactNumToKeep(10)
}
parameters {
stringParam('jobType', '')
}
scm {
git {
remote {
url('gitlab url to checkout the project')
branch('master')
credentials(*********)
extensions {
submoduleOptions {
recursive(true)
}
}
}
}
}
steps {
shell(puppetparser)
}
publishers {
gitLabCommitStatusPublisher {
name('syntaxcheck')
markUnstableAsSuccess(false)
}
}
}
Suggestions or workarounds would be appreciated.

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