1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

Merge branch 'master' into pr/DoNotReturnWrongValueIfOnlyAPartOfAPathCanBeResolved

This commit is contained in:
Christopher Fenner 2019-05-15 10:16:09 +02:00 committed by GitHub
commit 2fed3f231f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 681 additions and 28 deletions

View File

@ -25,15 +25,15 @@ none
## Exceptions
* `Exception`:
* If `source` is not provided.
* If `propertiesFile` is not provided (when using `'WAR_PROPERTIESFILE'` deployment mode).
* If `application` is not provided (when using `'WAR_PARAMS'` deployment mode).
* If `runtime` is not provided (when using `'WAR_PARAMS'` deployment mode).
* If `runtimeVersion` is not provided (when using `'WAR_PARAMS'` deployment mode).
* If `source` is not provided.
* If `propertiesFile` is not provided (when using `'WAR_PROPERTIESFILE'` deployment mode).
* If `application` is not provided (when using `'WAR_PARAMS'` deployment mode).
* If `runtime` is not provided (when using `'WAR_PARAMS'` deployment mode).
* If `runtimeVersion` is not provided (when using `'WAR_PARAMS'` deployment mode).
* `AbortException`:
* If neo-java-web-sdk is not installed, or `neoHome`is wrong.
* If neo-java-web-sdk is not installed, or `neoHome`is wrong.
* `CredentialNotFoundException`:
* If the credentials cannot be resolved.
* If the credentials cannot be resolved.
## Example

View File

