Case Study: CPython Development Workflow

Case Study: CPython Development Workflow

Julien Danjou

It’s no secret that Mergify is written in Python. Our engine is open source and is free for anyone to contribute to. That’s how we roll.

We’ve been doing Python for a long time, and that got us close to the development of Python itself and genuinely interested in their development processes.

A couple of years ago, the Python developers decided to move to git and GitHub for developing the language. What a smart move, right? 😉

What’s interesting for us is the automation workflow that Python built around GitHub. It’s pretty well set up and advanced compared to most projects. The CPython’s developers wrote and maintain bots to customize GitHub to their needs.

In this article, we decided to submit ourselves to an interesting exercise: we decrypted what CPython’s process for merging pull requests is, and how one could implement the same workflow using Mergify.

Merging Rules

CPython merging rules are pretty simple. Let’s dissect the pull request #8297 to understand the process.

CPython pull request #8297

Once a pull request is created, there a few automatic checks that are being run such as continuous integration (tests), Contributors Licensed Agreement signed, etc. A human is then mandated to review the code and to approve it. Once it’s approved, it can be merged by a human — either the one that reviewed the patch, another one, or the author of the patch themselves if they want to have a final word. It is not visible in the above screenshot, but further digging indicates that some of the continuous integration jobs are mandatory: the merge button is greyed out if any of the jobs fail.

Once everything is ok, the patch is deemed mergeable.

CPython developers created a bot, named miss-islington, that is in charge of doing the grunt work of merging the patch, adding comments or even backporting the patches to old branches. They don’t necessarily need to press the merge button themselves!

Merging with Mergify

The good news is that it is possible to implement CPython’s workflow using Mergify! How would you do that? Here’s how:

pull_request_rules:
  - name: automatic merge
    conditions:
      - status-success=continuous-integration/appveyor/pr
      - status-success=continuous-integration/travis-ci/pr
      - "#approved-reviews-by>=1"
    actions:
      merge:
        method: merge

The conditions check that the required CI systems pass and that at least one of the core reviewer approved the pull request. If so, the pull request is merged automatically. The merge automatically happens whenever the continuous integration finishes—even if it finishes after the patch has been approved. There’s no need for a human to wait behind its screen to click a button.

You could obviously fine-tune this rule as needed.

No strict workflow

CPython development workflow has a flaw that is not obvious here and that many other projects have. They ignore the risk of merging code that seems to work while it’s going to break master because it’s not up-to-date. We wrote a few months ago an article on what we call the strict workflow that can solve this, and I beg you to read it to understand what might be wrong there.

Backports

CPython creates a stable branch each time it releases a new version of the language. There are branches for Python 2.7, Python 3.6, Python 3.7, etc.

Bugs happen, and when they get fixed in the master branch, they need to be ported back to stable branches. Usually that process is done manually by developers, but in this case, the CPython developers have been smart.

CPython pull request #8251

Their miss-islington bot takes charge of doing the grunt work. It works that way:

  1. A human puts a label such as needs backport to 3.7 on a pull request.
  2. Once the pull request is merged, miss-islington creates a copy of this pull request targeting the python:3.7 branch.
  3. A human needs to approve the pull request.
  4. miss-islington merges the pull request if the continuous integration system validates it.

We think it’s an excellent workflow. Why? Because it’s exactly the one we implemented inside Mergify. Who said we are biased?

If you want your own Miss Islington for doing backports and ease your life, just write something like this in your .mergify.yml :

pull_request_rules:
  - name: backport to 2.7
    conditions:
      - label=needs backport to 2.7
    actions:
      backport:
        branches:
          - python:2.7
  - name: automerge backports
    conditions:
      - status-success=continuous-integration/appveyor/pr
      - status-success=continuous-integration/travis-ci/pr
      - author=mergify[bot]
      - head=python:2.7
    actions:
      merge:
        method: merge

This configuration makes Mergify do two things:

  1. It creates pull requests automatically when a pull request is merged with a label such as needs backport to 2.7.
  2. It automatically merge the created pull request backport if the CI pass.

This fully automatizes the management of backports. This is the same workflow that Ceph Ansible uses, as we’ve seen recently.

If you’re interested in learning more about Python development workflow, you should watch this great keynote of DjangoCon US 2018:

We built Mergify to be able to adapt to most workflows. We hope that many more projects will be able to use it and automate their development workflows.

Feel free to suggest projects with different workflows in the comment section. We’d be delighted to feature them as case studies. 😀