Child pages
  • Violation Comments to GitLab Plugin
Skip to end of metadata
Go to start of metadata

Plugin Information

View Violation Comments to GitLab on the plugin site for more information.

This plugin uses Violation Comments to GitLab Lib. It will find report files from static code analysis and comment GitLab merge requests with the content.


You can have a look at violations-test to see what the result may look like.

There is also plugins for:

It supports same formats as Violations Lib:

Some formats may vary. Examples of the exact supported formats can be found here.

Missing a format? Open an issue here!

Notify Jenkins from GitLab

Merge

You must perform the merge before build. If you don't perform the merge, the reported violations will refer to other lines then those in the pull request. The merge can be done with a shell script like this.

Shell script build step
git clone $TOREPO
cd *
git reset --hard $TO
git status
git remote add from $FROMREPO
git fetch from
git merge $FROM
git --no-pager log --max-count=10 --graph --abbrev-commit

your build command here!


Screenshots

When installed, a post build action will be available.

The pull request will be commented like this.

Job DSL

Here is an example that will use Generic Webhook Trigger plugin and comment GitLab merge requests. It also uses HTTP Request Plugin to comment the merge request with a link to the job. And also Conditional BuildStep Plugin to have different comments depending on build status.

GitLab job DSL
job('GitLab_MR_Builder') {
 concurrentBuild()
 quietPeriod(0)
 parameters {
  stringParam('MERGE_REQUEST_TO_URL', '')
  stringParam('MERGE_REQUEST_FROM_URL', '')
  stringParam('MERGE_REQUEST_TO_BRANCH', '')
  stringParam('MERGE_REQUEST_FROM_BRANCH', '')
 }
 scm {
  git {
   remote {
    name('origin')
    url('$MERGE_REQUEST_TO_URL')
   }
   remote {
    name('upstream')
    url('$MERGE_REQUEST_FROM_URL')
   }
   branch('$MERGE_REQUEST_FROM_BRANCH')
   extensions {
    mergeOptions {
     remote('upstream')
     branch('$MERGE_REQUEST_TO_BRANCH')
    }
   }
  }
 }
 triggers {
  genericTrigger {
   genericVariables {
    genericVariable {
     key("MERGE_REQUEST_TO_URL")
     value("\$.object_attributes.target.git_http_url")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_FROM_URL")
     value("\$.object_attributes.source.git_http_url")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_TO_BRANCH")
     value("\$.object_attributes.target_branch")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_FROM_BRANCH")
     value("\$.object_attributes.source_branch")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("PROJECT_ID")
     value("\$.object_attributes.target_project_id")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUST_ID")
     value("\$.object_attributes.id")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_OBJECT_KIND")
     value("\$.object_kind")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_OLD_REV")
     value("\$.object_attributes.oldrev")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_ACTION")
     value("\$.object_attributes.action")
     expressionType("JSONPath")
     regexpFilter("")
    }
   }
   regexpFilterText("\$MR_OBJECT_KIND \$MR_ACTION \$MR_OLD_REV")
   regexpFilterExpression("^merge_request\\s(update\\s.{40}\$|open.*)")
  }
 }
 steps {
  httpRequest {
   url("http://gitlab:880/api/v3/projects/\$PROJECT_ID/merge_requests/\$MERGE_REQUST_ID/notes?private_token=AvAkp6HtUvzpesPypXSk")
   consoleLogResponseBody(true)
   httpMode("POST")
   requestBody('body=Building... %20\$BUILD_URL')
   }
 
  shell('./gradlew build')
 
  conditionalBuilder {
   runCondition {
    statusCondition {
     worstResult('SUCCESS')
     bestResult('SUCCESS')
    }
    runner {
     runUnstable()
    }
    conditionalbuilders {
     httpRequest {
      url('http://gitlab:880/api/v3/projects/\$PROJECT_ID/merge_requests/\$MERGE_REQUST_ID/notes?private_token=AvAkp6HtUvzpesPypXSk')
      consoleLogResponseBody(true)
      httpMode('POST')
      requestBody('body=SUCCESS%20\$BUILD_URL')
     }
    }
   }
  }
 
  conditionalBuilder {
   runCondition {
    statusCondition {
     worstResult('FAILURE')
     bestResult('FAILURE')
    }
    runner {
     runUnstable()
    }
    conditionalbuilders {
     httpRequest {
      url('http://gitlab:880/api/v3/projects/\$PROJECT_ID/merge_requests/\$MERGE_REQUST_ID/notes?private_token=AvAkp6HtUvzpesPypXSk')
      consoleLogResponseBody(true)
      httpMode('POST')
      requestBody('body=FAIL%20\$BUILD_URL')
     }
    }
   }
  }
 }
 publishers {
  violationsToGitLabRecorder {
   config {
    gitLabUrl("http://gitlab:880/")
    projectId("\$PROJECT_ID")
    mergeRequestId("\$MERGE_REQUST_ID")
 
    commentOnlyChangedContent(true)
    createCommentWithAllSingleFileComments(true)
    minSeverity('INFO')
 
    apiToken("")
    apiTokenCredentialsId("gitlabtoken")
    apiTokenPrivate(true)
    authMethodHeader(true)
    ignoreCertificateErrors(true)
 
    violationConfigs {
     violationConfig {
      parser("FINDBUGS")
      reporter("Findbugs")
      pattern(".*/findbugs/.*\\.xml\$")
     }
     violationConfig {
      parser("CHECKSTYLE")
      reporter("Checkstyle")
      pattern(".*/checkstyle/.*\\.xml\$")
     }
    }
   }
  }
 }
}

