GitHub Action - Passing a Slack Message ID between Jobs | Christopher Vachon

GitHub Action - Passing a Slack Message ID between Jobs

2022-10-19

While migrating a project into GitHub, I have been updating the CI/CD processes of the repositories to use GitHub Actions.

One of the updates I wanted to make was to push notifications into a Slack Channel to notify users of the status of deployments but to do so without flooding the channel with multiple notifications of the same event.

Fortunately, the Slack API allows you to update a message in a channel. There are already several public actions to post a message into Slack and update them, so I will not go too deep into them. But what I got a little hung up on was how to pass the ID of the message being updated between multiple GitHub Action Jobs.

The first step we need to take is to define our action workflow

# ./.github/workflows/build-and-deploy.yml
name: Production Build and Deploy Release

on:
    release:
        types: [published]

jobs:
    build:
        runs-on: ubuntu-latest
        steps:
            - name: Build
              run: echo "build step"
            - name: Push to Registry
              run: echo "push to registry step"

    deploy:
        runs-on: ubuntu-latest
        needs: "build"
        steps:
            - name: Deploy
              run: echo "deploy step"

This Action runs three steps over 2 jobs. Next, we’ll push a message into Slack using the voxmedia/github-action-slack-notify-build@v1 action.

# ./.github/workflows/build-and-deploy.yml
name: Production Build and Deploy Release

on:
    release:
        types: [published]

jobs:
    build:
        runs-on: ubuntu-latest
        steps:
            - name: Notify Slack Building
              id: slack
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: BUILDING
                  color: warning

            - name: Build
              run: echo "build step"
            - name: Push to Registry
              run: echo "push to registry step"

    deploy:
        runs-on: ubuntu-latest
        needs: "build"
        steps:
            - name: Notify Slack Deploying
              id: slack
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DEPLOYING
                  color: warning

            - name: Deploy
              run: echo "deploy step"

            - name: Notify Slack Complete
              id: slack
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DONE
                  color: success

This will push three messages into Slack, but we can capture the message ID and share it between each slack call.

# ./.github/workflows/build-and-deploy.yml
name: Production Build and Deploy Release

on:
    release:
        types: [published]

jobs:
    build:
        runs-on: ubuntu-latest
        steps:
            - name: Notify Slack Building
              id: slack-building
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: BUILDING
                  color: warning

            - name: Build
              run: echo "build step"
            - name: Push to Registry
              run: echo "push to registry step"

    deploy:
        runs-on: ubuntu-latest
        needs: "build"
        steps:
            - name: Notify Slack Deploying
              id: slack-deploy
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DEPLOYING
                  color: warning

            - name: Deploy
              run: echo "deploy step"

            - name: Notify Slack Complete
              id: slack-done
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  message_id: ${{ steps.slack-deploy.outputs.slack_message_id}}
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DONE
                  color: success

this will now Update the `slack-deploy` message to the `slack-done` message giving us two messages in Slack instead of three.

An important point to mention here is that each Job will run in an isolated environment. Jobs can be made aware of the status of other jobs, but they can not share values or artifacts between themselves without some kind of intervention. This is why my Build job pushes the artifact to a registry to be utilized and deployed by other jobs. For Primitive values like strings, numbers, and booleans we can define outputs on a job. Subsequent Jobs and “need” that job will then have access to those outputs.

# ./.github/workflows/build-and-deploy.yml
name: Production Build and Deploy Release

on:
    release:
        types: [published]

jobs:
    build:
        runs-on: ubuntu-latest
        outputs:
            slack_message_id: ${{ steps.slack-building.outputs.message_id }}
        steps:
            - name: Notify Slack Building
              id: slack-building
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: BUILDING
                  color: warning

            - name: Build
              run: echo "build step"
            - name: Push to Registry
              run: echo "push to registry step"

    deploy:
        runs-on: ubuntu-latest
        needs: "build"
        steps:
            - name: Notify Slack Deploying
              id: slack-deploy
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  message_id: ${{ needs.build.outputs.slack_message_id}}
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DEPLOYING
                  color: warning

            - name: Deploy
              run: echo "deploy step"

            - name: Notify Slack Complete
              id: slack-done
              env:
                  SLACK_BOT_TOKEN: ${{ secrets.SLACK_SECRET }}
              uses: voxmedia/github-action-slack-notify-build@v1
              with:
                  message_id: ${{ needs.build.outputs.slack_message_id}}
                  channel: ${{ secrets.SLACK_CHANNEL }}
                  status: DONE
                  color: success

The Build Job now specifies an output named slack_message_id and is defined as the output of the message_id from the voxmedia/github-action-slack-notify-build@v1 action.

The Deploy Job that “needs” build can now access the `slack_message_id` value and update the original message in Slack.

The team has found it very helpful to know when and in what state things are happening without having to flood a channel with multiple messages regarding the same process.