Skip to content

Commit

Permalink
feat(tasks): allow notifications for tasks (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
emjburns committed Oct 2, 2019
1 parent f5dfc29 commit c3d4e5b
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ abstract class AbstractEventNotificationAgent implements EchoEventListener {
String spinnakerUrl

static Map CONFIG = [
'orchestration': [
type: 'orchestration',
link: 'tasks'
],
'pipeline': [
type: 'pipeline',
link: 'executions/details'
Expand Down Expand Up @@ -83,7 +87,7 @@ abstract class AbstractEventNotificationAgent implements EchoEventListener {
}

// TODO (lpollo): why do we have a 'CANCELED' status and a canceled property, which are prime for inconsistency?
if (config.type == 'pipeline' &&
if (isExecution(config.type) &&
(event.content.execution?.status == 'CANCELED' || event.content.execution?.canceled == true)) {
return
}
Expand All @@ -95,10 +99,10 @@ abstract class AbstractEventNotificationAgent implements EchoEventListener {
def sendRequests = []

// pipeline level
if (config.type == 'pipeline') {
event.content?.execution.notifications?.each { notification ->
if (isExecution(config.type)) {
event.content?.execution?.notifications?.each { notification ->
String key = getNotificationType()
if (notification.type == key && notification?.when?.contains("$config.type.$status".toString())) {
if (notification.type == key && notification?.when?.contains("${config.type}.$status".toString())) {
sendRequests << notification
}
}
Expand All @@ -110,18 +114,26 @@ abstract class AbstractEventNotificationAgent implements EchoEventListener {
if (event.content?.context?.sendNotifications && ( !isSynthetic ) ) {
event.content?.context?.notifications?.each { notification ->
String key = getNotificationType()
if (notification.type == key && notification?.when?.contains("$config.type.$status".toString())) {
if (notification.type == key && notification?.when?.contains("${config.type}.$status".toString())) {
sendRequests << notification
}
}
}
}

sendRequests.each { notification ->
sendNotifications(notification, application, event, config, status)
try {
sendNotifications(notification, application, event, config, status)
} catch (Exception e) {
log.error('failed to send {} message ', notificationType ,e)
}
}
}

private boolean isExecution(String type) {
return type == "pipeline" || type == "orchestration"
}

abstract String getNotificationType()

abstract void sendNotifications(Map notification, String application, Event event, Map config, String status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,52 +49,47 @@ class BearychatNotificationAgent extends AbstractEventNotificationAgent {

@Override
void sendNotifications(Map preference, String application, Event event, Map config, String status) {
try {
String buildInfo = ''

if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """build #<a href="${event.content.execution.trigger.buildInfo.url}">${
event.content.execution.trigger.buildInfo.number as Integer
}</a> """
}
}
log.info('Sending bearychat message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))

String buildInfo = ''

String message = ''

if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
message = """Stage $stageName for """
if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """build #<a href="${event.content.execution.trigger.buildInfo.url}">${
event.content.execution.trigger.buildInfo.number as Integer
}</a> """
}
}
log.info('Sending bearychat message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))

String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"

message +=
"""${WordUtils.capitalize(application)}'s ${
event.content?.execution?.name ?: event.content?.execution?.description
} ${buildInfo} ${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}. To see more details, please visit: ${link}"""
String message = ''

String customMessage = event.content?.context?.customMessage
if (customMessage) {
message = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}
if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
message = """Stage $stageName for """
}

List<BearychatUserInfo> userList = bearychatService.getUserList(token)
String userid = userList.find {it.email == preference.address}.id
CreateP2PChannelResponse channelInfo = bearychatService.createp2pchannel(token,new CreateP2PChannelPara(user_id: userid))
String channelId = channelInfo.vchannel_id
bearychatService.sendMessage(token,new SendMessagePara(vchannel_id: channelId,
text: message,
attachments: "" ))
String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"

} catch (Exception e) {
log.error('failed to send bearychat message ', e)
message +=
"""${WordUtils.capitalize(application)}'s ${
event.content?.execution?.name ?: event.content?.execution?.description
} ${buildInfo} ${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}. To see more details, please visit: ${link}"""

String customMessage = event.content?.context?.customMessage
if (customMessage) {
message = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}

List<BearychatUserInfo> userList = bearychatService.getUserList(token)
String userid = userList.find {it.email == preference.address}.id
CreateP2PChannelResponse channelInfo = bearychatService.createp2pchannel(token,new CreateP2PChannelPara(user_id: userid))
String channelId = channelInfo.vchannel_id
bearychatService.sendMessage(token,new SendMessagePara(vchannel_id: channelId,
text: message,
attachments: "" ))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,59 +38,54 @@ public class GoogleChatNotificationAgent extends AbstractEventNotificationAgent

@Override
public void sendNotifications(Map preference, String application, Event event, Map config, String status) {
try {
String buildInfo = ''

if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """build #<a href="${event.content.execution.trigger.buildInfo.url}">${
event.content.execution.trigger.buildInfo.number as Integer
}</a> """
}
}

log.info('Sending Google Chat message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))

String body = ''
String buildInfo = ''

if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
body = """Stage $stageName for """
if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """build #<a href="${event.content.execution.trigger.buildInfo.url}">${
event.content.execution.trigger.buildInfo.number as Integer
}</a> """
}
}

String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"
log.info('Sending Google Chat message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))

body +=
"""${capitalize(application)}'s <a href="${link}">${
event.content?.execution?.name ?: event.content?.execution?.description
}</a> ${buildInfo}${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}"""
String body = ''

if (preference.message?."$config.type.$status"?.text) {
body += "\n\n" + preference.message."$config.type.$status".text
}
if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
body = """Stage $stageName for """
}

String customMessage = preference.customMessage ?: event.content?.context?.customMessage
if (customMessage) {
body = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}
String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"

// In Chat, users can only copy the whole link easily. We just extract the information from the whole link.
// Example: https://chat.googleapis.com/v1/spaces/{partialWebhookUrl}
String baseUrl = "https://chat.googleapis.com/v1/spaces/"
String completeLink = preference.address
String partialWebhookURL = completeLink.substring(baseUrl.length())
Response response = googleChatService.sendMessage(partialWebhookURL, new GoogleChatMessage(body))
body +=
"""${capitalize(application)}'s <a href="${link}">${
event.content?.execution?.name ?: event.content?.execution?.description
}</a> ${buildInfo}${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}"""

log.info("Received response from Google Chat: {} {} for execution id {}. {}",
response?.status, response?.reason, event.content?.execution?.id, response?.body)
if (preference.message?."$config.type.$status"?.text) {
body += "\n\n" + preference.message."$config.type.$status".text
}

} catch (Exception e) {
log.error('failed to send Google Chat message ', e)
String customMessage = preference.customMessage ?: event.content?.context?.customMessage
if (customMessage) {
body = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}

// In Chat, users can only copy the whole link easily. We just extract the information from the whole link.
// Example: https://chat.googleapis.com/v1/spaces/{partialWebhookUrl}
String baseUrl = "https://chat.googleapis.com/v1/spaces/"
String completeLink = preference.address
String partialWebhookURL = completeLink.substring(baseUrl.length())
Response response = googleChatService.sendMessage(partialWebhookURL, new GoogleChatMessage(body))

log.info("Received response from Google Chat: {} {} for execution id {}. {}",
response?.status, response?.reason, event.content?.execution?.id, response?.body)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,75 +46,70 @@ class SlackNotificationAgent extends AbstractEventNotificationAgent {

@Override
void sendNotifications(Map preference, String application, Event event, Map config, String status) {
try {
String buildInfo = ' '
String buildInfo = ' '

String color = '#CCCCCC'
String color = '#CCCCCC'

if (status == 'failed') {
color = '#B82525'
}
if (status == 'failed') {
color = '#B82525'
}

if (status == 'starting') {
color = '#2275B8'
}
if (status == 'starting') {
color = '#2275B8'
}

if (status == 'complete') {
color = '#769D3E'
}
if (status == 'complete') {
color = '#769D3E'
}

if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """ build <${event.content.execution.trigger.buildInfo.url}|${
event.content.execution.trigger.buildInfo.number as Integer
}> """
}
if (config.type == 'pipeline' || config.type == 'stage') {
if (event.content?.execution?.trigger?.buildInfo?.url) {
buildInfo = """ build <${event.content.execution.trigger.buildInfo.url}|${
event.content.execution.trigger.buildInfo.number as Integer
}> """
}
}

log.info('Sending Slack message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))
log.info('Sending Slack message {} for {} {} {} {}', kv('address', preference.address), kv('application', application), kv('type', config.type), kv('status', status), kv('executionId', event.content?.execution?.id))

String body = ''
String body = ''

if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
body = """Stage $stageName for """
}

String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"
if (config.type == 'stage') {
String stageName = event.content.name ?: event.content?.context?.stageDetails?.name
body = """Stage $stageName for """
}

body +=
"""${capitalize(application)}'s <${link}|${
event.content?.execution?.name ?: event.content?.execution?.description
}>${buildInfo}${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}"""
String link = "${spinnakerUrl}/#/applications/${application}/${config.type == 'stage' ? 'executions/details' : config.link }/${event.content?.execution?.id}"

if (preference.message?."$config.type.$status"?.text) {
body += "\n\n" + preference.message."$config.type.$status".text
}
body +=
"""${capitalize(application)}'s <${link}|${
event.content?.execution?.name ?: event.content?.execution?.description
}>${buildInfo}${config.type == 'task' ? 'task' : 'pipeline'} ${status == 'starting' ? 'is' : 'has'} ${
status == 'complete' ? 'completed successfully' : status
}"""

String customMessage = preference.customMessage ?: event.content?.context?.customMessage
if (customMessage) {
body = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}
if (preference.message?."$config.type.$status"?.text) {
body += "\n\n" + preference.message."$config.type.$status".text
}

String address = preference.address.startsWith('#') ? preference.address : "#${preference.address}"
String customMessage = preference.customMessage ?: event.content?.context?.customMessage
if (customMessage) {
body = customMessage
.replace("{{executionId}}", (String) event.content.execution?.id ?: "")
.replace("{{link}}", link ?: "")
}

Response response
if (sendCompactMessages) {
response = slackService.sendCompactMessage(token, new CompactSlackMessage(body, color), address, true)
} else {
String title = getNotificationTitle(config.type, application, status)
response = slackService.sendMessage(token, new SlackAttachment(title, body, color), address, true)
}
log.info("Received response from Slack: {} {} for execution id {}. {}",
response?.status, response?.reason, event.content?.execution?.id, response?.body)
String address = preference.address.startsWith('#') ? preference.address : "#${preference.address}"

} catch (Exception e) {
log.error('failed to send slack message ', e)
Response response
if (sendCompactMessages) {
response = slackService.sendCompactMessage(token, new CompactSlackMessage(body, color), address, true)
} else {
String title = getNotificationTitle(config.type, application, status)
response = slackService.sendMessage(token, new SlackAttachment(title, body, color), address, true)
}
log.info("Received response from Slack: {} {} for execution id {}. {}",
response?.status, response?.reason, event.content?.execution?.id, response?.body)
}

/**
Expand Down
Loading

0 comments on commit c3d4e5b

Please sign in to comment.