Search code examples
github-actions

Is it possible to make Github Actions ignore 'edited' activity when it's only PR body change?


I'm using Github Enterprise.

Below is the workflow to allow PR to be merged only if PR changes pass test.

on:
  pull_request:
    branches: [...]
    types: [opened, reopened, synchronize, edited]

jobs:
  test:
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

    steps:
      ...

Apparently edited activity also includes changing just the body of PR as well as changing the base, so I tried to ignore it by putting if statement like below:

jobs:
  test:
    if: github.event.action != 'edited' || github.event.changes.base
    runs-on: self-hosted
    steps:
      ...

But problem is that Github accepts skipped test as "success". skipped check

Which means that PR that fails test job can be merged if PR body changes after.

I tried to use needs: in test job, so test can run only when it's code changes, but Github accepts the fact that test job is not run as "failure".

How can I make Github not consider runs for PR check that are triggered by changing PR body?

Solution

This is the exact way I solved it, thanks to @Azeem.

name: foo

on:
  pull_request:
    branches: [...]
    types: [opened, reopened, synchronize, edited]

concurrency:
  group: ${{ github.event.pull_request.head.sha }}
  cancel-in-progress: false

jobs:
  prepare:
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

  check-the-last-test-status:
    needs: prepare
    runs-on: self-hosted
    outputs:
      status: ${{ steps.check-status.outputs.result }}
    steps:
      - name: Check the 'test' status of the latest commit (${{ github.event.pull_request.head.sha }})
        id: check-status
        if: ${{ github.event.action == 'edited' && !github.event.changes.base }}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          IS_THE_LAST_TEST_SUCCESS=$(gh run list \
            --workflow "foo" \
            --event pull_request \
            --branch ${{ github.event.pull_request.head.ref }} \
            --commit ${{ github.event.pull_request.head.sha }} \
            --json status,conclusion \
            --jq '[.[] | select(.status == "completed" and .conclusion == "success")] | any')
          echo "Is the last test success: $IS_THE_LAST_TEST_SUCCESS"
          if [[ "$IS_THE_LAST_TEST_SUCCESS" == 'true' ]]; then
            echo "result=success" >> $GITHUB_OUTPUT
          else
            echo "result=failure" >> $GITHUB_OUTPUT
          fi;

      - name: Cancel
        if: steps.check-status.conclusion != 'skipped' && steps.check-status.outputs.result == 'failure'
        run: |
          gh run cancel ${{ github.run_id }}
          gh run watch ${{ github.run_id }}


  test:
    needs: check-the-last-test-status
    if: needs.check-the-last-test-status.outputs.status != 'success'
    runs-on: self-hosted
    steps:
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20.10.0'

      - ...

Solution

  • Yes, the edited action of the pull_request event means that:

    The title or body of a pull request was edited, or the base branch of a pull request was changed.


    For your specific use case, if the PR's title or body is edited, you can fetch the result of the previous workflow run using GitHub CLI's gh run list command, evaluate it, set the result as an output parameter (at job or step level) and use it for further decision making.

    Here's an example:

    - name: Check last workflow run status
      id: last-run
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        STATUS=$(gh run list \
          --workflow test \
          --event pull_request \
          --branch "$GITHUB_HEAD_REF" \
          --limit 1 \
          --json status,conclusion \
          --jq '.[].status == "completed" and .[].conclusion == "success"')
        echo "STATUS=$STATUS" >>"$GITHUB_OUTPUT"
    
    - name: Tests
      if: ${{ steps.last-run.outputs.STATUS == 'false' }}
      run: ...
    

    You can expand on this idea and adapt it according to your use case.