Skip to content
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
Binary file modified docs/images/nf-slack-00.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/nf-slack-examples-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/nf-slack-examples-02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/nf-slack-examples-03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/nf-slack-examples-04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/nf-slack-examples-05.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 24 additions & 21 deletions docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ Configuration for workflow start notifications.

#### Properties

| Property | Type | Default | Description |
| -------------------- | ------------- | ------------------------- | -------------------------------------- |
| `enabled` | Boolean | `true` | Send notification when workflow starts |
| `message` | String or Map | `'🚀 *Pipeline started*'` | Start notification message |
| `includeCommandLine` | Boolean | `true` | Include command line in message |
| `showFooter` | Boolean | `true` | Show timestamp footer in message |
| Property | Type | Default | Required | Description |
| -------------------- | ------------- | ------------------------- | -------- | ------------------------------------------------------ |
| `enabled` | Boolean | `true` | No | Send notification when workflow starts |
| `message` | String or Map | `'🚀 *Pipeline started*'` | No | Start notification message |
| `includeCommandLine` | Boolean | `true` | No | Include command line in message |
| `showFooter` | Boolean | `true` | No | Show timestamp footer in message |
| `channel` | String | `null` | No | Override channel for start notifications (Bot only) |

#### Message Available Fields

Expand Down Expand Up @@ -119,14 +120,15 @@ Configuration for workflow completion notifications.

#### Properties

| Property | Type | Default | Description |
| ---------------------- | -------------- | ---------------------------------------- | ------------------------------------------------------------- |
| `enabled` | Boolean | `true` | Send notification when workflow completes |
| `message` | String or Map | `'✅ *Pipeline completed successfully*'` | Completion notification message |
| `includeCommandLine` | Boolean | `true` | Include command line in message |
| `includeResourceUsage` | Boolean | `true` | Include task statistics and resource usage |
| `showFooter` | Boolean | `true` | Show timestamp footer in message |
| `files` | `List<String>` | `[]` | File paths to upload after completion notification (Bot only) |
| Property | Type | Default | Required | Description |
| ---------------------- | -------------- | ---------------------------------------- | -------- | ----------------------------------------------------------------- |
| `enabled` | Boolean | `true` | No | Send notification when workflow completes |
| `message` | String or Map | `'✅ *Pipeline completed successfully*'` | No | Completion notification message |
| `includeCommandLine` | Boolean | `true` | No | Include command line in message |
| `includeResourceUsage` | Boolean | `true` | No | Include task statistics and resource usage |
| `showFooter` | Boolean | `true` | No | Show timestamp footer in message |
| `files` | `List<String>` | `[]` | No | File paths to upload after completion notification (Bot only) |
| `channel` | String | `null` | No | Override channel for completion notifications (Bot only) |

<!-- prettier-ignore -->
!!! note
Expand Down Expand Up @@ -165,13 +167,14 @@ Configuration for workflow error notifications.

#### Properties

| Property | Type | Default | Description |
| -------------------- | -------------- | ------------------------ | -------------------------------------------------------- |
| `enabled` | Boolean | `true` | Send notification when workflow fails |
| `message` | String or Map | `'❌ *Pipeline failed*'` | Error notification message |
| `includeCommandLine` | Boolean | `true` | Include command line in message |
| `showFooter` | Boolean | `true` | Show timestamp footer in message |
| `files` | `List<String>` | `[]` | File paths to upload after error notification (Bot only) |
| Property | Type | Default | Required | Description |
| -------------------- | -------------- | ------------------------ | -------- | ------------------------------------------------------------ |
| `enabled` | Boolean | `true` | No | Send notification when workflow fails |
| `message` | String or Map | `'❌ *Pipeline failed*'` | No | Error notification message |
| `includeCommandLine` | Boolean | `true` | No | Include command line in message |
| `showFooter` | Boolean | `true` | No | Show timestamp footer in message |
| `files` | `List<String>` | `[]` | No | File paths to upload after error notification (Bot only) |
| `channel` | String | `null` | No | Override channel for error notifications (Bot only) |

### `slack.seqeraPlatform`

