Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Slack/Teams notifications #43

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions assets/slackreport.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could you rename this as .j2.json, just to know that it is a template while browsing the file tree? (not critical, feel free to disregard)

"attachments": [
{
"fallback": "Plain-text summary of the attachment.",
"color": "<% if (success) { %>good<% } else { %>danger<%} %>",
"author_name": "TalusBio/nf-encyclopedia - ${runName}",
"author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico",
"text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>",
"fields": [
{
"title": "Command used to launch the workflow",
"value": "```${commandLine}```",
"short": false
}
<%
if (!success) { %>
,
{
"title": "Full error message",
"value": "```${errorReport}```",
"short": false
},
{
"title": "Pipeline configuration",
"value": "<% out << summary.collect{ k,v -> k == "hook_url" ? "_${k}_: (_hidden_)" : ( ( v.class.toString().contains('Path') || ( v.class.toString().contains('String') && v.contains('/') ) ) ? "_${k}_: `${v}`" : (v.class.toString().contains('DateTime') ? ("_${k}_: " + v.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM))) : "_${k}_: ${v}") ) }.join(",\n") %>",
"short": false
}
<% }
%>
],
"footer": "Completed at <% out << dateComplete.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)) %> (duration: ${duration})"
}
]
}
49 changes: 49 additions & 0 deletions lib/TalusTemplate.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,53 @@ class TalusTemplate {
def email_html = html_template.toString()
return [subject, email_html]
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: This looks very clean

//
// Construct and send a notification to a web server as JSON
// e.g. Microsoft Teams and Slack
//
public static void IM_notification(workflow, params, projectDir) {
def hook_url = params.hook_url
def misc_fields = [:]
misc_fields['start'] = workflow.start
misc_fields['complete'] = workflow.complete
misc_fields['scriptfile'] = workflow.scriptFile
misc_fields['scriptid'] = workflow.scriptId
if (workflow.repository) misc_fields['repository'] = workflow.repository
if (workflow.commitId) misc_fields['commitid'] = workflow.commitId
if (workflow.revision) misc_fields['revision'] = workflow.revision
misc_fields['nxf_version'] = workflow.nextflow.version
misc_fields['nxf_build'] = workflow.nextflow.build
misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp

def summary = [:]
def msg_fields = [:]
msg_fields['runName'] = workflow.runName
msg_fields['success'] = workflow.success
msg_fields['dateComplete'] = workflow.complete
msg_fields['duration'] = workflow.duration
msg_fields['exitStatus'] = workflow.exitStatus
msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None')
msg_fields['errorReport'] = (workflow.errorReport ?: 'None')
msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "")
msg_fields['projectDir'] = workflow.projectDir
msg_fields['summary'] = summary << misc_fields

// Render the JSON template
def engine = new groovy.text.GStringTemplateEngine()
// Different JSON depending on the service provider
// Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format
def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json"
def hf = new File("$projectDir/assets/${json_path}")
def json_template = engine.createTemplate(hf).make(msg_fields)
def json_message = json_template.toString()

// POST
def post = new URL(hook_url).openConnection();
post.setRequestMethod("POST")
post.setDoOutput(true)
post.setRequestProperty("Content-Type", "application/json")
post.getOutputStream().write(json_message.getBytes("UTF-8"));
def postRC = post.getResponseCode();
}
}
15 changes: 14 additions & 1 deletion main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ def email() {
}


//
// Used for Slack notifications
//
def slack() {
if (params.hook_url) {
TalusTemplate.IM_notification(workflow, params, projectDir)
}
}


//
// Use the DLIB when the ELIB is unavailable.
//
Expand Down Expand Up @@ -133,4 +143,7 @@ workflow dummy {
}

// Email notifications:
workflow.onComplete { email() }
workflow.onComplete {
email()
slack()
}
1 change: 1 addition & 0 deletions nextflow.config
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ params {
report_dir = 'reports' /** \type{str} Where reports will be saved. */
mzml_dir = 'mzml' /** \type{str} Where mzML files will be saved. */
email = null /** \type{str} An email to alert on completion. */
hook_url = null /** \type{str} A URL for Slack notifications */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you link the slack docs to know how to get one? :D please...


/** \group{Grouping Parameters} */
/** \type{boolean}
Expand Down