jsongithubyamlgithub-actions

How to reference a JSON files content from GIthub Actions and assign it to Slack Payload


I have a Github Workflow and a JSON file in my repo. The directory looks something like this (The directories referenced in the code is slightly different but it doesn't really matter)

.github/workflows/my_workflow.yml

.github/workflows/data.json

In the code below I want to replace the JSON content that is assigned to the payload key with a reference to an actual json file: .github/workflows/data.json

The goal is to create a script where instead of hardcoding the JSON to the payload key, all that data is referenced from a JSON file that can be swapped out.

This query does what I was looking for but it created another problem: Created job that takes content of JSON file, passes to Slack API but content does not interpolate

name: GitHub Push Slack Notification
on: [push, pull_request]
permissions:
  contents: write
jobs:
  notify-slack:
    runs-on: ubuntu-latest
    steps:
      - name: Send message to Slack
        uses: slackapi/slack-github-action@v1.27.0
        with:
          payload: |
            {
              "blocks": [
                  {
                    "type": "section",
                    "text": {
                      "type": "mrkdwn",
                      "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>\n\n*Developer:* ${{ github.actor }}\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit Message:* ${{ github.event.head_commit.message }}"
                    }
                  },
                  {
                    "type": "divider"
                  }
                ]
             }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

The json file contents are the following:

{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>\n\n*Developer:* ${{ github.actor }}\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit Message:* ${{ github.event.head_commit.message }}"
      }
    },
    {
      "type": "divider"
    }
  ]
}

EDIT

I have tried a number of things including creating an artifact out of the json content and then trying to reference the artifact from the Slack job. Nothing seems to work.

Each individual Job below works when I run this workflow. I can't figure out how to replace the JSON assigned to payload with the json that is created via the artifact (if there is an easier approach please feel free to demonstrate it)

I want to do (something like) this:

payload: directory/to/file.json

Code:

name: Echo JSON Content

on: [push, pull_request]
permissions:
  contents: write

jobs:

 # Works
  read-json:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v3  # Ensure the repository is checked out

      - name: Read JSON content
        run: |
          # Check if the file exists before trying to read it
          if [ -f slack_message_payload/data.json ]; then
            cat slack_message_payload/data.json > json_payload.json
          else
            echo "Error: slack_message_payload/data.json not found!"
            exit 1
          fi

      - name: Upload JSON content as artifact
        uses: actions/upload-artifact@v3
        with:
          name: json-payload
          path: json_payload.json

 # Works
  use-json:
    needs: read-json
    runs-on: ubuntu-latest
    steps:
      - name: Download JSON artifact
        uses: actions/download-artifact@v3
        with:
          name: json-payload

      - name: Use JSON content
        run: |
          # Read the downloaded artifact and print the content
          json_content=$(cat json_payload.json)
          echo "The JSON content is: $json_content"

 # Works
  notify-slack:
    runs-on: ubuntu-latest
    steps:
      - name: Send message to Slack
        uses: slackapi/slack-github-action@v1.27.0
        with:
          payload: |
            {
              "blocks": [
                  {
                    "type": "section",
                    "text": {
                      "type": "mrkdwn",
                      "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>\n\n*Developer:* ${{ github.actor }}\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit Message:* ${{ github.event.head_commit.message }}"
                    }
                  },
                  {
                    "type": "divider"
                  }
                ]
             }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

Another try

I tried doing this and got the error below.

name: GitHub Push Slack Notification with JSON Payload

on: [push, pull_request]

jobs:
  read-json:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Read JSON content from file and set output
        id: read_json
        run: |
          # Read the JSON content from the file
          json_content=$(cat slack_message_payload/data.json)

          # Print the content for debugging
          echo "JSON content: $json_content"

          # Set the content as an output for use in another job
          echo "::set-output name=json_data::$json_content"

  notify-slack:
    needs: read-json  # This job depends on the 'read-json' job
    runs-on: ubuntu-latest

    steps:
      - name: Send message to Slack
        uses: slackapi/slack-github-action@v1.27.0
        with:
          payload: ${{ needs.read-json.outputs.json_data }}  # Use the JSON content from the previous job
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

