From 22e42daf1bd15e11580d7c98dd54f1f6dd9288a5 Mon Sep 17 00:00:00 2001 From: adamrtalbot <12817534+adamrtalbot@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:45:54 +0100 Subject: [PATCH 1/3] feat: replace webhook notifications with nf-slack plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the custom webhook-based instant message system with the nf-slack plugin for improved Slack notifications. This change provides automatic workflow lifecycle notifications with enhanced features. Changes: - Add nf-slack plugin (v0.1.0) to nextflow.config - Configure automatic notifications for start, complete, and error events - Remove custom imNotification function and webhook templates - Remove hook_url parameter from pipeline configuration - Update README with Slack notification setup instructions Benefits: - Automatic notifications without manual coding - Built-in support for resource usage statistics - Fail-safe operation that never fails the workflow - Cleaner codebase with ~60 lines of code removed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 23 +++++++ assets/adaptivecard.json | 67 ------------------- assets/slackreport.json | 34 ---------- main.nf | 1 - nextflow.config | 15 ++++- nextflow_schema.json | 7 -- .../local/utils_nfcore_demo_pipeline/main.nf | 5 -- .../nf-core/utils_nfcore_pipeline/main.nf | 64 ------------------ 8 files changed, 37 insertions(+), 179 deletions(-) delete mode 100644 assets/adaptivecard.json delete mode 100644 assets/slackreport.json diff --git a/README.md b/README.md index 4f3b6e0..6a95557 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,29 @@ nextflow run nf-core/demo \ For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/demo/usage) and the [parameter documentation](https://nf-co.re/demo/parameters). +## Slack Notifications + +The pipeline includes automatic Slack notifications via the nf-slack plugin. To enable Slack notifications: + +1. Create a Slack incoming webhook in your workspace: + - Go to your Slack workspace settings + - Navigate to "Apps" → "Incoming Webhooks" + - Create a new webhook and copy the URL + +2. Set the webhook URL as an environment variable: + ```bash + export SLACK_WEBHOOK_URL='https://hooks.slack.com/services/YOUR/WEBHOOK/URL' + ``` + +3. Run your pipeline normally - notifications will be sent automatically: + - Pipeline start notification + - Pipeline completion notification (with task statistics) + - Pipeline failure notification (with error details) + +The plugin is configured to include command line details and resource usage statistics in the notifications. You can customize the notification settings in `nextflow.config` under the `slack` configuration block. + +For more information about the nf-slack plugin, visit the [nf-slack repository](https://github.com/seqeralabs/nf-slack). + ## Pipeline output To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/demo/results) tab on the nf-core website pipeline page. diff --git a/assets/adaptivecard.json b/assets/adaptivecard.json deleted file mode 100644 index 72be61c..0000000 --- a/assets/adaptivecard.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "type": "message", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.adaptive", - "contentUrl": null, - "content": { - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "msteams": { - "width": "Full" - }, - "type": "AdaptiveCard", - "version": "1.2", - "body": [ - { - "type": "TextBlock", - "size": "Large", - "weight": "Bolder", - "color": "<% if (success) { %>Good<% } else { %>Attention<%} %>", - "text": "nf-core/demo v${version} - ${runName}", - "wrap": true - }, - { - "type": "TextBlock", - "spacing": "None", - "text": "Completed at ${dateComplete} (duration: ${duration})", - "isSubtle": true, - "wrap": true - }, - { - "type": "TextBlock", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors. The full error message was: ${errorReport}.<% } %>", - "wrap": true - }, - { - "type": "TextBlock", - "text": "The command used to launch the workflow was as follows:", - "wrap": true - }, - { - "type": "TextBlock", - "text": "${commandLine}", - "isSubtle": true, - "wrap": true - } - ], - "actions": [ - { - "type": "Action.ShowCard", - "title": "Pipeline Configuration", - "card": { - "type": "AdaptiveCard", - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "body": [ - { - "type": "FactSet", - "facts": [<% out << summary.collect{ k,v -> "{\"title\": \"$k\", \"value\" : \"$v\"}"}.join(",\n") %> - ] - } - ] - } - } - ] - } - } - ] -} diff --git a/assets/slackreport.json b/assets/slackreport.json deleted file mode 100644 index 3b478ac..0000000 --- a/assets/slackreport.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "attachments": [ - { - "fallback": "Plain-text summary of the attachment.", - "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "nf-core/demo ${version} - ${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})" - } - ] -} diff --git a/main.nf b/main.nf index 88ebe1d..48dc0fc 100644 --- a/main.nf +++ b/main.nf @@ -89,7 +89,6 @@ workflow { params.plaintext_email, params.outdir, params.monochrome_logs, - params.hook_url, NFCORE_DEMO.out.multiqc_report ) } diff --git a/nextflow.config b/nextflow.config index 7cca8e8..0a4658e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -34,7 +34,6 @@ params { email_on_fail = null plaintext_email = false monochrome_logs = false - hook_url = null help = false help_full = false show_hidden = false @@ -273,6 +272,20 @@ manifest { // Nextflow plugins plugins { id 'nf-schema@2.3.0' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-slack@0.1.0' // Slack notifications for workflow events +} + +// Slack notification configuration +slack { + enabled = true + webhook = System.getenv('SLACK_WEBHOOK_URL') + notifyOnStart = true + notifyOnComplete = true + notifyOnError = true + username = 'Nextflow Bot' + iconEmoji = ':rocket:' + includeCommandLine = true + includeResourceUsage = true } validation { diff --git a/nextflow_schema.json b/nextflow_schema.json index f47c237..d6eebff 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -193,13 +193,6 @@ "fa_icon": "fas fa-palette", "hidden": true }, - "hook_url": { - "type": "string", - "description": "Incoming hook URL for messaging service", - "fa_icon": "fas fa-broadcast-tower", - "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", - "hidden": true - }, "multiqc_config": { "type": "string", "format": "file-path", diff --git a/subworkflows/local/utils_nfcore_demo_pipeline/main.nf b/subworkflows/local/utils_nfcore_demo_pipeline/main.nf index b34c81f..16bea4e 100644 --- a/subworkflows/local/utils_nfcore_demo_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_demo_pipeline/main.nf @@ -13,7 +13,6 @@ include { paramsSummaryMap } from 'plugin/nf-schema' include { samplesheetToList } from 'plugin/nf-schema' include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' @@ -111,7 +110,6 @@ workflow PIPELINE_COMPLETION { plaintext_email // boolean: Send plain-text email instead of HTML outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications multiqc_report // string: Path to MultiQC report main: @@ -135,9 +133,6 @@ workflow PIPELINE_COMPLETION { } completionSummary(monochrome_logs) - if (hook_url) { - imNotification(summary_params, hook_url) - } } workflow.onError { diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index bfd2587..981660b 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - 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 msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - 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("${workflow.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() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} From 504bd78a873d15bc575c34d2845efb7b290ce88f Mon Sep 17 00:00:00 2001 From: adamrtalbot <12817534+adamrtalbot@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:47:52 +0100 Subject: [PATCH 2/3] prettier fixup --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6a95557..3d49a0a 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,13 @@ For more details and further functionality, please refer to the [usage documenta The pipeline includes automatic Slack notifications via the nf-slack plugin. To enable Slack notifications: 1. Create a Slack incoming webhook in your workspace: + - Go to your Slack workspace settings - Navigate to "Apps" → "Incoming Webhooks" - Create a new webhook and copy the URL 2. Set the webhook URL as an environment variable: + ```bash export SLACK_WEBHOOK_URL='https://hooks.slack.com/services/YOUR/WEBHOOK/URL' ``` From fb39227e0293910450ceb6cd67eb0095d5c79de4 Mon Sep 17 00:00:00 2001 From: adamrtalbot <12817534+adamrtalbot@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:02:10 +0100 Subject: [PATCH 3/3] Remove nf-slack instructions which should come from the plugin --- README.md | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/README.md b/README.md index 3d49a0a..4f3b6e0 100644 --- a/README.md +++ b/README.md @@ -61,31 +61,6 @@ nextflow run nf-core/demo \ For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/demo/usage) and the [parameter documentation](https://nf-co.re/demo/parameters). -## Slack Notifications - -The pipeline includes automatic Slack notifications via the nf-slack plugin. To enable Slack notifications: - -1. Create a Slack incoming webhook in your workspace: - - - Go to your Slack workspace settings - - Navigate to "Apps" → "Incoming Webhooks" - - Create a new webhook and copy the URL - -2. Set the webhook URL as an environment variable: - - ```bash - export SLACK_WEBHOOK_URL='https://hooks.slack.com/services/YOUR/WEBHOOK/URL' - ``` - -3. Run your pipeline normally - notifications will be sent automatically: - - Pipeline start notification - - Pipeline completion notification (with task statistics) - - Pipeline failure notification (with error details) - -The plugin is configured to include command line details and resource usage statistics in the notifications. You can customize the notification settings in `nextflow.config` under the `slack` configuration block. - -For more information about the nf-slack plugin, visit the [nf-slack repository](https://github.com/seqeralabs/nf-slack). - ## Pipeline output To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/demo/results) tab on the nf-core website pipeline page.