From 58555db42322608592496603e76f478c6334db69 Mon Sep 17 00:00:00 2001 From: "Rodrigo Q. Saramago" Date: Tue, 4 Apr 2023 09:34:39 +0200 Subject: [PATCH] Fix text formatting of CI matrix notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- .circleci/config.yml | 28 +------ .../ci/notification/matrix_notification.sh | 82 +++++++++++++++++++ .../ci/notification/templates/build_fail.json | 6 ++ .../notification/templates/build_release.json | 6 ++ .../notification/templates/build_success.json | 6 ++ 5 files changed, 101 insertions(+), 27 deletions(-) create mode 100755 scripts/ci/notification/matrix_notification.sh create mode 100644 scripts/ci/notification/templates/build_fail.json create mode 100644 scripts/ci/notification/templates/build_release.json create mode 100644 scripts/ci/notification/templates/build_success.json diff --git a/.circleci/config.yml b/.circleci/config.yml index e189ea07b..6d972ca19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,33 +47,7 @@ commands: - run: name: "Matrix notification" when: << parameters.condition >> - command: | - # FIXME: Checking $CIRCLE_PULL_REQUEST would be better than hard-coding branch names - # but it's broken. CircleCI associates runs on develop/breaking with random old PRs. - [[ $CIRCLE_BRANCH == develop || $CIRCLE_BRANCH == breaking ]] || { echo "Running on a PR or a feature branch - notification skipped."; exit 0; } - - # Workflow name is not exposed as an env variable. Has to be queried from the API. - # The name is not critical so if anything fails, use the raw workflow ID as a fallback. - workflow_info=$(curl --silent "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}") || true - workflow_name=$(echo "$workflow_info" | grep -E '"\s*name"\s*:\s*".*"' | cut -d \" -f 4 || echo "$CIRCLE_WORKFLOW_ID") - - [[ $CIRCLE_NODE_TOTAL == 1 ]] && job="**${CIRCLE_JOB}**" - [[ $CIRCLE_NODE_TOTAL != 1 ]] && job="**${CIRCLE_JOB}** (run $((CIRCLE_NODE_INDEX + 1))/${CIRCLE_NODE_TOTAL})" - - [[ "<< parameters.event >>" == "failure" ]] && message=" ❌ [${workflow_name}] Job ${job} failed on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." - [[ "<< parameters.event >>" == "success" ]] && message=" βœ… [${workflow_name}] Job ${job} succeeded on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." - [[ "<< parameters.event >>" == "release" ]] && message=" πŸ“¦ Release binaries for version **${CIRCLE_TAG}** are ready and attached as artifacts to [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}). **Please make sure the whole workflow succeeded before using them.**" - - # The release notification only makes sense on tagged commits. If the commit is untagged, just bail out. - [[ "<< parameters.event >>" == "release" ]] && { [[ $CIRCLE_TAG != "" ]] || { echo "Not a tagged commit - notification skipped."; exit 0; } } - - curl "https://${MATRIX_SERVER}/_matrix/client/v3/rooms/${MATRIX_NOTIFY_ROOM_ID}/send/m.room.message" \ - --request POST \ - --include \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \ - --data "{\"msgtype\":\"m.text\", \"body\":\"${message}\"}" + command: scripts/ci/notification/matrix_notification.sh << parameters.event >> matrix_notify_failure_unless_pr: description: "Posts a failure notification to the main room on Matrix (if not running on a PR)." diff --git a/scripts/ci/notification/matrix_notification.sh b/scripts/ci/notification/matrix_notification.sh new file mode 100755 index 000000000..ecf14d3e5 --- /dev/null +++ b/scripts/ci/notification/matrix_notification.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +set -euo pipefail +shopt -s inherit_errexit + +SCRIPT_DIR="$(dirname "$0")" + +function fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +function notify() { + [[ -z "$1" ]] && fail "Event type not provided." + [[ "$1" != "failure" && "$1" != "success" && "$1" != "release" ]] && fail "Wrong event type." + local event="$1" + local formatted_message + + # FIXME: Checking $CIRCLE_PULL_REQUEST would be better than hard-coding branch names + # but it's broken. CircleCI associates runs on develop/breaking with random old PRs. + [[ "$BRANCH" == "develop" || "$BRANCH" == "breaking" ]] || { echo "Running on a PR or a feature branch - notification skipped."; exit 0; } + + # The release notification only makes sense on tagged commits. If the commit is untagged, just bail out. + [[ "$event" == "release" ]] && { [[ $TAG != "" ]] || { echo "Not a tagged commit - notification skipped."; exit 0; } } + + formatted_message="$(format_predefined_message "$event")" + + curl "https://${MATRIX_SERVER}/_matrix/client/v3/rooms/${MATRIX_NOTIFY_ROOM_ID}/send/m.room.message" \ + --request POST \ + --include \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \ + --data "$formatted_message" +} + +function circleci_workflow_name() { + # Workflow name is not exposed as an env variable. Has to be queried from the API. + # The name is not critical so if anything fails, use the raw workflow ID as a fallback. + local workflow_info + workflow_info=$(curl --silent "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}") || true + echo "$workflow_info" | grep -E '"\s*name"\s*:\s*".*"' | cut -d \" -f 4 || echo "$CIRCLE_WORKFLOW_ID" +} + +function circleci_job_name() { + (( CIRCLE_NODE_TOTAL == 1 )) && echo "${CIRCLE_JOB}" && return + (( CIRCLE_NODE_TOTAL != 1 )) && echo "${CIRCLE_JOB} (run $((CIRCLE_NODE_INDEX + 1))/${CIRCLE_NODE_TOTAL})" +} + +# Currently matrix only supports html formatted body, +# see: https://spec.matrix.org/v1.6/client-server-api/#mtext +# +# Eventually, the matrix api will have support for better format options and `formatted_body` may not be necessary anymore: +# https://github.com/matrix-org/matrix-spec-proposals/pull/1767 +function format_predefined_message() { + [[ -z "$1" ]] && fail "Event type not provided." + local event="$1" + local template + + [[ "$event" == "failure" ]] && template="${SCRIPT_DIR}/templates/build_fail.json" + [[ "$event" == "success" ]] && template="${SCRIPT_DIR}/templates/build_success.json" + [[ "$event" == "release" ]] && template="${SCRIPT_DIR}/templates/build_release.json" + + [[ -z "$template" ]] && fail "Message template for event [$event] not defined." + + # Export variables that must be substituted + export WORKFLOW_NAME JOB BRANCH TAG BUILD_URL BUILD_NUM + envsubst < "$template" + unset WORKFLOW_NAME JOB BRANCH TAG BUILD_URL BUILD_NUM +} + +# Set message environment variables based on CI backend +if [[ "$CIRCLECI" = true ]] ; then + BRANCH="$CIRCLE_BRANCH" + TAG="$CIRCLE_TAG" + BUILD_URL="$CIRCLE_BUILD_URL" + BUILD_NUM="$CIRCLE_BUILD_NUM" + WORKFLOW_NAME="$(circleci_workflow_name)" + JOB="$(circleci_job_name)" +fi + +notify "$@" diff --git a/scripts/ci/notification/templates/build_fail.json b/scripts/ci/notification/templates/build_fail.json new file mode 100644 index 000000000..baf69aa4a --- /dev/null +++ b/scripts/ci/notification/templates/build_fail.json @@ -0,0 +1,6 @@ +{ + "msgtype": "m.text", + "body": " ❌ [${WORKFLOW_NAME}] Job ${JOB} failed on ${BRANCH}. Please see ${BUILD_URL} for details.", + "format": "org.matrix.custom.html", + "formatted_body": " ❌ [${WORKFLOW_NAME}] Job ${JOB} failed on ${BRANCH}. Please see build ${BUILD_NUM} for details." +} diff --git a/scripts/ci/notification/templates/build_release.json b/scripts/ci/notification/templates/build_release.json new file mode 100644 index 000000000..b7c538f8c --- /dev/null +++ b/scripts/ci/notification/templates/build_release.json @@ -0,0 +1,6 @@ +{ + "msgtype": "m.text", + "body": " πŸ“¦ Release binaries for version ${TAG} are ready and attached as artifacts to ${BUILD_URL}. Please make sure the whole workflow succeeded before using them.", + "format": "org.matrix.custom.html", + "formatted_body": " πŸ“¦ Release binaries for version ${TAG} are ready and attached as artifacts to build ${BUILD_NUM}. Please make sure the whole workflow succeeded before using them." +} diff --git a/scripts/ci/notification/templates/build_success.json b/scripts/ci/notification/templates/build_success.json new file mode 100644 index 000000000..170360fbb --- /dev/null +++ b/scripts/ci/notification/templates/build_success.json @@ -0,0 +1,6 @@ +{ + "msgtype": "m.text", + "body": " βœ… [${WORKFLOW_NAME}] Job ${JOB} succeeded on ${BRANCH}. Please see ${BUILD_URL} for details.", + "format": "org.matrix.custom.html", + "formatted_body":" βœ… [${WORKFLOW_NAME}] Job ${JOB} succeeded on ${BRANCH}. Please see build ${BUILD_NUM} for details." +}