@ -0,0 +1,18 @@
# ${docGenStepName}
## ${docGenDescription}
## Prerequsites
- The project needs a `sonar-project.properties` file that describes the project and defines certain settings, see [here](https://docs.sonarqube.org/display/SCAN/Advanced+SonarQube+Scanner+Usages#AdvancedSonarQubeScannerUsages-Multi-moduleProjectStructure).
- A SonarQube instance needs to be defined in the Jenkins.
## ${docGenParameters}
## ${docGenConfiguration}
## Exceptions
none
## Examples

View File

@ -10,6 +10,7 @@ nav:
- cloudFoundryDeploy: steps/cloudFoundryDeploy.md
- commonPipelineEnvironment: steps/commonPipelineEnvironment.md
- containerExecuteStructureTests: steps/containerExecuteStructureTests.md
- detectExecuteScan: steps/detectExecuteScan.md
- dockerExecute: steps/dockerExecute.md
- dockerExecuteOnKubernetes: steps/dockerExecuteOnKubernetes.md
- durationMeasure: steps/durationMeasure.md
@ -36,6 +37,7 @@ nav:
- setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md
- slackSendNotification: steps/slackSendNotification.md
- snykExecute: steps/snykExecute.md
- sonarExecuteScan: steps/sonarExecuteScan.md
- testsPublishResults: steps/testsPublishResults.md
- transportRequestCreate: steps/transportRequestCreate.md
- transportRequestRelease: steps/transportRequestRelease.md

View File

@ -1,4 +1,8 @@
stages:
Init:
stepConditions:
slackSendNotification:
config: 'channel'
'Pull-Request Voting': {}
Build: {}
'Additional Unit Tests': {}
@ -18,3 +22,7 @@ stages:
Compliance: {}
Promote: {}
Release: {}
'Post Actions':
stepConditions:
slackSendNotification:
config: 'channel'

View File

@ -463,6 +463,12 @@ steps:
- 'opensourceConfiguration'
toJson: false
toHtml: false
sonarExecuteScan:
dockerImage: 'maven:3.5-jdk-8'
instance: 'SonarCloud'
options: []
pullRequestProvider: 'github'
sonarScannerDownloadUrl: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.3.0.1492-linux.zip'
testsPublishResults:
failOnError: false
junit:

View File

@ -386,11 +386,7 @@ class NeoDeployTest extends BasePiperTest {
deployMode: 'warPropertiesFile',
warAction: 'deploy',
neo: [
propertiesFile: warPropertiesFileName,
application: 'testApp',
runtime: 'neo-javaee6-wp',
runtimeVersion: '2.125',
size: 'lite'
propertiesFile: warPropertiesFileName
]
)
@ -412,11 +408,7 @@ class NeoDeployTest extends BasePiperTest {
deployMode: 'warPropertiesFile',
warAction: 'rolling-update',
neo: [
propertiesFile: warPropertiesFileName,
application: 'testApp',
runtime: 'neo-javaee6-wp',
runtimeVersion: '2.125',
size: 'lite'
propertiesFile: warPropertiesFileName
])
Assert.assertThat(shellRule.shell,

View File

@ -0,0 +1,122 @@
#!groovy
package stages
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import util.BasePiperTest
import util.JenkinsLoggingRule
import util.JenkinsReadYamlRule
import util.JenkinsStepRule
import util.Rules
import static org.hamcrest.Matchers.*
import static org.junit.Assert.assertThat
class PiperPipelineStageInitTest extends BasePiperTest {
private JenkinsStepRule jsr = new JenkinsStepRule(this)
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
private ExpectedException thrown = ExpectedException.none()
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(new JenkinsReadYamlRule(this))
.around(thrown)
.around(jlr)
.around(jsr)
private List stepsCalled = []
@Before
void init() {
binding.variables.env.STAGE_NAME = 'Init'
binding.setVariable('scm', {})
helper.registerAllowedMethod('deleteDir', [], null)
helper.registerAllowedMethod("findFiles", [Map.class], { map ->
switch (map.glob) {
case 'pom.xml':
return [new File('pom.xml')].toArray()
default:
return [].toArray()
}
})
helper.registerAllowedMethod('piperStageWrapper', [Map.class, Closure.class], {m, body ->
assertThat(m.stageName, is('Init'))
return body()
})
helper.registerAllowedMethod('checkout', [Closure.class], {c ->
stepsCalled.add('checkout')
return [
GIT_COMMIT: 'abcdef12345',
GIT_URL: 'some.url'
]
})
helper.registerAllowedMethod('setupCommonPipelineEnvironment', [Map.class], {m -> stepsCalled.add('setupCommonPipelineEnvironment')})
helper.registerAllowedMethod('piperInitRunStageConfiguration', [Map.class], {m -> stepsCalled.add('piperInitRunStageConfiguration')})
helper.registerAllowedMethod('slackSendNotification', [Map.class], {m -> stepsCalled.add('slackSendNotification')})
helper.registerAllowedMethod('artifactSetVersion', [Map.class], {m -> stepsCalled.add('artifactSetVersion')})
helper.registerAllowedMethod('pipelineStashFilesBeforeBuild', [Map.class], {m -> stepsCalled.add('pipelineStashFilesBeforeBuild')})
}
@Test
void testInitNoBuildTool() {
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR buildTool')
jsr.step.piperPipelineStageInit(script: nullScript, juStabUtils: utils)
}
@Test
void testInitBuildToolDoesNotMatchProject() {
thrown.expect(hudson.AbortException)
thrown.expectMessage(containsString("buildTool configuration 'npm' does not fit to your project"))
jsr.step.piperPipelineStageInit(script: nullScript, juStabUtils: utils, buildTool: 'npm')
}
@Test
void testInitDefault() {
jsr.step.piperPipelineStageInit(script: nullScript, juStabUtils: utils, buildTool: 'maven')
assertThat(stepsCalled, hasItems(
'checkout',
'setupCommonPipelineEnvironment',
'piperInitRunStageConfiguration',
'artifactSetVersion',
'pipelineStashFilesBeforeBuild'
))
assertThat(stepsCalled, not(hasItems('slackSendNotification')))
}
@Test
void testInitNotOnProductiveBranch() {
binding.variables.env.BRANCH_NAME = 'anyOtherBranch'
jsr.step.piperPipelineStageInit(script: nullScript, juStabUtils: utils, buildTool: 'maven')
assertThat(stepsCalled, hasItems(
'checkout',
'setupCommonPipelineEnvironment',
'piperInitRunStageConfiguration',
'pipelineStashFilesBeforeBuild'
))
assertThat(stepsCalled, not(hasItems('artifactSetVersion')))
}
@Test
void testInitWithSlackNotification() {
nullScript.commonPipelineEnvironment.configuration = [runStep: [Init: [slackSendNotification: true]]]
jsr.step.piperPipelineStageInit(script: nullScript, juStabUtils: utils, buildTool: 'maven')
assertThat(stepsCalled, hasItems(
'checkout',
'setupCommonPipelineEnvironment',
'piperInitRunStageConfiguration',
'artifactSetVersion',
'slackSendNotification',
'pipelineStashFilesBeforeBuild'
))
}
}

View File

@ -0,0 +1,69 @@
#!groovy
package stages
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import util.BasePiperTest
import util.JenkinsReadYamlRule
import util.JenkinsStepRule
import util.Rules
import static org.hamcrest.Matchers.*
import static org.junit.Assert.assertThat
class PiperPipelineStagePostTest extends BasePiperTest {
private JenkinsStepRule jsr = new JenkinsStepRule(this)
private ExpectedException thrown = ExpectedException.none()
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(new JenkinsReadYamlRule(this))
.around(thrown)
.around(jsr)
private List stepsCalled = []
@Before
void init() {
binding.variables.env.STAGE_NAME = 'Release'
helper.registerAllowedMethod('piperStageWrapper', [Map.class, Closure.class], {m, body ->
assertThat(m.stageName, is('Release'))
return body()
})
helper.registerAllowedMethod('influxWriteData', [Map.class], {m -> stepsCalled.add('influxWriteData')})
helper.registerAllowedMethod('slackSendNotification', [Map.class], {m -> stepsCalled.add('slackSendNotification')})
helper.registerAllowedMethod('mailSendNotification', [Map.class], {m -> stepsCalled.add('mailSendNotification')})
}
@Test
void testPostDefault() {
jsr.step.piperPipelineStagePost(script: nullScript, juStabUtils: utils)
assertThat(stepsCalled, hasItems('influxWriteData','mailSendNotification'))
assertThat(stepsCalled, not(hasItems('slackSendNotification')))
}
@Test
void testPostNotOnProductiveBranch() {
binding.variables.env.BRANCH_NAME = 'anyOtherBranch'
jsr.step.piperPipelineStagePost(script: nullScript, juStabUtils: utils)
assertThat(stepsCalled, hasItems('influxWriteData','mailSendNotification'))
assertThat(stepsCalled, not(hasItems('slackSendNotification')))
}
@Test
void testPostWithSlackNotification() {
nullScript.commonPipelineEnvironment.configuration = [runStep: ['Post Actions': [slackSendNotification: true]]]
jsr.step.piperPipelineStagePost(script: nullScript, juStabUtils: utils)
assertThat(stepsCalled, hasItems('influxWriteData','mailSendNotification','slackSendNotification'))
}
}

View File

@ -0,0 +1,237 @@
import static org.hamcrest.Matchers.containsString
import static org.hamcrest.Matchers.hasItem
import static org.hamcrest.Matchers.is
import static org.hamcrest.Matchers.allOf
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.rules.ExpectedException
import static org.junit.Assert.assertThat
import util.BasePiperTest
import util.JenkinsDockerExecuteRule
import util.JenkinsShellCallRule
import util.JenkinsReadYamlRule
import util.JenkinsStepRule
import util.JenkinsLoggingRule
import util.Rules
class SonarExecuteScanTest extends BasePiperTest {
private ExpectedException thrown = ExpectedException.none()
private JenkinsReadYamlRule readYamlRule = new JenkinsReadYamlRule(this)
private JenkinsStepRule jsr = new JenkinsStepRule(this)
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
private JenkinsDockerExecuteRule jedr = new JenkinsDockerExecuteRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(readYamlRule)
.around(thrown)
.around(jedr)
.around(jscr)
.around(jlr)
.around(jsr)
def sonarInstance
@Before
void init() throws Exception {
sonarInstance = null
helper.registerAllowedMethod("withSonarQubeEnv", [String.class, Closure.class], { string, closure ->
sonarInstance = string
return closure()
})
helper.registerAllowedMethod("unstash", [String.class], { stashInput -> return []})
helper.registerAllowedMethod("fileExists", [String.class], { file -> return file })
helper.registerAllowedMethod('string', [Map], { m -> m })
helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
try {
binding.setProperty(l[0].variable, 'TOKEN_'+l[0].credentialsId)
c()
} finally {
binding.setProperty(l[0].variable, null)
}
})
nullScript.commonPipelineEnvironment.setArtifactVersion('1.2.3-20180101')
}
@Test
void testWithDefaults() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils
)
// asserts
assertThat('Sonar instance is not set to the default value', sonarInstance, is('SonarCloud'))
assertThat('Sonar project version is not set to the default value', jscr.shell, hasItem(containsString('sonar-scanner -Dsonar.projectVersion=1')))
assertThat('Docker image is not set to the default value', jedr.dockerParams.dockerImage, is('maven:3.5-jdk-8'))
assertJobStatusSuccess()
}
@Test
void testWithCustomVersion() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
projectVersion: '2'
)
// asserts
assertThat('Sonar project version is not set to the custom value', jscr.shell, hasItem(containsString('sonar-scanner -Dsonar.projectVersion=2')))
assertJobStatusSuccess()
}
@Test
void testWithCustomOptions() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
options: '-Dsonar.host.url=localhost'
)
// asserts
assertThat('Sonar options are not set to the custom value', jscr.shell, hasItem(containsString('sonar-scanner -Dsonar.host.url=localhost')))
assertJobStatusSuccess()
}
@Test
void testWithCustomOptionsList() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
options: ['sonar.host.url=localhost']
)
// asserts
assertThat('Sonar options are not set to the custom value', jscr.shell, hasItem(containsString('sonar-scanner -Dsonar.host.url=localhost')))
assertJobStatusSuccess()
}
@Test
void testWithCustomInstance() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
instance: 'MySonarInstance'
)
// asserts
assertThat('Sonar instance is not set to the custom value', sonarInstance.toString(), is('MySonarInstance'))
assertJobStatusSuccess()
}
@Test
void testWithPRHandling() throws Exception {
binding.setVariable('env', [
'CHANGE_ID': '42',
'CHANGE_TARGET': 'master',
'BRANCH_NAME': 'feature/anything'
])
nullScript.commonPipelineEnvironment.setGithubOrg('testOrg')
//nullScript.commonPipelineEnvironment.setGithubRepo('testRepo')
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
//githubOrg: 'testOrg',
githubRepo: 'testRepo'
)
// asserts
assertThat(jscr.shell, hasItem(allOf(
containsString('-Dsonar.pullrequest.key=42'),
containsString('-Dsonar.pullrequest.base=master'),
containsString('-Dsonar.pullrequest.branch=feature/anything'),
containsString('-Dsonar.pullrequest.provider=github'),
containsString('-Dsonar.pullrequest.github.repository=testOrg/testRepo')
)))
assertJobStatusSuccess()
}
@Test
void testWithPRHandlingWithoutMandatory() throws Exception {
thrown.expect(Exception)
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR githubRepo')
binding.setVariable('env', ['CHANGE_ID': '42'])
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
githubOrg: 'testOrg'
)
// asserts
assertJobStatusFailure()
}
@Test
void testWithLegacyPRHandling() throws Exception {
binding.setVariable('env', ['CHANGE_ID': '42'])
nullScript.commonPipelineEnvironment.setGithubOrg('testOrg')
//nullScript.commonPipelineEnvironment.setGithubRepo('testRepo')
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
legacyPRHandling: true,
githubTokenCredentialsId: 'githubId',
//githubOrg: 'testOrg',
githubRepo: 'testRepo'
)
// asserts
assertThat(jscr.shell, hasItem(allOf(
containsString('-Dsonar.analysis.mode=preview'),
containsString('-Dsonar.github.pullRequest=42'),
containsString('-Dsonar.github.oauth=TOKEN_githubId'),
containsString('-Dsonar.github.repository=testOrg/testRepo')
)))
assertJobStatusSuccess()
}
@Test
void testWithLegacyPRHandlingWithoutMandatory() throws Exception {
thrown.expect(Exception)
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR githubTokenCredentialsId')
binding.setVariable('env', ['CHANGE_ID': '42'])
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
legacyPRHandling: true,
githubOrg: 'testOrg',
githubRepo: 'testRepo'
)
// asserts
assertJobStatusFailure()
}
@Test
void testWithSonarAuth() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
sonarTokenCredentialsId: 'githubId'
)
// asserts
assertThat(jscr.shell, hasItem(containsString('-Dsonar.login=TOKEN_githubId')))
assertJobStatusSuccess()
}
@Test
void testWithSonarCloudOrganization() throws Exception {
jsr.step.sonarExecuteScan(
script: nullScript,
juStabUtils: utils,
organization: 'TestOrg-github'
)
// asserts
assertThat(jscr.shell, hasItem(containsString('-Dsonar.organization=TestOrg-github')))
assertJobStatusSuccess()
}
}

