GitHub Actions: Automatic conflicting pull request tagging and comment

Sep 13, 2020

Open-source repositories enable tremendous productivity in software development. Growth in user base usually translates in growth in contributors, which in turns translates in a better solution bringing more users and so on… Maintaining large open-source repositories can be time-consuming as you spend more and more time reviewing contributions. Don’t take me wrong, that time spent reviewing pull requests is mostly well spent as it represents a factor of scale efficiency gain: for minutes spent reviewing any given pull request, the codebase benefits hours of development efforts invested by the contributor.

Because people are chosing to spend their time contributing to your project, which they could be spending a million other ways, you want to make sure their pull request is looked at as soon as possible, and let them know as soon as a problem emmerges. A fluid review experience not only ensures that the pull request will end up being merged but it also encourages contributors to submit more pull requests in the future. At the same time, you want to use as many tools as possible to avoid open source maintainers burnout. You might already know that I really enjoy automating as much trivial work as possible so I can spend my time on value-adding tasks.

One problem a pull request can encounter is a merge conflict. Let’s suppose Alice and Bob both have brilliant ideas to add to your project, at about the same time. They both forked the repository and started working. Alice was faster at finishing her pull request and submitted it first, quickly followed by Bob. They both introduced changes in files that conflict with each other (edited the same lines). You start by reviewing Alice’s pull request, it’s pristine, and you decide to merge it right away. Now your attention is required somewhere else and you don’t look at Bob’s.

It is generally accepted that contributors should submit clean pull requests (no conflicts, code builds and passes unit tests, atomic, docs updated…) and they should maintain it in a clean state until the pull request gets merged. Bob’s pull request will show the following status, requiring the conflicts to be resolved before it can be merged into the codebase.

pull request conflicting status

This status does not send any notification to the contributor, and it doesn’t display anything on any list. This makes it hard for you as a maintainer to identify at glance which pull requests are conflicting so you can focus on reviewing the ones that are ready. This can also stall the pull request unless Bob comes check on his pull request and why it hasn’t been merged yet or unless you take the time to leave a comment asking Bob to resolve conflicts.

This friction and latency point can easily be improved through automation using GitHub actions workflows. This workflow is currently being used by the Microsoft Graph Docs repository and by some Microsoft Graph SDK repositories. It triggers on pushes to the master branch as well as on pull requests targeting the master branch and uses the eps1lon/actions-label-merge-conflict action to:

  1. Identify which pull requests are now conflicting/not conflicting anymore based on the last update.
  2. Automatically add/remove tags based on this information so it’s easier for you to identify at glance which pull requests are conflicting.
  3. Automatically comment based on the information so the contributors receive a notification.

You can see that conflicting pull requests are much easier to identify (and even filter out) when looking at all the pull requests on the repository.

conflicting pull requests status

Here is an example of what a message for a conflicting pull request looks like.

conflicting pull request message

Lastly, here is the sample worklow. You need to place this file under /.github/workflows/somename.yml in your repository and you can of course tweak it to your convenience.

Note: you might wonder why this workflow triggers on push. That is because GITHUB_TOKEN for pull requests coming from forks will have read-only permissions, which prevents it from labeling and/or commenting issues. The action goes through all the open pull requests whenever it’s triggered on push.

name: PullRequestConflicting

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
  push:
    branches: [ master, dev ]
  pull_request:
    types: [synchronize]
    branches: [ master, dev ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    - name: check if prs are dirty
      uses: eps1lon/actions-label-merge-conflict@releases/2.x
      if: env.LABELING_TOKEN != '' && env.LABELING_TOKEN != null
      id: check
      with:
        dirtyLabel: "conflicting"
        repoToken: "${{ secrets.GITHUB_TOKEN  }}"
        continueOnMissingPermissions: true
        commentOnDirty: 'This pull request has conflicting changes, the author must resolve the conflicts before this pull request can be merged.'
        commentOnClean: 'Conflicts have been resolved. A maintainer will take a look shortly.'
      env:
        LABELING_TOKEN: ${{secrets.GITHUB_TOKEN }}

Last edited Sep 6, 2021 by Vincent


Tags: