githubgithub-actionsslack-apislack-block-kit

Github Actions: how to return empty string if ${{ toJson() }} returns null?


Here's my GitHub Actions .yml script that will send a notification to Slack when a Pull Request is open, commented, merge & close, or close.

name: Pull Request Notice
on:
  pull_request:
    types:
      - opened
    branches:
      - 'main'
  issue_comment:
    types:
      - created
  workflow_dispatch:
jobs:
  open_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Send Open PR Body to Slack
        uses: slackapi/slack-github-action@v1.21.0
        if: github.event.pull_request.state == 'open' || github.event.issue.pull_request.state == 'open'
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
          BODY: ${{ toJson(github.event.pull_request.body) || github.event.pull_request.body }}
        with:
          # For posting a rich message using Block Kit
          payload: |
            {
              "attachments": [
                {
                  "color": "#36a64f",
                  "blocks": [
                    {
                      "type": "header",
                      "text": {
                        "type": "plain_text",
                        "text": ":recycle: PR: ${{ github.event.repository.name }}"
                      }
                    },
                    {
                      "type": "context",
                      "elements": [
                        {
                          "text": "*${{ github.event.pull_request.created_at }}*  |  Opened by: ${{ github.event.pull_request.user.login }}",
                          "type": "mrkdwn"
                        }
                      ]
                    },
                    {
                      "type": "divider"
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*${{ github.event.pull_request.title }}*\n${{ github.event.pull_request.html_url }}"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Branch:* `${{ github.head_ref }}`"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Message:*"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": ${{ env.BODY }}
                      }
                    }
                  ]
                }
              ]
            }
      - name: Send Merged PR Body to Slack
        uses: slackapi/slack-github-action@v1.21.0
        if: github.event.issue.pull_request.state == 'closed' && github.event.issue.pull_request.merged
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
        with:
          # For posting a rich message using Block Kit
          payload: |
            {
              "attachments": [
                {
                  "color": "#8250df",
                  "blocks": [
                    {
                      "type": "header",
                      "text": {
                        "type": "plain_text",
                        "text": ":scorpius: PR: ${{ github.event.repository.name }}"
                      }
                    },
                    {
                      "type": "context",
                      "elements": [
                        {
                          "text": "*${{ github.event.issue.pull_request.created_at }}*  |  Merged by: ${{ github.event.issue.pull_request.user.login }}",
                          "type": "mrkdwn"
                        }
                      ]
                    },
                    {
                      "type": "divider"
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*${{ github.event.issue.pull_request.title }}*\n${{ github.event.issue.pull_request.html_url }}"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Branch:* ${{ github.head_ref }}"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Message:*\n${{ github.event.comment.body }}"
                      }
                    }
                  ]
                }
              ]
            }
      - name: Send Closed PR Body to Slack
        uses: slackapi/slack-github-action@v1.21.0
        if: github.event.issue.state == 'closed'
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
          BODY: ${{ toJson(github.event.comment.body) || github.event.comment.body }}
        with:
          # For posting a rich message using Block Kit
          payload: |
            {
              "attachments": [
                {
                  "color": "#cf222e",
                  "blocks": [
                    {
                      "type": "header",
                      "text": {
                        "type": "plain_text",
                        "text": ":x: PR: ${{ github.event.repository.name }}"
                      }
                    },
                    {
                      "type": "context",
                      "elements": [
                        {
                          "text": "*${{ github.event.issue.closed_at }}*  |  Closed by: ${{ github.event.comment.user.login }}",
                          "type": "mrkdwn"
                        }
                      ]
                    },
                    {
                      "type": "divider"
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*${{ github.event.issue.title }}*\n${{ github.event.issue.html_url }}"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Branch:* ${{ github.ref_name }}"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "*Comment:*"
                      }
                    },
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": ${{ env.BODY }}
                      }
                    }
                  ]
                }
              ]
            }

However, it fails when the Pull Request body is empty, resulting in invalid JSON.

Github Action fail

This is due to the fact that the Slack API Text Object > text field being a "Required" field: https://api.slack.com/reference/block-kit/composition-objects#text

As you can see from my script, I'm trying to post different message based on the PR status. There is a lot of repeating code due to the if: checking.

Is there a way to perform a conditional if checking within the steps, or within the env: declaration?

For example:

env:
  COLOR: ${{ github.event.pull_request.state == 'open' ? '#36a64f' : '#cf222e' }}
  BODY: ${{ github.event.pull_request.body == null ? 'N/A' : toJson(github.event.pull_request.body) }}

Any help or suggestion to make the script better would be greatly appreciated!


Solution

  • The issue has been solved by placing an expression with the || OR operator within the toJson() function.

    ...
    env:
      NA: _n/a_
    with:
    ...
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ${{ toJson(github.event.pull_request.body || env.BODY) }}
      }
    }
    ...
    

    It will result in "n/a"(underscore for italicised) in the JSON property if the Pull request body is empty.