Github Action for PR comment with command output on exit status

Here’s a Github Action that runs a given bash command, captures the stdout and strderr output, and posts a comment with the output back to the PR if the command has a non-zero exit status.

This is useful for running check commands such as linters against a PR, and making a PR comment with the linter output if there are linting errors.

name: Command & Comment
description: Run a bash command and comment failure output back to PR
inputs:
  identifier:
    description: Single word identifier for the check command
    required: true
  bash_command:
    description: Bash command to run and comment from
    required: true
runs:
  using: "composite"
  steps:
    - uses: ./.github/actions/job_url
      id: job_url
      with:
        step_name: ${{inputs.identifier}}
    - id: check_command
      name: ${{inputs.identifier}}
      shell: bash
      run: |
        set +e
        echo "COMMAND_OUT<<EOF" | tee "$GITHUB_OUTPUT"
        ${{inputs.bash_command}} 2>&1 | sed 's/$/\\n/g' | tr -d '\n' | tee -a "$GITHUB_OUTPUT" ; COMMAND_STATUS=$?
        ( echo ; echo "EOF" ) | tee -a "$GITHUB_OUTPUT"
        exit $COMMAND_STATUS
    - name: Remove previous command comments
      uses: ./.github/actions/remove_comments
      if: always()
      with:
        identifier: ${{inputs.identifier}}
    - name: PR comment command failure
      uses: actions/github-script@v7
      if: always() && steps.check_command.outcome == 'failure'
      with:
        script: |
          github.rest.issues.createComment({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: context.issue.number,
            body: '[${{inputs.identifier}}](${{steps.job_url.outputs.job_url}})\n\n```\n${{steps.check_command.outputs.COMMAND_OUT}}```'
          })

Note that this uses separate actions to get the job URL and to remove previous PR comments.

The bash step to run the given command and capture the output and exit status looks like this:

set +e
echo "COMMAND_OUT<<EOF" | tee "$GITHUB_OUTPUT"
${{inputs.bash_command}} 2>&1 | sed 's/$/\\n/g' | tr -d '\n' | tee -a "$GITHUB_OUTPUT" ; COMMAND_STATUS=$?
( echo ; echo "EOF" ) | tee -a "$GITHUB_OUTPUT"

That is subsequently picked up in a Github Script step that posts a PR comment with the job URL and the failed command output in a Markdown block:

github.rest.issues.createComment({
  owner: context.repo.owner,
  repo: context.repo.repo,
  issue_number: context.issue.number,
  body: '[${{inputs.identifier}}](${{steps.job_url.outputs.job_url}})\n\n```\n${{steps.check_command.outputs.COMMAND_OUT}}```'
})

You can use this command-and-comment action like this:

# ...
jobs:
  isort:
    name: isort
    description: Run isort check and post output on failure
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/command_comment
        id: isort
        with:
          identifier: isort
          bash_command: isort . --check

Tech mentioned