Slack Notifications with GitHub Actions
Tags: actionshackathon, slack, github, actions
Published: 2020-08-14 09:30:49

### My Workflow

When I first started working with GitHub about a month ago, there were already quite a few Slack notification actions available, but I found each to either be cumbersome to use, or lacking what seemed like simple features such as status based messages. 

So I created `adamkdean/simple-slack-notify` to try and address those issues, and this post will show you how to use it.

The main features are:
- As simple or complex as you need it to be
- Status based messages meaning one step handles job successes, failures, and cancellations
- JavaScript strings for embedding environment variables or custom logic into notification strings
- Easy to add fields based on standard Slack JSON inputs

#### Example usage

The simplest use would consist of relying on the webhook's defaults and simply providing some text.

```yaml
- name: Simple notification
  uses: adamkdean/simple-slack-notify@master
  with:
    text: 'This is the simplest notification'
```

Overriding the channel is sometimes needed, such as to separate out builds, deployments, and alerts perhaps.

```yaml
- name: Channel specific notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#alerts'
    text: 'Something is happening and someone should probably panic'
```

The above works well, but what would really make someone panic is if we make the alert red, right?

You can use `danger`, `warning`, `good`, or a hex code such as `#d90000`.

```yaml
- name: Panic inducing notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#alerts'
    text: 'Something is happening and someone should probably panic'
    color: 'danger'
```

Perhaps you also want to change the username?

```yaml
- name: Panic Bot notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#alerts'
    username: 'Panic Bot'
    text: 'Something is happening and someone should probably panic'
    color: 'danger'
```

The action also supports fields, but due to the limitations of GitHub actions only passing in inputs as strings, we can't use yaml arrays. So, this is how you'd specify a field:

```yaml
- name: Specifying what to panic about notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#alerts'
    username: 'Panic Bot'
    text: 'Something is happening and someone should probably panic'
    color: 'danger'
    fields: |
      [{ "title": "Reason to panic", "value": "Deployed failed halfway through" }]
```

If there were multiple reasons to panic, you'd add more objects to the fields array:

```yaml
- name: Specifying what to panic about notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#alerts'
    username: 'Panic Bot'
    text: 'Something is happening and someone should probably panic'
    color: 'danger'
    fields: |
      [{ "title": "Reason to panic", "value": "Deployed failed halfway through", "short": true },
       { "title": "Timestamp", "value": "${Date.now()}", "short": true }]
```

Did you notice that some JavaScript snook in? Input strings are evaluated as a JavaScript strings, which means you can put environment variables into your messages, such as the `GITHUB_WORKFLOW` variable or `GITHUB_RUN_NUMBER` etc. The environment is stored within the `env` variable so to access environment variables in your strings, you simply use `${env.GITHUB_REPOSITORY}` etc. Here's an example:

```yaml
- name: Environment variable notification
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#example'
    text: '${env.GITHUB_WORKFLOW} (${env.GITHUB_RUN_NUMBER}) has finished'
    fields: |
      [{ "title": "Repository", "value": "${env.GITHUB_REPOSITORY}", "short": true },
       { "title": "Branch", "value": "${env.BRANCH}", "short": true }]
```

Now, each job has a status, which can be `success`, `failed`, or `cancelled`. Most other notification plugins use multiple blocks with `if: success()` and `if: failed()` etc but we don't need to do that. We can simply pass in the status and set status specific text. We use `if: always()` so that it runs regardless of whether the job is successful or not.

```yaml
- name: Build notification
  if: always()
  uses: adamkdean/simple-slack-notify@master
  with:
    channel: '#builds'
    status: ${{ job.status }}
    success_text: '${env.GITHUB_WORKFLOW} (${env.GITHUB_RUN_NUMBER}) build completed successfully'
    failure_text: '${env.GITHUB_WORKFLOW} (${env.GITHUB_RUN_NUMBER}) build failed'
    cancelled_text: '${env.GITHUB_WORKFLOW} (${env.GITHUB_RUN_NUMBER}) build was cancelled'
    fields: |
      [{ "title": "Repository", "value": "${env.GITHUB_REPOSITORY}", "short": true },
       { "title": "Branch", "value": "${env.BRANCH}", "short": true }]
```

Below I show how I'm using this in an actual build & deployment workflow.

### Submission Category: 

- Maintainer Must-Haves

### Yaml File or Link to Code

The following example Yaml file shows `adamkdean/simple-slack-notify` being integrated into a build & deploy pipeline.

```yaml
name: Build & Deploy
on: push
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
    - name: Build project
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.DEPLOY_HOST }}
        username: ${{ secrets.DEPLOY_USER }}
        key: ${{ secrets.DEPLOY_SSH_KEY }}
        port: ${{ secrets.DEPLOY_PORT }}
        script_stop: true
        script: |
          # Your build commands here
          example_build_project

    - name: Build notification
      if: always()
      uses: adamkdean/simple-slack-notify@master
      with:
        channel: '#builds'
        status: ${{ job.status }}
        success_text: 'Build (#${env.GITHUB_RUN_NUMBER}) completed successfully'
        failure_text: 'Build (#${env.GITHUB_RUN_NUMBER}) failed'
        cancelled_text: 'Build (#${env.GITHUB_RUN_NUMBER}) was cancelled'
        fields: |
          [{ "title": "Action URL", "value": "${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}"}]

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    steps:
    - name: Deploy project
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.DEPLOY_HOST }}
        username: ${{ secrets.DEPLOY_USER }}
        key: ${{ secrets.DEPLOY_SSH_KEY }}
        port: ${{ secrets.DEPLOY_PORT }}
        script_stop: true
        script: |
          # Your deploy commands here
          example_deploy_project

    - name: Deploy notification
      if: always()
      uses: adamkdean/simple-slack-notify@master
      with:
        channel: '#deployments'
        status: ${{ job.status }}
        success_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) completed successfully'
        failure_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) failed'
        cancelled_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) was cancelled'
        fields: |
          [{ "title": "Host", "value": "${{ secrets.DEPLOY_HOST }}"},
           { "title": "Action URL", "value": "${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}"}]
```

### Additional Resources / Info

{% github adamkdean/simple-slack-notify %}

#### Notes

I just wanted to point out for anyone new to GitHub Actions that while above I'm referring to the master branch (i.e. ` adamkdean/simple-slack-notify@master`), if you're using this in production, it's always wiser to use a version. As of writing, the latest version is `1.0.4` so we would use ` adamkdean/simple-slack-notify@1.0.4`.