How to conditionally route Slack notifications

slack
notification
script
envman
environment-variable

#1

We have lots of builds running all day long, but we don’t want to flood the same Slack channel with build results for every branch. Here’s how we avoid the noise and make sure only the appropriate channels or individuals get notified.

First, we can add an app environment variable that defines which are the “main” (i.e. non-development) branches, using a simple regular expression:


In this example, it will provide us with the condition we check in order to choose the notification target.

Then, we add a “Script” step to our workflow, somewhere towards the end:
image

In this step, we can test the condition (are we on a “main” branch?), choose the appropriate Slack target, and finally use envman to export it as an environment variable that can be used later:

#!/usr/bin/env bash
set -ex
if [[ $BITRISE_GIT_BRANCH =~ ^$MAIN_BRANCHES_REGEXP$ ]]; then
  SLACK_TARGET="#myapp_ci_builds"
else
  SLACK_TARGET="@$(git log -1 --format=%ae | cut -d @ -f 1)"
fi
envman add --key SLACK_TARGET --value "$SLACK_TARGET"

:information_source: Note that the BITRISE_GIT_BRANCH environment variable is available generally only when the workflow is triggered by a push event. One can easily adapt the script for pull requests, tags, etc. by modifying or adding conditions to check the relevant environment variables.

In the above script, if there was a push to a “main” branch, then we’ll want to notify a dedicated channel. Otherwise, we assume the last commit author is the relevant notification target, and we transform their email address into their Slack username. (This works in my organization, but it might be less straightforward for others.) Finally, we use envman to export the variable.

Finally, we insert the “Slack message” step and simply set the “target” to $SLACK_TARGET:
image

In your bitrise.yml, it should look something like this:

# ... other stuff
    - script:
        title: Set Slack target
        is_skippable: true
        inputs:
        - content: |-
            #!/usr/bin/env bash
            set -ex
            if [[ $BITRISE_GIT_BRANCH =~ ^$MAIN_BRANCHES_REGEXP$ ]]; then
              SLACK_TARGET="#myapp_ci_builds"
            else
              SLACK_TARGET="@$(git log -1 --format=%ae | cut -d @ -f 1)"
            fi
            envman add --key SLACK_TARGET --value "$SLACK_TARGET"
        is_always_run: true
    - slack:
        inputs:
        - channel: "$SLACK_TARGET"
# ... other stuff

Note the is_skippable: true on the script step, which you might want to add manually to keep any unexpected failure at this step from affecting the overall build status. (Thanks for the tip, @koral!)

Hope this helps someone, and feel free to comment if you find any improvements. :slight_smile:

(Also, be sure to vote for or follow the relevant feature requests if you want Bitrise to allow us to notify multiple committers/targets at once, or the person who manually launched the build!)

Cheers!


#2

I would add is_skippable: true to Set Slack target step. So if something goes wrong here it won’t affect the build status. Steps like slack have it enabled.


#3

I might actually be able to use echo $GIT_CLONE_COMMIT_AUTHOR_EMAIL instead of git log -1 --format=%ae, since it’s a variable exported from the git clone step, though I haven’t tried yet…


#4

Some caveats for those with “Manual merge” set to “yes” on their git-checkout step:

  • If a merge commit is generated (e.g. during a pull request-triggered build), then the “Bitrise Bot” will be the commit author (email address: letsconnect@bitrise.io); unless you have a #letsconnect Slack channel, the Slack notification step will fail in this case.
  • Regarding my previous comment: if the manual merge fails (e.g. there’s a conflict), the $GIT_CLONE_COMMIT_AUTHOR_EMAIL variable won’t be set, so the Slack notification step will fail.

You can trivially program around these cases if you need to, but just be aware of these possibilities!