Skip to content

Commit

Permalink
ci: Add a slack notifier workflow (#18)
Browse files Browse the repository at this point in the history
Add a workflow based on `slackapi/slack-github-action`, that lets us
rate-limit messages sent to slack to avoid spamming.
  • Loading branch information
aborgna-q authored Oct 25, 2024
1 parent 3d83760 commit 8279ce0
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
136 changes: 136 additions & 0 deletions .github/workflows/slack-notifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: Post comments on slack, with rate limiting.
on:
workflow_call:
secrets:
GITHUB_PAT:
description: 'The github token used to read the timeout variable.'
required: true
SLACK_BOT_TOKEN:
description: 'The slack API token, with `chat:write` permissions.'
required: true
inputs:
channel-id:
description: 'The channel ID to send the message to.'
required: true
type: string
slack-message:
description: 'The message to send to slack.'
required: true
type: string
timeout-variable:
description: 'A repository variable used to store the last message timestamp.'
required: true
type: string
timeout-minutes:
description: 'The minimum time to wait before sending the message again, in minutes.'
required: false
type: string
# Default to 24 hours
default: '1440'
outputs:
sent:
description: 'Whether the message was sent. Returns false if we are waiting for a timeout.'
value: ${{ jobs.notify-slack.outputs.sent }}

jobs:
notify-slack:
runs-on: ubuntu-latest
outputs:
sent: ${{ steps.rate-limit.outputs.send }}
steps:
- name: Check last message timestamp
id: last-sent
run: |
set +e
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/$OWNER/$REPO/actions/variables/$VAR \
> read-variable.json
if [ $? -ne 0 ]
then
echo "Could not read the variable."
echo "missing=true" >> $GITHUB_OUTPUT
else
jq -r '.value' read-variable.json > last-sent.txt
echo "missing=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_PAT }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
VAR: ${{ inputs.timeout-variable }}

- name: Create the timestamp variable if it's missing
if: ${{ steps.last-sent.outputs.missing == 'true' }}
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/$OWNER/$REPO/actions/variables \
-f "name=$VAR" -f "value=1990-01-01T00:00:00Z"
env:
GH_TOKEN: ${{ secrets.GITHUB_PAT }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
VAR: ${{ inputs.timeout-variable }}

- name: Rate limit
id: rate-limit
run: |
# Check if the last message was sent within the timeout
echo "Preparing to send message:"
echo
echo "\"$MESSAGE\""
echo
if [ -f last-sent.txt ]
then
LAST_SENT=$( cat last-sent.txt )
NOW=$( date +'%FT%TZ' )
echo "Last sent: $LAST_SENT"
echo "Now: $NOW"
DIFF_MINUTES=$(( ( $( date -d "$NOW" +%s ) - $( date -d "$LAST_SENT" +%s ) ) / 60 ))
echo "Timeout: $TIMEOUT mins"
echo "Difference: $DIFF_MINUTES mins"
if [ $DIFF_MINUTES -lt $TIMEOUT ]
then
echo "On timeout period. Not sending the message."
echo "send=false" >> "$GITHUB_OUTPUT"
exit 0
fi
else
echo "Last-sent variable was not set."
fi
echo "send=true" >> "$GITHUB_OUTPUT"
date +%s > last-sent.txt
env:
TIMEOUT: ${{ inputs.timeout-minutes }}
MESSAGE: ${{ inputs.slack-message }}

- name: Send notification
if: ${{ steps.rate-limit.outputs.send == 'true' }}
uses: slackapi/[email protected]
with:
channel-id: ${{ inputs.channel-id }}
slack-message: ${{ inputs.slack-message }}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

- name: Modify the variable to save the new timestamp
if: ${{ steps.rate-limit.outputs.send == 'true' }}
run: |
gh api \
--method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/$OWNER/$REPO/actions/variables/$VAR \
-f "name=$VAR" -f "value=$( date +'%FT%TZ' )"
env:
GH_TOKEN: ${{ secrets.GITHUB_PAT }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
VAR: ${{ inputs.timeout-variable }}
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The following workflows are available:
- [`drop-cache`](#drop-cache): Drops the cache for a branch when a pull request is closed.
- [`pr-title`](#pr-title): Checks the title of pull requests to ensure they follow the conventional commits format.
- [`rs-semver-checks`](#rs-semver-checks): Runs `cargo-semver-checks` on a PR against the base branch, and reports back if there are breaking changes.
- [`slack-notifier`](#slack-notifier): Post comments on slack, with a rate limit to avoid spamming the channel.

## [`add-to-project`](https://github.com/CQCL/hugrverse-actions/blob/main/.github/workflows/add-to-project.yml)

Expand Down Expand Up @@ -184,3 +185,58 @@ The fine-grained `GITHUB_PAT` secret must include the following permissions:
| --- | --- |
| Pull requests | Read and write |


## [`slack-notifier`](https://github.com/CQCL/hugrverse-actions/blob/main/.github/workflows/slack-notifier.yml)

Post comments on slack using
[slackapi/slack-github-action](https://github.com/slackapi/slack-github-action),
adding a rate limit to avoid spamming the channel.

### Usage
```yaml
name: Send a slack message
on:
pull_request:
branches:
- main
jobs:
message-slack:
uses: CQCL/hugrverse-actions/.github/workflows/slack-notifier.yml@main
with:
channel-id: "SOME CHANNEL ID"
slack-message: "Hello 🌎!"
# A minimum time in minutes to wait before sending another message.
timeout-minutes: 60
# A repository variable used to store the last message timestamp.
timeout-variable: "HELLO_MESSAGE_TIMESTAMP"
secrets:
GITHUB_PAT: ${{ secrets.GITHUB_PAT }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
```

### Inputs

- `channel-id`: The ID of the channel to post the message to. (**required**)
- `slack-message`: The message to post. (**required**)
- `timeout-variable`: A repository variable used to store the last message timestamp. (**required**)
- `timeout-minutes`: A minimum time in minutes to wait before sending another message. Defaults to 24 hours.

### Outputs

- `sent`: A boolean indicating if the message was sent.

### Token Permissions

`SLACK_BOT_TOKEN` is a token generated by Slack with `chat:write` access to the
channel. See the
[slackapi/slack-github-action](https://github.com/slackapi/slack-github-action?tab=readme-ov-file#technique-2-slack-app)
documentation for more information.
If you are using a slack app, make sure to add it to the channel.
See formatting options in the [Slack API documentation](https://api.slack.com/reference/surfaces/formatting).

The fine-grained `GITHUB_PAT` secret must include the following permissions:

| Permission | Access |
| --- | --- |
| Variables (repository) | Read and write |

0 comments on commit 8279ce0

Please sign in to comment.