diff --git a/.circleci/test-deploy.yml b/.circleci/test-deploy.yml index 6c924056..cfbc40b1 100644 --- a/.circleci/test-deploy.yml +++ b/.circleci/test-deploy.yml @@ -28,6 +28,24 @@ jobs: template: basic_success_1 event: always thread_id: orb-testing-thread-<${CIRCLE_SHA1}> + - slack/notify: + debug: true + step_name: "Message with thread updated" + event: always + update_notification: true + thread_id: orb-testing-thread-<${CIRCLE_SHA1}> + custom: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "This message should be on thread and updating thread" + } + } + ] + } - slack/notify: debug: true step_name: "Custom template with group mention" diff --git a/README.md b/README.md index e51cde76..9c7d9fb4 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,31 @@ Post replies in threads with a special parameter `thread_id`. Including this par } ``` +## Update Top Level Messages + +Update a top level message using the `thread_id` parameter. Can update the top of a threaded message or a standalone message. include the parameter `update_notification: true` to specify that this will be an update of an existing message. If the `thread_id` is missing or not found, the message will be posted as a new message instead. + + ```yaml +- slack/notify: + event: always + update_notification: true + custom: | + { + "blocks": [ + { + "type": "section", + "fields": [ + { + "type": "plain_text", + "text": "*This is a text notification*", + "emoji": true + } + ] + } + ] + } + ``` + ## Scheduled Message Set the `scheduled_offset_seconds` special parameter to a number of seconds if you want to post a scheduled message. Example: diff --git a/src/commands/notify.yml b/src/commands/notify.yml index 1c77161f..b684d9f8 100644 --- a/src/commands/notify.yml +++ b/src/commands/notify.yml @@ -91,6 +91,10 @@ parameters: default: 0 description: | When set, the notification is a scheduled message. + update_notification: + type: boolean + default: false + description: When set, the parent notification of the thread is updated retries: type: integer default: 0 @@ -142,6 +146,7 @@ steps: SLACK_PARAM_THREAD: "<>" SLACK_PARAM_OFFSET: "<>" SLACK_SCRIPT_NOTIFY: "<>" + SLACK_PARAM_UPDATE: "<>" SLACK_SCRIPT_UTILS: "<>" # import pre-built templates using the orb-pack local script include. basic_fail_1: "<>" diff --git a/src/examples/update_notification.yml b/src/examples/update_notification.yml new file mode 100644 index 00000000..6943bafc --- /dev/null +++ b/src/examples/update_notification.yml @@ -0,0 +1,102 @@ +description: | + Send a Slack notification to a channel and use the same message to post replies in a thread. + `thread_id` parameter holds a thread identifier in case there are multiple notifications in the pipeline +usage: + version: 2.1 + orbs: + slack: circleci/slack@5.0 + node: circleci/node:4.1 + jobs: + test: + executor: + name: node/default + steps: + - slack/notify: + event: always + channel: engineering + thread_id: testing + custom: | + { + "blocks": [ + { + "type": "section", + "fields": [ + { + "type": "plain_text", + "text": "*Tests started.*", + "emoji": true + } + ] + } + ] + } + - slack/notify: + event: always + channel: engineering + thread_id: testing + update_notification: true + custom: | + { + "blocks": [ + { + "type": "section", + "fields": [ + { + "type": "plain_text", + "text": "*Tests finished.*", + "emoji": true + } + ] + } + ] + } + deploy: + executor: + name: node/default + steps: + - slack/notify: + event: always + channel: engineering + thread_id: deployment + custom: | + { + "blocks": [ + { + "type": "section", + "fields": [ + { + "type": "plain_text", + "text": "*Deployment started.*", + "emoji": true + } + ] + } + ] + } + - slack/notify: + event: always + channel: engineering + thread_id: deployment + update_notification: true + custom: | + { + "blocks": [ + { + "type": "section", + "fields": [ + { + "type": "plain_text", + "text": "*Deployment finished.*", + "emoji": true + } + ] + } + ] + } + workflows: + deploy_and_notify: + jobs: + - deploy + - test: + requires: + - deploy diff --git a/src/scripts/notify.sh b/src/scripts/notify.sh index 430296ed..2f187813 100644 --- a/src/scripts/notify.sh +++ b/src/scripts/notify.sh @@ -59,7 +59,7 @@ NotifyWithRetries() { local success_request=false local retry_count=0 while [ "$retry_count" -le "$SLACK_PARAM_RETRIES" ]; do - if SLACK_SENT_RESPONSE=$(curl -s -f -X POST -H 'Content-type: application/json' -H "Authorization: Bearer $SLACK_ACCESS_TOKEN" --data "$SLACK_MSG_BODY" "$1"); then + if SLACK_SENT_RESPONSE=$(curl -s -f -X POST -H 'Content-type: application/json; charset=utf-8' -H "Authorization: Bearer $SLACK_ACCESS_TOKEN" --data "$SLACK_MSG_BODY" "$1"); then echo "Notification sent" success_request=true break @@ -101,8 +101,15 @@ PostToSlack() { # get the value of the specified thread from the environment # SLACK_THREAD_TS=12345.12345 SLACK_THREAD_TS=$(eval "echo \"\$$SLACK_PARAM_THREAD\"") - # append the thread_ts to the body for posting the message in the correct thread - SLACK_MSG_BODY=$(echo "$SLACK_MSG_BODY" | jq --arg thread_ts "$SLACK_THREAD_TS" '.thread_ts = $thread_ts') + if [ "$SLACK_PARAM_UPDATE" ]; then + # when updating, the key ts is used to reference the message to be updated + TS=$(eval "echo \"\$$SLACK_PARAM_THREAD\"") + SLACK_MSG_BODY=$(echo "$SLACK_MSG_BODY" | jq --arg ts "$TS" '.ts = $ts') + SLACK_UPDATE=true + else + # append the thread_ts to the body for posting the message in the correct thread + SLACK_MSG_BODY=$(echo "$SLACK_MSG_BODY" | jq --arg thread_ts "$SLACK_THREAD_TS" '.thread_ts = $thread_ts') + fi fi echo "Sending to Slack Channel: $i" @@ -127,7 +134,10 @@ PostToSlack() { SLACK_MSG_BODY=$(echo "$SLACK_MSG_BODY" | jq --arg post_at "$POST_AT" '.post_at = ($post_at|tonumber)') # text is required for scheduled messages SLACK_MSG_BODY=$(echo "$SLACK_MSG_BODY" | jq '.text = "Dummy fallback text"') + NotifyWithRetries https://slack.com/api/chat.scheduleMessage + elif [ $SLACK_UPDATE ]; then + NotifyWithRetries https://slack.com/api/chat.update else NotifyWithRetries https://slack.com/api/chat.postMessage fi