diff --git a/.github/actions/reportportal-summarize/action.yml b/.github/actions/reportportal-summarize/action.yml index 10f8360ac..54d2fc437 100644 --- a/.github/actions/reportportal-summarize/action.yml +++ b/.github/actions/reportportal-summarize/action.yml @@ -23,6 +23,9 @@ outputs: slack-message: description: Outcome message for slack value: ${{ steps.slack-message.outputs.message }} + teams-message: + description: Outcome message for teams + value: ${{ steps.teams-message.outputs.message }} runs: using: composite @@ -54,3 +57,12 @@ runs: RP_CONTENT: ${{ steps.rp-output.outputs.content }} RP_LAUNCH_URL: ${{ steps.rp-output.outputs.url }} run: ${{ github.action_path }}/get-slack-message.sh + + - name: Compute Teams message + id: teams-message + shell: bash + env: + RP_LAUNCH_KEY: ${{ inputs.rp-launch-key }} + RP_CONTENT: ${{ steps.rp-output.outputs.content }} + RP_LAUNCH_URL: ${{ steps.rp-output.outputs.url }} + run: ${{ github.action_path }}/get-teams-message.sh diff --git a/.github/actions/reportportal-summarize/get-slack-message.sh b/.github/actions/reportportal-summarize/get-slack-message.sh index 02df8bbed..1a4a68463 100755 --- a/.github/actions/reportportal-summarize/get-slack-message.sh +++ b/.github/actions/reportportal-summarize/get-slack-message.sh @@ -18,15 +18,15 @@ if [[ -n "$RP_LAUNCH_KEY" ]]; then read -r status case $status in PASSED) - sstatus="✅" ;; + status_icon="✅" ;; FAILED) - sstatus="❌" + status_icon="❌" ;; *) - sstatus="$status" + status_icon="$status" ;; esac - MSG+="\n<$RP_LAUNCH_URL/$id|Report #$number> $sstatus" + MSG+="\n<$RP_LAUNCH_URL/$id|Report #$number> $status_icon" done < <(echo "$RP_CONTENT" | jq -r '.content[] | .id, .number, .status') fi fi diff --git a/.github/actions/reportportal-summarize/get-teams-message.sh b/.github/actions/reportportal-summarize/get-teams-message.sh new file mode 100755 index 000000000..d043070c8 --- /dev/null +++ b/.github/actions/reportportal-summarize/get-teams-message.sh @@ -0,0 +1,34 @@ +#!/bin/bash -e + +if [[ -n "$RP_LAUNCH_KEY" ]]; then + + NB=$(echo "$RP_CONTENT" | jq -r '.page.totalElements // "0"') + if [[ "$NB" == "0" || -z "$NB" ]]; then + MSG+="No report found for key "'`'"$RP_LAUNCH_KEY"'`'"." + MSG+="\n\nSee [latest reports]($RP_LAUNCH_URL)." + elif [ "$NB" == "1" ]; then + RP_LAUNCH_ID=$(echo "$RP_CONTENT" | jq -r '.content[0].id // empty') + STATUS=$(echo "$RP_CONTENT" | jq -r '.content[0].status // empty') + [[ "$STATUS" == 'PASSED' ]] && ICON="✅" || ICON="❌" + MSG+="See [report]($RP_LAUNCH_URL/$RP_LAUNCH_ID) $ICON" + else + MSG+="$NB reports found for key "'`'"$RP_LAUNCH_KEY"'`'"." + while read -r id ; do + read -r number + read -r status + case $status in + PASSED) + status_icon="✅" ;; + FAILED) + status_icon="❌" + ;; + *) + status_icon="$status" + ;; + esac + MSG+="\n\n[Report #$number]($RP_LAUNCH_URL/$id) $status_icon" + done < <(echo "$RP_CONTENT" | jq -r '.content[] | .id, .number, .status') + fi +fi + +echo "message=$MSG" >> $GITHUB_OUTPUT diff --git a/.github/actions/reportportal-summarize/tests/get-teams-message.bats b/.github/actions/reportportal-summarize/tests/get-teams-message.bats new file mode 100644 index 000000000..8c4dd8eeb --- /dev/null +++ b/.github/actions/reportportal-summarize/tests/get-teams-message.bats @@ -0,0 +1,92 @@ +setup() { + # Runs everywhere + DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" + PATH="$DIR/..:$PATH" + + export GITHUB_OUTPUT="$BATS_TMPDIR"/test-get-teams-message_ghoutput_"$RANDOM"'.log' + > $GITHUB_OUTPUT + + export RP_LAUNCH_KEY=my-tests-push-3665876492 + export RP_TOKEN=tok + export RP_URL=https://rpserver:8080 + + export RP_CONTENT="" + export RP_LAUNCH_URL=https://rpserver:8080/ui/#my-project/launches/all + + export NO_MESSAGE="message=" + export KEY_NO_REPORT="message=No report found for key \`my-tests-push-3665876492\`.\n\nSee [latest reports](https://rpserver:8080/ui/#my-project/launches/all)." + export SINGLE_REPORT="message=See [report](https://rpserver:8080/ui/#my-project/launches/all/88) ✅" + export MULTIPLE_REPORTS=$(cat << BATS +message=3 reports found for key \`my-tests-push-3665876492\`.\n\n[Report #3](https://rpserver:8080/ui/#my-project/launches/all/91) ❌\n\n[Report #2](https://rpserver:8080/ui/#my-project/launches/all/90) WHATEVER_STATUS\n\n[Report #1](https://rpserver:8080/ui/#my-project/launches/all/89) ✅ +BATS +) +} + +teardown() { + rm -f $GITHUB_OUTPUT +} + +@test "teams message rp disabled" { + export RP_LAUNCH_KEY="" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] +} + +@test "teams message no launch id" { + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] +} + +@test "teams message single" { + export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launch.json)" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$SINGLE_REPORT" ] +} + +@test "teams message multiple" { + export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launches.json)" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$MULTIPLE_REPORTS" ] +} + +@test "teams message rp failure no results" { + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] +} + +@test "teams message rp failure no results empty json" { + export RP_CONTENT="{}" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] +} + +@test "teams message rp success no results" { + export OUTCOME="success" + export RP_CONTENT="$(< $BATS_TEST_DIRNAME/empty-launch.json)" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] +} + +@test "teams message rp failure no results empty json no launch key" { + export RP_LAUNCH_KEY="" + export RP_CONTENT="{}" + run get-teams-message.sh + [ "$status" -eq 0 ] + echo "$(< $GITHUB_OUTPUT)" + [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] + +} diff --git a/.github/actions/send-teams-notification/action.yml b/.github/actions/send-teams-notification/action.yml index f83cda119..12530cf79 100644 --- a/.github/actions/send-teams-notification/action.yml +++ b/.github/actions/send-teams-notification/action.yml @@ -4,70 +4,261 @@ inputs: webhook-url: description: Microsoft Teams Incoming Webhooks URL required: true + title: + description: 'Text to show as message title' + required: false + message: + description: An optional message that overrides the default one + required: false + append: + description: Whether the optional message should be added after the default one + required: false + default: "false" needs: - description: JSON parsed needs context + description: 'JSON parsed needs context' required: false - default: "" + default: '{}' dry-run: description: Do not actually send the message required: false default: 'false' - raw: - description: JSON object to send to Microsoft Teams - required: false - default: "" - overwrite: - description: JSON like object to overwrite default message - required: false - default: >- - { - title: `${{github.actor}} initialized ${{ github.event_name}} event on ${{ github.repository }} of branch ${{ github.ref_name}}`, - "potentialAction": [ - { - "@type": "OpenUri", - "name": "Repository", - "targets": [ - { - "os": "default", - "uri": "${{ github.server_url }}/${{ github.repository }}" - } - ] - }, - { - "@type": "OpenUri", - "name": "Build URL", - "targets": [ - { - "os": "default", - "uri": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } - ] - }, - { - "@type": "OpenUri", - "name": "Compare", - "targets": [ - { - "os": "default", - "uri": "${{ github.event.compare }}" - } - ] - } - ] - } + runs: using: composite steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Check workflow status + + - name: Compute workflow status + id: compute-workflow-status uses: martialonline/workflow-status@fe13c6a4716673e224038aa1b02387352fb35e13 # v4 - id: workflow_status_check + + - name: Compute color + shell: bash + id: compute-color + env: + STATUS: ${{ steps.compute-workflow-status.outputs.status }} + run: | + COLOR=808080 + case $STATUS in + success) + COLOR=36A64F + ;; + failure) + COLOR=A30200 + ;; + esac + echo "result=$COLOR" >> $GITHUB_OUTPUT + + - name: Compute small sha + id: compute-small-sha + shell: bash + env: + GITHUB_LONG_SHA: ${{ github.sha }} + run: | + SMALL_SHA=${GITHUB_LONG_SHA:0:6} + echo "result=$SMALL_SHA" >> $GITHUB_OUTPUT + + - name: Compute needs + id: compute-needs + shell: bash + env: + NEEDS: ${{ inputs.needs }} + run: | + NEEDS_OUTPUT=$(echo $NEEDS | jq -r 'to_entries[] | "\(.key): \(.value.result)"') + echo "result=$NEEDS_OUTPUT" >> $GITHUB_OUTPUT + + - name: Compute message + id: compute-message + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + BLOCK_MESSAGE: ${{ inputs.message }} + APPEND: ${{ inputs.append }} + PR_TITLE: ${{ github.event.pull_request.title }} + ISSUE_BODY: ${{ github.event.issue.body }} + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + NEEDS: ${{ steps.compute-needs.outputs.result }} + run: | + ${{ github.action_path }}/compute-message.sh >> $GITHUB_OUTPUT + + - name: Compute event + id: compute-event + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + REPO_URL: ${{ github.server_url }}/${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + SHA: ${{ github.sha }} + run: | + RESULT="$EVENT_NAME" + if [[ "$EVENT_NAME" == 'pull_request' ]]; then + RESULT="[$EVENT_NAME #$PR_NUMBER]($REPO_URL/pull/$PR_NUMBER)" + elif [[ "$EVENT_NAME" == 'push' ]]; then + RESULT="[$EVENT_NAME]($REPO_URL/commit/$SHA/checks)" + fi + echo "result=$RESULT" >> $GITHUB_OUTPUT + + - name: Compute run link + id: compute-run-link + shell: bash + env: + REPO_URL: ${{ github.server_url }}/${{ github.repository }} + WORKFLOW: ${{ github.workflow }} + run: | + RESULT="$REPO_URL/actions/runs/$GITHUB_RUN_ID/attempts/$GITHUB_RUN_ATTEMPT" + echo "result=$RESULT" >> $GITHUB_OUTPUT + + - name: Compute workflow title + id: compute-workflow-title + shell: bash + run: | + RESULT="$GITHUB_WORKFLOW" + if [[ "$GITHUB_RUN_ATTEMPT" != '1' ]]; then + RESULT+=" (attempt #$GITHUB_RUN_ATTEMPT)" + fi + echo "result=$RESULT" >> $GITHUB_OUTPUT + + - name: Get branch name + uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v8.4.0 + - name: Send teams notification - uses: skitionek/notify-microsoft-teams@9c67757f64d610fb6748d8ff3c11f284355ed7ec # v1.0.8 + uses: skitionek/notify-microsoft-teams@190d4d92146df11f854709774a4dae6eaf5e2aa3 # master + env: + ACTOR_URL: ${{ github.server_url }}/${{ github.triggering_actor }} + REPO_URL: ${{ github.server_url }}/${{ github.repository }} + SMALL_SHA: ${{ steps.compute-small-sha.outputs.result }} + MESSAGE_OUTPUT: ${{ steps.compute-message.outputs.result }} + RUN_LINK: ${{ steps.compute-run-link.outputs.result }} + WORKFLOW_TITLE: ${{ steps.compute-workflow-title.outputs.result }} + COLOR: ${{ steps.compute-color.outputs.result }} + TITLE: "Notification on ${{ steps.compute-event.outputs.result }} on branch [`${{ env.BRANCH_NAME }}`](${{ env.REPO_URL }}/tree/${{ env.BRANCH_NAME }})" with: webhook_url: ${{ inputs.webhook-url }} - job: ${{ toJSON(steps.workflow_status_check.outputs) }} - needs: ${{ inputs.needs }} + job: "{}" + steps: "{}" + needs: "{}" dry_run: ${{ inputs.dry-run }} - overwrite: ${{ inputs.overwrite }} - raw: ${{ inputs.raw }} + raw: >- + { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "type": "AdaptiveCard", + "body": [ + { + "type": "TextBlock", + "size": "medium", + "weight": "bolder", + "text": "${{ inputs.title || env.TITLE }}", + "style": "heading", + "wrap": true + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "Image", + "style": "person", + "url": "${{ env.ACTOR_URL }}.png?size=32", + "altText": "${{ github.triggering_actor }}", + "size": "small" + } + ], + "width": "auto" + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "[${{ github.triggering_actor }}](${{ env.ACTOR_URL }})" + } + ] + }, + { + "type": "Column", + "items": [ + { + "type": "Image", + "style": "person", + "url": "https://slack.github.com/static/img/favicon-neutral.png", + "altText": "GitHub", + "size": "small" + } + ], + "width": "auto" + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "[${{ github.repository }}](${{ env.REPO_URL }})" + } + ] + } + ] + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "**Action**: [${{ env.WORKFLOW_TITLE }}](${{ env.RUN_LINK }})" + } + ] + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "**Commit**: [`${{ env.SMALL_SHA }}`](${{ env.REPO_URL }}/commit/${{ github.sha }})" + } + ] + } + ] + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "**Message**" + }, + { + "type": "TextBlock", + "text": "${{ env.MESSAGE_OUTPUT }} " + } + ] + } + ] + } + ], + "backgroundImage": { + "url": "https://singlecolorimage.com/get/${{ env.COLOR }}/2x2", + "fillMode": "RepeatHorizontally" + }, + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5", + "msteams": { + "width": "full", + "entities": [ + {} + ] + } + } + } + ] + } diff --git a/.github/actions/send-teams-notification/compute-message.sh b/.github/actions/send-teams-notification/compute-message.sh new file mode 100755 index 000000000..76daf8ff6 --- /dev/null +++ b/.github/actions/send-teams-notification/compute-message.sh @@ -0,0 +1,41 @@ +#!/bin/bash -e + +COMPUTED_MESSAGE="" + +if [ -n "$NEEDS" ]; then + COMPUTED_MESSAGE="$NEEDS\n\n" +fi + +if [[ -n "$BLOCK_MESSAGE" && "$APPEND" == 'true' ]] || [ -z "$BLOCK_MESSAGE" ]; then + case $EVENT_NAME in + pull_request) + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}$PR_TITLE" + ;; + issues) + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}$ISSUE_BODY" + ;; + *) + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}$COMMIT_MESSAGE" + ;; + esac +fi + +if [ -n "$BLOCK_MESSAGE" ]; then + if [[ "$APPEND" == 'true' && -n "$COMPUTED_MESSAGE" ]]; then + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}\n\n" + fi + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}$BLOCK_MESSAGE" +fi + +if [ -n "$COMPUTED_MESSAGE" ]; then + COMPUTED_MESSAGE="${COMPUTED_MESSAGE}" + COMPUTED_MESSAGE=$(printf "${COMPUTED_MESSAGE}" | sed -z 's/\n/\\n/g' | sed -r 's/"/\\\"/g' | sed -e 's/\r//g') + # avoid error if message is too long (total message must be less than 3001 characters) + COMPUTED_MESSAGE=${COMPUTED_MESSAGE:0:3000} + echo 'result< +EOF +BATS +) + + [ "$output" = "$expected_output" ] +} + +@test "empty teams message" { + export COMMIT_MESSAGE="" + + run compute-message.sh + + [ "$status" -eq 0 ] + + expected_output=$(cat << BATS +result= +BATS +) + + [ "$output" = "$expected_output" ] +} + +@test "empty block message" { + export BLOCK_MESSAGE="" + + run compute-message.sh + + [ "$status" -eq 0 ] + + expected_output=$(cat << BATS +result<