View File

@ -41,7 +41,8 @@ class JenkinsSetupRule implements TestRule {
JOB_NAME : 'p',
BUILD_NUMBER: '1',
BUILD_URL : 'http://build.url',
BRANCH_NAME: 'master'
BRANCH_NAME: 'master',
WORKSPACE: 'any/path'
])
base.evaluate()

View File

@ -236,14 +236,12 @@ private deploy(script, utils, Map configuration, NeoCommandHelper neoCommandHelp
}
catch (Exception ex) {
if (dockerImage) {
echo "Error while deploying to SAP Cloud Platform. Here are the neo.sh logs:"
try {
sh "cat logs/neo/*"
} catch(Exception e) {
echo "Unable to provide the logs."
ex.addSuppressed(e)
}
echo "Error while deploying to SAP Cloud Platform. Here are the neo.sh logs:"
try {
sh "cat logs/neo/*"
} catch(Exception e) {
echo "Unable to provide the logs."
ex.addSuppressed(e)
}
throw ex
}

View File

@ -55,11 +55,12 @@ void call(Map parameters = [:]) {
piperInitRunStageConfiguration script: script, stageConfigResource: config.stageConfigResource
if (env.BRANCH_NAME == config.productiveBranch) {
if (parameters.script.commonPipelineEnvironment.configuration.runStep?.get('Init')?.slackSendNotification) {
slackSendNotification script: script, message: "STARTED: Job <${env.BUILD_URL}|${URLDecoder.decode(env.JOB_NAME, java.nio.charset.StandardCharsets.UTF_8.name())} ${env.BUILD_DISPLAY_NAME}>", color: 'WARNING'
}
artifactSetVersion script: script
}
pipelineStashFilesBeforeBuild script: script
}
}

