mirror of
https://github.com/SAP/jenkins-library.git
synced 2026-06-19 22:58:55 +02:00
add step slackSendNotification (#338)
* add step slackSendNotification This step allows to send Slack notifications in case of pipeline failures. * add SWA reporting * remove allowBuildFailure * add GENERAL_CONFIG_KEYS * update STEP_NAME * add missing import * fix MD findings * adjust rule name to be aligned with #455
This commit is contained in:
committed by
Christopher Fenner
parent
56d3a6ed97
commit
793df723cf
@@ -0,0 +1,73 @@
|
||||
# slackSendNotification
|
||||
|
||||
## Description
|
||||
|
||||
Sends notifications to the Slack channel about the build status.
|
||||
|
||||
Notification contains:
|
||||
|
||||
* Build status;
|
||||
* Repo Owner;
|
||||
* Repo Name;
|
||||
* Branch Name;
|
||||
* Jenkins Build Number;
|
||||
* Jenkins Build URL.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Installed and configured [Jenkins Slack plugin](https://github.com/jenkinsci/slack-plugin).
|
||||
|
||||
## Example
|
||||
|
||||
Usage of pipeline step:
|
||||
|
||||
```groovy
|
||||
try {
|
||||
stage('..') {..}
|
||||
stage('..') {..}
|
||||
stage('..') {..}
|
||||
currentBuild.result = 'SUCCESS'
|
||||
} catch (Throwable err) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw err
|
||||
} finally {
|
||||
stage('report') {
|
||||
slackSendNotification script: this
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|baseUrl|no|||
|
||||
|channel|no|||
|
||||
|color|no|`${buildStatus == 'SUCCESS'?'#008000':'#E60000'}`||
|
||||
|credentialsId|no|||
|
||||
|message|no|||
|
||||
|
||||
### Details
|
||||
|
||||
* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
|
||||
* `baseUrl` allows overriding the Slack Plugin Integration Base Url specified in the global configuration.
|
||||
* `color` defines the message color.
|
||||
* If `channel` is defined another than the default channel will be used.
|
||||
* `credentialsId` defines the Jenkins credentialId which holds the Slack token
|
||||
* With parameter `message` a custom message can be defined which is sent into the Slack channel.
|
||||
|
||||
## Step configuration
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|baseUrl||X|X|
|
||||
|channel||X|X|
|
||||
|color||X|X|
|
||||
|credentialsId||X|X|
|
||||
|message||X|X|
|
||||
@@ -30,6 +30,7 @@ nav:
|
||||
- prepareDefaultValues: steps/prepareDefaultValues.md
|
||||
- seleniumExecuteTests: steps/seleniumExecuteTests.md
|
||||
- setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md
|
||||
- slackSendNotification: steps/slackSendNotification.md
|
||||
- testsPublishResults: steps/testsPublishResults.md
|
||||
- toolValidate: steps/toolValidate.md
|
||||
- transportRequestCreate: steps/transportRequestCreate.md
|
||||
|
||||
@@ -305,6 +305,9 @@ steps:
|
||||
dockerImage: 'node:8-stretch'
|
||||
dockerName: 'npm'
|
||||
dockerWorkspace: '/home/node'
|
||||
slackSendNotification:
|
||||
color: "${buildStatus == 'SUCCESS'?'#008000':'#E60000'}"
|
||||
defaultMessage: "${buildStatus}: Job ${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}>"
|
||||
snykExecute:
|
||||
buildDescriptorFile: './package.json'
|
||||
dockerImage: 'node:8-stretch'
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#!groovy
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.RuleChain
|
||||
import util.BasePiperTest
|
||||
import util.JenkinsLoggingRule
|
||||
import util.JenkinsReadYamlRule
|
||||
import util.JenkinsStepRule
|
||||
import util.Rules
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class SlackSendNotificationTest extends BasePiperTest {
|
||||
def slackCallMap = [:]
|
||||
|
||||
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
||||
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain ruleChain = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(loggingRule)
|
||||
.around(stepRule)
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
helper.registerAllowedMethod("slackSend", [Map.class], {m -> slackCallMap = m})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationBuildSuccessDefaultChannel() throws Exception {
|
||||
stepRule.step.slackSendNotification(script: [currentBuild: [result: 'SUCCESS']])
|
||||
// asserts
|
||||
assertEquals('Message not set correctly', 'SUCCESS: Job p <http://build.url|#1>', slackCallMap.message.toString())
|
||||
assertNull('Channel not set correctly', slackCallMap.channel)
|
||||
assertEquals('Color not set correctly', '#008000', slackCallMap.color)
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationBuildSuccessCustomChannel() throws Exception {
|
||||
stepRule.step.slackSendNotification(script: [currentBuild: [result: 'SUCCCESS']], channel: 'Test')
|
||||
// asserts
|
||||
assertEquals('Channel not set correctly', 'Test', slackCallMap.channel)
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationBuildFailed() throws Exception {
|
||||
stepRule.step.slackSendNotification(script: [currentBuild: [result: 'FAILURE']])
|
||||
// asserts
|
||||
assertEquals('Message not set correctly', 'FAILURE: Job p <http://build.url|#1>', slackCallMap.message.toString())
|
||||
assertEquals('Color not set correctly', '#E60000', slackCallMap.color)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationBuildStatusNull() throws Exception {
|
||||
stepRule.step.slackSendNotification(script: [currentBuild: [:]])
|
||||
// asserts
|
||||
assertTrue('Missing build status not detected', loggingRule.log.contains('currentBuild.result is not set. Skipping Slack notification'))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationCustomMessageAndColor() throws Exception {
|
||||
stepRule.step.slackSendNotification(script: [currentBuild: [:]], message: 'Custom Message', color: '#AAAAAA')
|
||||
// asserts
|
||||
assertEquals('Custom message not set correctly', 'Custom Message', slackCallMap.message.toString())
|
||||
assertEquals('Custom color not set correctly', '#AAAAAA', slackCallMap.color)
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotificationWithCustomCredentials() throws Exception {
|
||||
stepRule.step.slackSendNotification(
|
||||
script: [currentBuild: [:]],
|
||||
message: 'I am no Message',
|
||||
baseUrl: 'https://my.base.url',
|
||||
credentialsId: 'MY_TOKEN_ID'
|
||||
)
|
||||
// asserts
|
||||
assertEquals('Custom base url not set correctly', 'https://my.base.url', slackCallMap.baseUrl)
|
||||
assertEquals('Custom token id not set correctly', 'MY_TOKEN_ID', slackCallMap.tokenCredentialId)
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import static com.sap.piper.Prerequisites.checkScript
|
||||
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.Utils
|
||||
import groovy.transform.Field
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = []
|
||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||
'baseUrl',
|
||||
'channel',
|
||||
'color',
|
||||
'credentialsId',
|
||||
'message'
|
||||
])
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
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 config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
def buildStatus = script.currentBuild.result
|
||||
// resolve templates
|
||||
config.color = SimpleTemplateEngine.newInstance().createTemplate(config.color).make([buildStatus: buildStatus]).toString()
|
||||
if (!config?.message){
|
||||
if (!buildStatus) {
|
||||
echo "[${STEP_NAME}] currentBuild.result is not set. Skipping Slack notification"
|
||||
return
|
||||
}
|
||||
config.message = SimpleTemplateEngine.newInstance().createTemplate(config.defaultMessage).make([buildStatus: buildStatus, env: env]).toString()
|
||||
}
|
||||
Map options = [:]
|
||||
if(config.credentialsId)
|
||||
options.put('tokenCredentialId', config.credentialsId)
|
||||
for(String entry : STEP_CONFIG_KEYS.minus('credentialsId'))
|
||||
if(config.get(entry))
|
||||
options.put(entry, config.get(entry))
|
||||
slackSend(options)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user