Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A centralized collection of reusable GitHub Actions designed to streamline and a
* [**Get Jira Release Notes**](get-jira-release-notes/README.md): Fetches Jira release notes and generates the release notes URL for a given project and version.
* [**Get Jira Version**](get-jira-version/README.md): Extracts a Jira-compatible version number from a release version by formatting it appropriately for Jira.
* [**Get Release Version**](get-release-version/README.md): Extracts the release version from the repox status on a specified branch.
* [**Notify Slack on Failure**](notify-slack/README.md): Sends a Slack notification when a job fails.
* [**Publish GitHub Release**](publish-github-release/README.md): Publishes a GitHub Release with notes fetched from Jira or provided directly.
* [**Release Jira Version**](release-jira-version/README.md): Releases a Jira version and creates the next one.
* [**Update Analyzer**](update-analyzer/README.md): Updates an analyzer version in SonarQube or SonarCloud and creates a pull request.
Expand Down
101 changes: 101 additions & 0 deletions notify-slack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Notify Slack on Failure Action

This GitHub Action sends a Slack notification summarizing failed jobs in a workflow run when used with an `if: failure()` condition.

## Description

The action posts a concise message to a Slack channel containing:
1. A link to the failed GitHub Actions run
2. A list of failed jobs provided by the workflow
3. A custom project-branded username and icon

It is intended to be used as the last step (or in a dedicated job) guarded by `if: failure()` so that it only triggers on failures.

## Dependencies

This action depends on:
- [SonarSource/vault-action-wrapper](https://github.com/SonarSource/vault-action-wrapper) to retrieve the Slack token from Vault
- [rtCamp/action-slack-notify](https://github.com/rtCamp/action-slack-notify) to send the Slack message

## Inputs

| Input | Description | Required | Default |
|-----------------|------------------------------------------------------------------------|----------|-----------|
| `project-name` | The display name of the project; used in the Slack username. | Yes | - |
| `icon` | Emoji icon for the Slack message (Slack emoji code). | No | `:alert:` |
| `slack-channel` | Slack channel (without `#`) to post the notification into. | Yes | - |
| `jobs` | Comma-separated list of job names to report as failed (provided by you). | Yes | - |

Note: The list of failed jobs must be provided via the `jobs` input by your workflow logic.

## Outputs

No outputs are produced by this action.

## Usage

### Basic usage (in a dedicated failure notification job)

```yaml
jobs:
notify_on_failure:
needs: [ build, test, deploy ] # Example job dependencies
runs-on: ubuntu-latest
if: failure()
permissions:
statuses: read
id-token: write
steps:
- uses: SonarSource/release-github-actions/notify-slack@v1
with:
project-name: 'My Project'
slack-channel: 'engineering-alerts'
jobs: ${{ toJSON(needs) }}
```

### Minimal usage (only required inputs)

```yaml
- uses: SonarSource/release-github-actions/notify-slack@v1
if: failure()
with:
project-name: 'My Project'
slack-channel: 'engineering-alerts'
jobs: 'build, test'
```

### Custom icon

```yaml
- uses: SonarSource/release-github-actions/notify-slack@v1
if: failure()
with:
project-name: 'My Project'
slack-channel: 'engineering-alerts'
icon: ':rocket:'
jobs: 'build, test'
```

## Implementation Details

The action is a composite action that:
- Fetches `SLACK_TOKEN` from Vault path `development/kv/data/slack` using `vault-action-wrapper`
- Uses a workflow-provided `jobs` input (comma-separated string) to populate the "Failed Jobs" section
- Constructs a Slack message with run URL and the provided failed jobs list
- Uses `rtCamp/action-slack-notify` to send a minimal styled message (no title/footer) with danger color
- Sets Slack username to: `<project-name> CI Notifier`
- If the `jobs` list is empty or not provided, the "Failed Jobs" line will be blank

## Prerequisites

- Vault policy granting access to `development/kv/data/slack` must be configured for the repository.
- The secret at that path must contain a key named `token`.
- The Slack channel provided must exist and the token must have permission to post there.

## Notes

- Use `if: failure()` on the step or job; otherwise it will also fire on success.
- `project-name`, `slack-channel`, and `jobs` are required inputs (no defaults).
- Do not prefix the channel with `#`.
- Message formatting is intentionally minimal for quick triage in alert-focused channels.
- How you compute the failed jobs list is up to your workflow; you can use prior steps to gather job results and pass them to this action via `jobs`.
59 changes: 59 additions & 0 deletions notify-slack/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: 'Notify Slack on Failure'
description: 'Sends a Slack notification when a job fails.'

inputs:
project-name:
description: 'The name of the project.'
required: true
icon:
description: 'The icon for the Slack notification.'
required: false
default: ':alert:'
slack-channel:
description: 'The Slack channel to send the notification to.'
required: true
jobs:
description: 'A GitHub needs-like object string of jobs and their results (e.g., from toJSON(needs)).'
required: true

runs:
using: "composite"
steps:
- name: Collect Failed Jobs
shell: bash
id: collect_failed_jobs
env:
JOBS: ${{ inputs.jobs }}
run: |
echo "Checking Jobs: $JOBS"
# Parse the provided jobs mapping string without relying on strict JSON. Extract keys where result == failure.
# This handles inputs like: { build: { result: failure, outputs: {} }, qa_tests: { result: skipped, outputs: {} } }
FAILED_JOBS=$(echo "$JOBS" | awk '
/[[:alnum:]_.-]+:[[:space:]]*\{/{ key=$1; sub(/:$/, "", key) }
/result[[:space:]]*:[[:space:]]*failure/{ fails=(fails?fails", ":"") key }
END{ print fails }
')
echo "Failed Jobs: $FAILED_JOBS"
echo "failed-jobs=$FAILED_JOBS" >> $GITHUB_OUTPUT
- name: Vault Secrets
id: secrets
uses: SonarSource/vault-action-wrapper@v3
with:
secrets: |
development/kv/data/slack token | SLACK_TOKEN;
- name: Send Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_CHANNEL: ${{ inputs.slack-channel }}
SLACK_MSG_AUTHOR: " "
SLACK_TITLE: " "
SLACK_FOOTER: " "
SLACK_COLOR: danger
MSG_MINIMAL: true
SLACK_MESSAGE: |
*Run:* ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
*Failed Jobs:* ${{ steps.collect_failed_jobs.outputs.failed-jobs }}
SLACK_TOKEN: "${{ fromJSON(steps.secrets.outputs.vault).SLACK_TOKEN }}"
SLACK_ICON_EMOJI: "${{ inputs.icon }}"
SLACK_USERNAME: "${{ inputs.project-name }} CI Notifier"