Pull request Decoration with Bitbucket

Must-share information (formatted with Markdown):

  • which versions are you using (SonarQube Enterprise 8.1, Scanner 4, Plugin, and any relevant extension)
  • what are you trying to achieve
    Pull request decoration with Bitbucket server
  • what have you tried so far to achieve this
    PR Decoration requires passing the below information to sonarscanner (as per the documentation here )
Parameter Name Description
sonar.pullrequest.key Unique identifier of your PR. Must correspond to the key of the PR in GitHub or Azure DevOps. e.g.: sonar.pullrequest.key=5
sonar.pullrequest.branch The name of the branch that contains the changes to be merged. e.g.: sonar.pullrequest.branch=feature/my-new-feature
sonar.pullrequest.base The branch into which the PR will be merged. Default: master e.g.: sonar.pullrequest.base=master

I have been able to achieve pull request decoration in test configurations after hard coding the above information in my build step. How can we receive those information automatically for every PR?

Greetings,

What CI tool are you typically using (Jenkins? Travis? Something else?) – for many tools, this is done automatically by detecting environment variables related to your pull request.

Best regards,

Colin

1 Like

We use Jenkins and we created the following Jenkins Library functions (I inline utils classes):

import org.apache.commons.lang.StringUtils

def call(def parameters) {
	def mode = parameters['mode'] ?: (env.CHANGE_BRANCH == null ? 'branch' : 'pullRequest')

	def params = mode == 'branch' ? createBranchParameters(parameters) : createPullRequestParameters(parameters)
	return params.join(' ')
}

List<String> createBranchParameters(def parameters) {
	def mainBranch = requireNonBlank('mainBranch', parameters['mainBranch'])
	def branch = requireNonBlank('branch', parameters['branch'] ?: env.BRANCH_NAME)

	return branch == mainBranch ? [] : ["-Dsonar.branch.name=${branch}"]
}

List<String> createPullRequestParameters(def parameters) {
	def key = requireNonBlank('key', parameters['key'] ?: env.CHANGE_ID)
	def branch = requireNonBlank('branch', parameters['branch'] ?: env.CHANGE_BRANCH)
	def base = requireNonBlank('base', parameters['base'] ?: env.CHANGE_TARGET)

	return [
		"-Dsonar.pullrequest.key=${key}",
		"-Dsonar.pullrequest.branch=${branch}",
		"-Dsonar.pullrequest.base=${base}"
	]
}

private <T> T requireNonBlank(CharSequence name, T obj) {
	def text = obj as String

	if (StringUtils.isNotBlank(text)) {
		return obj
	}

	def valueType
	if (text == null) {
		valueType = 'null'
	} else if (text == '') {
		valueType = 'empty string'
	} else {
		valueType = 'text with only whitespace characters'
	}
	error "${name} cannot be blank! Its value: ${valueType}"
}