View File

@ -40,6 +40,12 @@ void call(Map parameters = [:]) {
utils.pushToSWA([step: STEP_NAME], config)
influxWriteData script: script
if(env.BRANCH_NAME == parameters.script.commonPipelineEnvironment.getStepConfiguration('', '').productiveBranch) {
if(parameters.script.commonPipelineEnvironment.configuration.runStep?.get('Post Actions')?.slackSendNotification) {
slackSendNotification script: parameters.script
}
}
mailSendNotification script: script
}
}

View File

@ -0,0 +1,193 @@
import com.sap.piper.ConfigurationHelper
import com.sap.piper.GenerateDocumentation
import com.sap.piper.Utils
import static com.sap.piper.Prerequisites.checkScript
import groovy.transform.Field
import groovy.text.SimpleTemplateEngine
@Field String STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = [
/**
* Pull-Request voting only:
* The URL to the Github API. see https://docs.sonarqube.org/display/PLUG/GitHub+Plugin#GitHubPlugin-Usage
* deprecated: only supported in LTS / < 7.2
*/
'githubApiUrl',
/**
* Pull-Request voting only:
* The Github organization.
* @default: `commonPipelineEnvironment.getGithubOrg()`
*/
'githubOrg',
/**
* Pull-Request voting only:
* The Github repository.
* @default: `commonPipelineEnvironment.getGithubRepo()`
*/
'githubRepo',
/**
* Pull-Request voting only:
* The Jenkins credentialId for a Github token. It is needed to report findings back to the pull-request.
* deprecated: only supported in LTS / < 7.2
* @possibleValues Jenkins credential id
*/
'githubTokenCredentialsId',
/**
* The Jenkins credentialsId for a SonarQube token. It is needed for non-anonymous analysis runs. see https://sonarcloud.io/account/security
* @possibleValues Jenkins credential id
*/
'sonarTokenCredentialsId',
]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
/**
* Pull-Request voting only:
* Disables the pull-request decoration with inline comments.
* deprecated: only supported in LTS / < 7.2
* @possibleValues `true`, `false`
*/
'disableInlineComments',
/**
* Name of the docker image that should be used. If empty, Docker is not used and the command is executed directly on the Jenkins system.
* see dockerExecute
*/
'dockerImage',
/**
* The name of the SonarQube instance defined in the Jenkins settings.
*/
'instance',
/**
* Pull-Request voting only:
* Activates the pull-request handling using the [GitHub Plugin](https://docs.sonarqube.org/display/PLUG/GitHub+Plugin) (deprecated).
* deprecated: only supported in LTS / < 7.2
* @possibleValues `true`, `false`
*/
'legacyPRHandling',
/**
* A list of options which are passed to the `sonar-scanner`.
*/
'options',
/**
* Organization that the project will be assigned to in SonarCloud.io.
*/
'organization',
/**
* The project version that is reported to SonarQube.
* @default: major number of `commonPipelineEnvironment.getArtifactVersion()`
*/
'projectVersion'
])
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
/**
* The step executes the [sonar-scanner](https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner) cli command to scan the defined sources and publish the results to a SonarQube instance.
*/
@GenerateDocumentation
void call(Map parameters = [:]) {
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
def utils = parameters.juStabUtils ?: new Utils()
def script = checkScript(this, parameters) ?: this
// load default & individual configuration
Map configuration = ConfigurationHelper.newInstance(this)
.loadStepDefaults()
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, GENERAL_CONFIG_KEYS)
.mixin(parameters, PARAMETER_KEYS)
.addIfEmpty('projectVersion', script.commonPipelineEnvironment.getArtifactVersion()?.tokenize('.')?.get(0))
.addIfEmpty('githubOrg', script.commonPipelineEnvironment.getGithubOrg())
.addIfEmpty('githubRepo', script.commonPipelineEnvironment.getGithubRepo())
// check mandatory parameters
.withMandatoryProperty('githubTokenCredentialsId', null, { config -> config.legacyPRHandling && isPullRequest() })
.withMandatoryProperty('githubOrg', null, { isPullRequest() })
.withMandatoryProperty('githubRepo', null, { isPullRequest() })
.use()
if(configuration.options instanceof String)
configuration.options = [].plus(configuration.options)
def worker = { config ->
withSonarQubeEnv(config.instance) {
loadSonarScanner(config)
if(config.organization) config.options.add("sonar.organization=${config.organization}")
if(config.projectVersion) config.options.add("sonar.projectVersion=${config.projectVersion}")
// prefix options
config.options = config.options.collect { it.startsWith('-D') ? it : "-D${it}" }
sh "PATH=\$PATH:${env.WORKSPACE}/.sonar-scanner/bin sonar-scanner ${config.options.join(' ')}"
}
}
if(configuration.sonarTokenCredentialsId){
def workerForSonarAuth = worker
worker = { config ->
withCredentials([string(
credentialsId: config.sonarTokenCredentialsId,
variable: 'SONAR_TOKEN'
)]){
config.options.add("sonar.login=$SONAR_TOKEN")
workerForSonarAuth(config)
}
}
}
if(isPullRequest()){
def workerForGithubAuth = worker
worker = { config ->
if(config.legacyPRHandling) {
withCredentials([string(
credentialsId: config.githubTokenCredentialsId,
variable: 'GITHUB_TOKEN'
)]){
// support for https://docs.sonarqube.org/display/PLUG/GitHub+Plugin
config.options.add('sonar.analysis.mode=preview')
config.options.add("sonar.github.oauth=$GITHUB_TOKEN")
config.options.add("sonar.github.pullRequest=${env.CHANGE_ID}")
config.options.add("sonar.github.repository=${config.githubOrg}/${config.githubRepo}")
if(config.githubApiUrl) config.options.add("sonar.github.endpoint=${config.githubApiUrl}")
if(config.disableInlineComments) config.options.add("sonar.github.disableInlineComments=${config.disableInlineComments}")
workerForGithubAuth(config)
}
} else {
// see https://sonarcloud.io/documentation/analysis/pull-request/
config.options.add("sonar.pullrequest.key=${env.CHANGE_ID}")
config.options.add("sonar.pullrequest.base=${env.CHANGE_TARGET}")
config.options.add("sonar.pullrequest.branch=${env.BRANCH_NAME}")
config.options.add("sonar.pullrequest.provider=${config.pullRequestProvider}")
switch(config.pullRequestProvider){
case 'github':
config.options.add("sonar.pullrequest.github.repository=${config.githubOrg}/${config.githubRepo}")
break;
default: error "Pull-Request provider '${config.pullRequestProvider}' is not supported!"
}
workerForGithubAuth(config)
}
}
}
dockerExecute(
script: script,
dockerImage: configuration.dockerImage
){
worker(configuration)
}
}
}
private Boolean isPullRequest(){
return env.CHANGE_ID
}
private void loadSonarScanner(config){
def filename = new File(config.sonarScannerDownloadUrl).getName()
def foldername = filename.replace('.zip', '').replace('cli-', '')
sh """
curl --remote-name --remote-header-name --location --silent --show-error ${config.sonarScannerDownloadUrl}
unzip -q ${filename}
mv ${foldername} .sonar-scanner
"""
}