---
title: Enforcing a "Do Not Merge" label with Github Actions
date: 2023-02-18T12:33:32-05:00
toc: false
images:
tags:
  - dev
---

At my workplace, we sometimes find ourselves in situations where a PR passes all
tests, and has been reviewed and approved, but still shouldn't be merged.
Sometimes this is because that PR needs some other work in another repository to
be merged and deployed first. Sometimes it's because merging the PR will
kickstart some process like sending out emails, and we are waiting to start that
process at a certain time.

Whatever the reason, our convention is that we add a "Do Not Merge" label to the
PR. But we recently had a case where someone didn't see the label and clicked
the merge button anyway. I can tell you that it's not fun scrambling to hit the
"cancel action" button on Github before the code gets deployed! So we started
looking into a way to prevent such issues.

Now, you might ask why we don't just leave these PRs as drafts. While that would
stop them from being merged on an accidental click, there is still some risk
that someone might just mark it ready for review and merge it without checking
the label. We also have some automation set up, like automatically changing card
state when a PR is marked as ready, which would not work if we leave PRs in
draft. Luckily, I found a better solution.

After coming across this [post from Jesse Squires](https://www.jessesquires.com/blog/2021/08/24/useful-label-based-github-actions-workflows/),
I decided to try the improved version of a "Do Not Merge" check he suggests.

```yml
name: Do Not Merge

on:
  pull_request:
    types: [synchronize, opened, reopened, labeled, unlabeled]

jobs:
  do-not-merge:
    if: ${{ contains(github.event.*.labels.*.name, 'do not merge') }}
    name: Prevent Merging
    runs-on: ubuntu-latest
    steps:
      - name: Check for label
        run: |
          echo "Pull request is labeled as 'do not merge'"
          echo "This workflow fails so that the pull request cannot be merged"
          exit 1
```

Our first attempt was dropping this into the repository, which worked, but we
have a lot of repositories and we sometimes create new ones too. Having to copy
this check to all repositories seems like a lot of work! But thanks to a
coworker discovering that you can set repository-wide workflows, we were able to
set up all of this organization-wide.

To do that, you first add this workflow file in some repository. It doesn't need
to be (and probably shouldn't be) in your `.github/workflows` folder. You might
even want to create a new repository to contain just this workflow file.

![A github repository, with a single file named do-not-merge.yml at the root of the repository. The file contains the code listed earlier in this page.](/img/gh-do-not-merge-action.png)

Next, go to your organization settings and select "Actions > General" on the
side menu.

![Github side bar menu, with heading Action expanded, and General selected inside that section.](/img/gh-menu-actions-general.png)

Scroll to the bottom, where you'll find "Required workflows". Click
to add a workflow.

![The required workflows section in Github organization settings. An "Add workflow" button is present.](/img/gh-required-workflows.png)

Then select the repository where you added your action, and
write the path to the workflow file within that repository.

![Add required workflow page. The previously mentioned repository is selected, and the path do-not-merge.yml is written next to that. A selection below has picked 'All repositories'.](/img/gh-required-workflows-config.png)


You're now done! All PRs in all repositories will run the do not merge label
check, and will prevent you from merging any PR with the label.

![The checks section on a PR page. A check named "Do Not Merge" has failed, and the merge button is disabled. Github warns that all checks must pass before merging.](/img/gh-do-not-merge-fail.png)

One caveat is
that there seems to be a bug on Github's end of things where for any PR that was
open at the time you added this check, the check gets stuck with the message
"Expected - Waiting for status to be reported". If that happens, add the "do not
merge" label then remove it. This will remind Github to actually run the check.

To make the experience a bit smoother for new repositories, you can also add "do
not merge" as a default PR label. To do so, go to the "Repository > Repository
defaults" section on the side bar.

![Github side bar menu, with heading Repository expanded, and Repository defaults selected inside that section.](/img/gh-repository-defaults.png)

Click "New label", and create a label named
"do not merge".

![The repository labels section in Github organization settings. A new label is being added, with the name do not merge.](/img/gh-repository-defaults-labels.png)

This will only apply to new repositories, so you may need to add
the label to your existing repositories. But even if you don't add the label to
the repository, the check should not block you so you don't have to worry about
going through all your repositories to add this label.
