GitHub Actions:toJson返回null时返回空字符串及脚本优化求助
解决GitHub Actions Slack PR通知的空值问题与代码优化
一、空值问题解决方案
Slack API要求Text Object的text字段为必填项,当PR内容或评论内容为空时,会导致生成无效JSON而执行失败。可以通过以下方式处理:
1. 用coalesce函数设置默认值
GitHub Actions支持coalesce函数,它会返回第一个非空的参数值,适合处理多场景下的空值:
CONTENT_BODY: ${{ toJson(coalesce(github.event.pull_request.body, github.event.comment.body, 'N/A')) }}
- 优先取PR正文,若为空则取评论正文,两者都为空时用
N/A替代 - 外层包裹
toJson确保文本转义正确,避免破坏JSON结构
2. 三元运算符兜底
如果需要更明确的条件判断,也可以用三元运算符:
CONTENT_BODY: ${{ toJson(github.event.pull_request.body != '' ? github.event.pull_request.body : (github.event.comment.body != '' ? github.event.comment.body : 'N/A')) }}
二、代码优化方案
原脚本通过多个独立步骤处理不同PR状态,存在大量重复代码。可以通过动态环境变量+单发送步骤的方式重构:
核心思路
将不同状态的差异化参数(颜色、图标、时间、操作人等)通过条件表达式定义在环境变量中,然后在统一的Slack发送步骤里引用这些变量,实现代码复用。
优化后的完整脚本
name: Pull Request Notice on: pull_request: types: [opened, closed] branches: ['main'] issue_comment: types: [created] workflow_dispatch: jobs: pr_notification: runs-on: ubuntu-latest env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK # 动态设置通知颜色 NOTIFICATION_COLOR: >- ${{ github.event_name == 'pull_request' && github.event.action == 'opened' ? '#36a64f' : github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged ? '#8250df' : github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.issue.state == 'closed' && github.event.issue.pull_request.merged ? '#8250df' : '#cf222e' }} # 动态设置标题图标与状态文本 NOTIFICATION_HEADER: >- ${{ github.event_name == 'pull_request' && github.event.action == 'opened' ? ':recycle: PR Opened: ' : github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged ? ':scorpius: PR Merged: ' : github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.issue.state == 'closed' && github.event.issue.pull_request.merged ? ':scorpius: PR Merged: ' : ':x: PR Closed: ' }} # 统一PR核心字段(兼容不同触发事件的路径差异) PR_TITLE: ${{ github.event.pull_request.title || github.event.issue.title }} PR_URL: ${{ github.event.pull_request.html_url || github.event.issue.html_url }} PR_BRANCH: ${{ github.event.pull_request.head.ref || github.head_ref || github.ref_name }} # 动态设置时间戳 TIMESTAMP: >- ${{ github.event_name == 'pull_request' && github.event.action == 'opened' ? github.event.pull_request.created_at : github.event_name == 'pull_request' && github.event.action == 'closed' ? github.event.pull_request.closed_at : github.event.issue.closed_at }} # 动态设置操作人 ACTOR: >- ${{ github.event_name == 'pull_request' && github.event.action == 'opened' ? github.event.pull_request.user.login : github.event_name == 'pull_request' && github.event.action == 'closed' ? github.event.pull_request.merged_by.login : github.event.comment.user.login }} # 处理空内容的正文 CONTENT_BODY: ${{ toJson(coalesce(github.event.pull_request.body, github.event.comment.body, 'N/A')) }} # 动态设置内容标题(Message/Comment) CONTENT_LABEL: ${{ github.event_name == 'pull_request' && github.event.action == 'opened' ? 'Message' : 'Comment' }} steps: - name: Send PR Notification to Slack uses: slackapi/slack-github-action@v1.21.0 if: >- (github.event_name == 'pull_request') || (github.event_name == 'issue_comment' && github.event.issue.pull_request) with: payload: | { "attachments": [ { "color": "${{ env.NOTIFICATION_COLOR }}", "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": "${{ env.NOTIFICATION_HEADER }} ${{ github.event.repository.name }}" } }, { "type": "context", "elements": [ { "text": "*${{ env.TIMESTAMP }}* | ${{ env.NOTIFICATION_HEADER == ':recycle: PR Opened: ' && 'Opened by' || env.NOTIFICATION_HEADER == ':scorpius: PR Merged: ' && 'Merged by' || 'Closed by' }}: ${{ env.ACTOR }}", "type": "mrkdwn" } ] }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "*${{ env.PR_TITLE }}*\n${{ env.PR_URL }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Branch:* `${{ env.PR_BRANCH }}`" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*${{ env.CONTENT_LABEL }}:*" } }, { "type": "section", "text": { "type": "mrkdwn", "text": ${{ env.CONTENT_BODY }} } } ] } ] }
优化点说明
- 合并重复步骤:将原有的3个发送步骤合并为1个,通过环境变量动态适配不同PR状态
- 兼容多触发场景:统一处理
pull_request(打开、合并、关闭)和issue_comment触发的通知逻辑 - 空值全局处理:通过
coalesce+toJson确保所有文本字段不会为空,避免JSON语法错误 - 逻辑更严谨:修正了原脚本中合并状态判断的不准确问题,明确区分合并关闭与直接关闭的场景
内容的提问来源于stack exchange,提问作者kenfai
相关产品推荐
相关产品推荐