Pipeline

Here is an example pipeline that will merge, run unit tests, run static code analysis and finally report back to GitLab. It requires the GitLab Plugin.

Pipeline script
pipelineJob("merge-request-pipeline") {
 concurrentBuild()
 quietPeriod(0)
 authenticationToken("thetoken")
 triggers {
  genericTrigger {
   genericVariables {
    genericVariable {
     key("MERGE_REQUEST_TO_URL")
     value("\$.object_attributes.target.git_http_url")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_FROM_URL")
     value("\$.object_attributes.source.git_http_url")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_TO_BRANCH")
     value("\$.object_attributes.target_branch")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUEST_FROM_BRANCH")
     value("\$.object_attributes.source_branch")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("PROJECT_ID")
     value("\$.object_attributes.target_project_id")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("PROJECT_PATH")
     value("\$.object_attributes.target.path_with_namespace")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MERGE_REQUST_IID")
     value("\$.object_attributes.iid")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_OBJECT_KIND")
     value("\$.object_kind")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_OLD_REV")
     value("\$.object_attributes.oldrev")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_ACTION")
     value("\$.object_attributes.action")
     expressionType("JSONPath")
     regexpFilter("")
    }
    genericVariable {
     key("MR_TITLE")
     value("\$.object_attributes.title")
     expressionType("JSONPath")
     regexpFilter("")
    }
   }
   regexpFilterText("\$MR_OBJECT_KIND \$MR_ACTION \$MR_OLD_REV")
   regexpFilterExpression("^merge_request\\s(update\\s.{40}\$|open.*)")
  }
 }

 definition {
  cps {
   script(readFileFromWorkspace('merge_request_pipeline.pipeline'))
   sandbox()
  }
 }
}

And the merge_request_pipeline.pipeline contains

Pipeline script
def commentMr(projectId, mergeRequestId, comment) {def body = comment
 .replaceAll(" ","%20")
 .replaceAll("/","%2F")
 def project = projectId
 .replaceAll("/","%2F")
 sh "curl http://gitlab:80/api/v4/projects/$project/merge_requests/$mergeRequestId/notes -H 'PRIVATE-TOKEN: 6xRcmSzPzzEXeS2qqr7R' -X POST -d \"body="+body+"\""
}
  
node {
 deleteDir()
 currentBuild.description = "$MR_TITLE from $MERGE_REQUEST_FROM_BRANCH to $MERGE_REQUEST_TO_BRANCH"
  
 commentMr(env.PROJECT_PATH,env.MERGE_REQUST_IID,"Verifierar $MERGE_REQUEST_FROM_BRANCH... ${env.BUILD_URL}")
  
 stage('Merge') {
 sh "git init"
 sh "git fetch --no-tags $MERGE_REQUEST_TO_URL +refs/heads/*:refs/remotes/origin/* --depth=200"
 sh "git checkout origin/${env.MERGE_REQUEST_TO_BRANCH}"
 sh "git config user.email 'je@nkins.domain'"
 sh "git config user.name 'jenkins'"
 sh "git merge origin/${env.MERGE_REQUEST_FROM_BRANCH}"
 sh "git log --graph --abbrev-commit --max-count=10"
 }
  
 stage('Compile') {
 sh "./gradlew assemble"
 }
  
 stage('Unit test') {
 sh "./gradlew test"
 commentMr(env.PROJECT_PATH,env.MERGE_REQUST_IID,"Test ok in $MERGE_REQUEST_FROM_BRANCH =) ${env.BUILD_URL}")
 }
  
 stage('Regression test') {
 sh "echo regtest"
 commentMr(env.PROJECT_PATH,env.MERGE_REQUST_IID,"Regression test ok in $MERGE_REQUEST_FROM_BRANCH =) ${env.BUILD_URL}")
 }
  
 stage('Static code analysis') {
 sh "./gradlew check"
 step([
 $class: 'ViolationsToGitLabRecorder',
 config: [
 gitLabUrl: 'http://gitlab:80/',
 projectId: env.PROJECT_PATH,
 mergeRequestId: env.MERGE_REQUST_IID,
 commentOnlyChangedContent: true,
 createCommentWithAllSingleFileComments: true,
 minSeverity: 'INFO',
 
 //Specify one of these
 apiToken: '6xRcmSzPzzEXeS2qqr7R',
 apiTokenCredentialsId: 'id',
 
 apiTokenPrivate: true,
 authMethodHeader: true,
 ignoreCertificateErrors: true,
 keepOldComments: false,
 shouldSetWip: true,
 violationConfigs: [
 [ pattern: '.*/checkstyle/.*\\.xml$', parser: 'CHECKSTYLE', reporter: 'Checkstyle' ],
 [ pattern: '.*/findbugs/.*\\.xml$', parser: 'FINDBUGS', reporter: 'Findbugs' ],
 [ pattern: '.*/pmd/.*\\.xml$', parser: 'PMD', reporter: 'PMD' ],
 ]
 ]
 ])
 }
}

Changelog

https://github.com/jenkinsci/violation-comments-to-gitlab-plugin/blob/master/CHANGELOG.md

Write a comment…