From what I can tell the directory and file is available. Here is the error (I didn't post the entire thing it is actually much larger):

Run slackapi/slack-github-action@v1.27.0
  with:
    payload-file-path-parsed: true
  env:
    SLACK_WEBHOOK_URL: ***
    SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
no custom payload was passed in, using default payload that triggered the GitHub Action
axios post failed, double check the payload being sent includes the keys Slack expects
{"message":"Request failed with status code 400","name":"AxiosError","stack":"AxiosError: Request failed with status code 400\n    at settle (/home/runner/work/_actions/slackapi/slack-github-action/v1.27.0/dist/index.js:47327:12)\n    at IncomingMessage.handleStreamEnd (/home/runner/work/_actions/slackapi/slack-github-action/v1.27.0/dist/index.js:48443:11)\n 

Another Edit.

I read that echo "json_data=$json_content" >> $GITHUB_OUTPUT replaces ::set-output

name: GitHub Push Slack Notification with JSON Payload

on: [push, pull_request]

jobs:
  read-json:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Read JSON content from file and set output
        id: read_json
        run: |
          # Read the JSON content from the file
          json_content=$(cat ./slack_message_payload/data.json)

          # Print the content for debugging
          echo "JSON content: $json_content"

          # Set the content as an output for use in another job using GITHUB_OUTPUT
          echo "json_data=$json_content" >> $GITHUB_OUTPUT  # This replaces ::set-output

  notify-slack:
    needs: read-json  # This job depends on the 'read-json' job
    runs-on: ubuntu-latest

    steps:
      - name: Send message to Slack
        uses: slackapi/slack-github-action@v1.27.0
        with:
          payload: ${{ needs.read-json.outputs.json_data }}  # Use the JSON content from the previous job
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

ERROR

Run # Read the JSON content from the file
JSON content: {
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>\n\n*Developer:* ${{ github.actor }}\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit Message:* ${{ github.event.head_commit.message }}"
      }
    },
    {
      "type": "divider"
    }
  ]
}
Error: Unable to process file command 'output' successfully.
Error: Invalid format '  "blocks": ['

Solution

  • Here's a working example with payload-file-path:

    name: slack_test
    
    on: workflow_dispatch
    
    jobs:
      ci:
        runs-on: ubuntu-latest
    
        steps:
        - name: Payload
          env:
            payload: |
              {
                "blocks": [
                  {
                    "type": "section",
                    "text": {
                      "type": "mrkdwn",
                      "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>\n\n*Developer:* ${{ github.actor }}\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit Message:* ${{ github.event.head_commit.message }}"
                    }
                  },
                  {
                    "type": "divider"
                  }
                ]
              }
          run: |
            echo "$payload" > payload.json
            jq . payload.json
    
        - name: Send message to Slack
          uses: slackapi/slack-github-action@v2
          with:
            webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
            webhook-type: incoming-webhook
            payload-file-path: payload.json
            payload-templated: true
    

    payload-templated: true is required for parsing templated variables in the payload file.

    Workflow run output:

    workflow run output

    Slack message:

    slack message


    UPDATE # 1

    With the separate payload file and payload-templated: true, the expressions ${{...}} are not being properly substituted. On slack message, such values are being shown as ???.

    slack message with question marks

    The issue has already been reported and being discussed here: https://github.com/slackapi/slack-github-action/issues/203

    Workflow:

    name: slack_test
    
    on: workflow_dispatch
    
    jobs:
      set-payload:
        runs-on: ubuntu-latest
    
        steps:
        - name: Checkout
          uses: actions/checkout@v4
          with:
            sparse-checkout: |
              slack_payload.json
        - name: Upload payload file
          uses: actions/upload-artifact@v4
          with:
            name: slack_payload
            path: slack_payload.json
    
      send-message:
        needs: set-payload
        runs-on: ubuntu-latest
    
        steps:
        - name: Download payload file
          uses: actions/download-artifact@v4
          with:
            name: slack_payload
    
        - name: Send message to Slack
          uses: slackapi/slack-github-action@v2
          with:
            webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
            webhook-type: incoming-webhook
            payload-file-path: slack_payload.json
            payload-templated: true
    

    UPDATE # 2

    Here's the version with env vars substitutions that is working fine:

    name: slack_test
    
    on: workflow_dispatch
    
    jobs:
      slack:
        runs-on: ubuntu-latest
    
        steps:
        - name: Checkout
          uses: actions/checkout@v4
          with:
            sparse-checkout: |
              slack_payload.json
    
        - name: Set env vars
          env:
            GITHUB_EVENT_HEAD_COMMIT_MESSAGE: '${{ github.event.head_commit.message }}'
          uses: iamazeem/substitute-action@v1
          with:
            input-files: |
              slack_payload.json
    
        - name: Dump payload file
          run: cat slack_payload.json
    
        - name: Send message to Slack
          uses: slackapi/slack-github-action@v2
          with:
            webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
            webhook-type: incoming-webhook
            payload-file-path: slack_payload.json
    

    Payload file with default env vars:

    {
      "blocks": [
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": ":large_green_circle: *Build succeeded* :large_green_circle:\n<https://github_com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}|View details>\n\n*Developer:* ${GITHUB_ACTOR}\n*Repository:* ${GITHUB_REPOSITORY}\n*Branch:* ${GITHUB_REF_NAME}\n*Commit Message:* ${GITHUB_EVENT_HEAD_COMMIT_MESSAGE}"
          }
        },
        {
          "type": "divider"
        }
      ]
    }
    

    Any other non-default variable may be set and used in the payload file as needed. For example, GITHUB_EVENT_HEAD_COMMIT_MESSAGE is not available as the default variable.

    Output (slack message):

    slack message with env vars