Header

Prevent Mistakes with NOMERGE Comments in CI/CD Pipelines

I added support for NOMERGE comments to our codebase, which the CI pipeline uses to prevent temporary, unfinished, or debug code from being released accidentally.

How many times have you left a console log in prod? Do you ever forget what you still need to do before releasing some code? How often do you comment something out and forget to re-add it before releasing?

For me, constantly. Hopefully it's pretty common for you too. This blog post won't be very popular if it turns out that I'm the only one.

At TalkJS we solved it with NOMERGE comments. Think of them like TODOs you can't forget. Because I think we've all experienced this:

core.ts

function centralMethodUsedEverywhere(opt: Options) { // TODO IMPORTANT: add validations for all options /* ... */ } /* > git blame > 3176a8d9611 frontend/core.ts (steven waterman 2019-02-21 11:35:33 +0000 2) */

How?

We use GitHub actions for CI. It was as simple as adding a new job which greps the codebase for NOMERGE. If found, the CI job will fail, making it clear that there's something that you forgot to do.

nomerge.yml

name: "Check for NoMerge comments" concurrency: group: nomerge-${{ github.ref }} cancel-in-progress: true on: pull_request: types: - synchronize - opened - reopened - labeled jobs: search: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # Way faster than grep - run: sudo apt install silversearcher-ag # Fail whenever it finds 'NoMerge' case-insensitive # Ignore the .git folder # Ignore this file # Look in .github .husky etc but not ../ # This also listens to .gitignore etc - run: "! ag -i --ignore=git --ignore=nomerge.yml NoMerge .[^.]* ."

Why?

I use nomerge comments any time there's something that must happen before the code is released:

  • To track the things I haven't implemented yet:
    // NOMERGE add pagination support
  • To stop myself from committing my debug logs:
    console.log("NOMERGE batching ran")
  • When deliberately breaking things to reproduce bugs:
    // NOMERGE this terminates the connection whenever immediately
  • When doing dangerous things to make experimentation easier:
    // NOMERGE this means we don't verify auth tokens
  • When I'm deep in flow but have a concerning thought:
    // NOMERGE I think these events could happen out of order
  • When reviewing big PRs and GitHub's UI is too clunky:
    // NOMERGE Does this code ever run?

There are better ways to prevent some of these issues. Linting can catch a stray console.log, and your tests could catch a deliberately-broken class. But they're not perfect, and I've found NOMERGE to be incredibly useful and versatile.


Also, I can't believe it's been over a year since I last posted. Apparently my last post was a depressing mologue about how overwhelming society is, and how I wanted to become a medieval shepherd. Things are better. I got therapy. I'll update at some point. I have exciting shepherd thoughts.