Expand Down
24 changes: 24 additions & 0 deletions docs/usage/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,30 @@ slack {

The start notification becomes the parent message. Complete, error, and any custom messages sent via `slackMessage()` appear as replies in the thread.

### Route Events to Different Channels

By default, all notifications go to the configured `bot.channel`. You can override this per event type to send different notifications to different channels:

```groovy
slack {
bot {
token = System.getenv('SLACK_BOT_TOKEN')
channel = '#general' // default channel for all events
}
onStart {
channel = '#deployments' // override for start notifications
}
onComplete {
channel = '#results' // override for completion notifications
}
onError {
channel = '#alerts' // override for error notifications
}
}
```

Per-event channels require a bot token. When a per-event channel differs from the global `bot.channel`, threading is automatically disabled for that event (since replies would go to a different conversation).

## Emoji Reactions

<!-- prettier-ignore -->
Expand Down
27 changes: 26 additions & 1 deletion example/configs/01-minimal.config
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
/*
* EXAMPLE 1: Minimal Setup - Just Enable Notifications
*
* The absolute minimum configuration to enable Slack notifications.
* Everything uses default values.
*
* Features enabled:
* - Notifications on workflow start, complete, and error
* - Default message templates
* - Includes all available information (command line, resource usage, etc.)
*
* Note: Bot name and icon are configured in Slack when creating the webhook.
*/

plugins {
id 'nf-slack@0.5.1'
}

slack {
enabled = true
// Only one setting required: your webhook URL
// Option A: Bot User
bot {
token = System.getenv('SLACK_BOT_TOKEN')
channel = System.getenv('SLACK_CHANNEL_ID')
}

// Option B: Webhook
// webhook {
// url = "$SLACK_WEBHOOK_URL"
// }
}

// That's it! You'll now get notifications for:
// - When the workflow starts
// - When the workflow completes successfully
// - When the workflow fails
36 changes: 32 additions & 4 deletions example/configs/02-notification-control.config
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
/*
* EXAMPLE 2: Notification Control - Choose When to Notify
*
* Control which workflow events trigger Slack notifications.
* All other settings remain at defaults.
*
* New features in this example:
* - onStart.enabled: control start notifications
* - onComplete.enabled: control completion notifications
* - onError.enabled: control error notifications
*/

plugins {
id 'nf-slack@0.5.1'
}

slack {
enabled = true
// Option A: Bot User
bot {
token = System.getenv('SLACK_BOT_TOKEN')
channel = System.getenv('SLACK_CHANNEL_ID')
}

onStart.enabled = false
onComplete.enabled = true
onError.enabled = true
// Option B: Webhook
// webhook {
// url = System.getenv('SLACK_WEBHOOK_URL')
// }

// Control which events trigger notifications
onStart {
enabled = false // Don't notify when workflow starts
}

onComplete {
enabled = true // DO notify when workflow completes
}

onError {
enabled = true // DO notify when workflow fails
}
}

// Use case: Reduce notification noise by only showing results and errors
35 changes: 30 additions & 5 deletions example/configs/03-message-text.config
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
/*
* EXAMPLE 3: Message Text Customization
*
* Customize the text of notification messages using simple strings.
* Supports Slack markdown formatting.
*
* New features in this example:
* - startMessage: customize start notification text
* - completeMessage: customize completion notification text
* - errorMessage: customize error notification text
*
* Note: This example uses default notification settings (all enabled)
*/

plugins {
id 'nf-slack@0.5.1'
}

slack {
enabled = true
// Option A: Bot User
bot {
token = System.getenv('SLACK_BOT_TOKEN')
channel = System.getenv('SLACK_CHANNEL_ID')
}

// Option B: Webhook
// webhook {
// url = System.getenv('SLACK_WEBHOOK_URL')
// }

// Customize message text with simple strings
// You can use Slack markdown: *bold*, _italic_, `code`, etc.
onStart {
enabled = true
message = '🚀 *My workflow is starting...*'
showFooter = false
}

onComplete {
enabled = true
message = '✅ *My workflow finished successfully!*'
showFooter = false
}

onError {
enabled = true
message = '❌ *My workflow failed!*'
showFooter = false
}
useThreads = false
}

// Default messages (if not customized):
// - Start: "🚀 *Pipeline started*"
// - Complete: "✅ *Pipeline completed successfully*"
// - Error: "❌ *Pipeline failed*"
28 changes: 28 additions & 0 deletions example/configs/13-per-event-channels.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Example 13: Per-Event Channel Routing
*
* Routes different notification types to different Slack channels.
* Start messages go to #deployments, completion to #results,
* and errors to #alerts.
*/

plugins {
id 'nf-slack@0.5.1'
}

slack {
enabled = true
bot {
token = System.getenv('SLACK_BOT_TOKEN')
channel = '#general'
}
onStart {
channel = '#deployments'
}
onComplete {
channel = '#results'
}
onError {
channel = '#alerts'
}
}
File renamed without changes.
6 changes: 6 additions & 0 deletions src/main/groovy/nextflow/slack/OnCompleteConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class OnCompleteConfig {
*/
final List<String> includeFields

/**
* Optional channel override for completion notifications (bot token only)
*/
final String channel

/**
* Create OnCompleteConfig from configuration map
*
Expand All @@ -87,6 +92,7 @@ class OnCompleteConfig {
this.showFooter = config?.showFooter != null ? config.showFooter as boolean : true
this.files = config?.files != null ? (config.files as List<String>) : []
this.includeFields = config?.includeFields != null ? (config.includeFields as List<String>) : []
this.channel = config?.channel as String
}

@Override
Expand Down
6 changes: 6 additions & 0 deletions src/main/groovy/nextflow/slack/OnErrorConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class OnErrorConfig {
*/
final List<String> includeFields

/**
* Optional channel override for error notifications (bot token only)
*/
final String channel

/**
* Create OnErrorConfig from configuration map
*
Expand All @@ -80,6 +85,7 @@ class OnErrorConfig {
this.showFooter = config?.showFooter != null ? config.showFooter as boolean : true
this.files = config?.files != null ? (config.files as List<String>) : []
this.includeFields = config?.includeFields != null ? (config.includeFields as List<String>) : []
this.channel = config?.channel as String
}

@Override
Expand Down
6 changes: 6 additions & 0 deletions src/main/groovy/nextflow/slack/OnStartConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ class OnStartConfig {
*/
final List<String> includeFields

/**
* Optional channel override for start notifications (bot token only)
*/
final String channel

/**
* Create OnStartConfig from configuration map
*
Expand All @@ -73,6 +78,7 @@ class OnStartConfig {
this.includeCommandLine = config?.includeCommandLine != null ? config.includeCommandLine as boolean : true
this.showFooter = config?.showFooter != null ? config.showFooter as boolean : true
this.includeFields = config?.includeFields != null ? (config.includeFields as List<String>) : []
this.channel = config?.channel as String
}

@Override
Expand Down
27 changes: 27 additions & 0 deletions src/main/groovy/nextflow/slack/SlackConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,24 @@ class SlackConfig {
// Set values in config map for constructor
if (webhook) config.webhook = webhook
if (botToken) {
// Validate token format
if (!botToken.startsWith('xoxb-') && !botToken.startsWith('xoxp-')) {
throw new IllegalArgumentException("Slack plugin: Bot token must start with 'xoxb-' or 'xoxp-'")
}
if (botToken.startsWith('xoxp-')) {
log.warn "Slack plugin: You are using a User Token (xoxp-). It is recommended to use a Bot Token (xoxb-) for better security and granular permissions."
}

// Validate channel is present
if (!botChannel) {
log.warn "Slack plugin: Bot channel is required when using bot token — plugin will be disabled"
return null
}
// Basic alphanumeric check for channel ID (allow hyphens/underscores for names)
// Also allow # for channel names
if (!botChannel.matches(/^[#a-zA-Z0-9\-_]+$/)) {
throw new IllegalArgumentException("Slack plugin: Invalid channel ID format: ${botChannel}")
}

def botConfig = config.bot as Map
if (botConfig == null) {
Expand All @@ -191,6 +204,20 @@ class SlackConfig {
}
}

// Validate per-event channel formats if specified
def onStartConfig = config.onStart as Map
def onCompleteConfig = config.onComplete as Map
def onErrorConfig = config.onError as Map
[onStart: onStartConfig, onComplete: onCompleteConfig, onError: onErrorConfig].each { name, cfg ->
def ch = cfg?.channel as String
if (ch && !ch.matches(/^[#a-zA-Z0-9\-_]+$/)) {
throw new IllegalArgumentException("Slack plugin: Invalid channel format in ${name}: ${ch}")
}
if (ch && !botToken) {
log.warn "Slack plugin: Per-event channel in '${name}' requires bot token - will be ignored with webhook"
}
}

def slackConfig = new SlackConfig(config)
log.info "Slack plugin: Enabled with ${botToken ? 'Bot' : 'Webhook'} notifications"
return slackConfig
Expand Down
Loading
Loading