A modern guide to CODEOWNERS
In software development, numerous people touch the same code, and it’s crucial to keep track of who is responsible for what. This is where CODEOWNERS
come into play.
The CODEOWNERS
feature allows you to specify individuals or teams who are responsible for code in a repository, making it easier to manage your projects. This feature can streamline the review process, enhance security, and make sure the right people are responsible for the right code.
In this guide, you’ll learn all about why you need CODEOWNERS
and how to effectively use this feature in your software development workflow.
Why you need CODEOWNERS
In order to outline who is responsible for different sections of a codebase, you need to create a CODEOWNERS
file in your repository. When a pull request (PR) is opened that touches files listed in the CODEOWNERS
file, the designated code owner is automatically asked to review that section of the code. Several popular code hosting platforms support this feature, including GitHub, GitLab, and Bitbucket.
Following are some of the reasons why you should consider implementing CODEOWNERS
into your software project:
- Enhanced security measures: Defining
CODEOWNERS
creates a safeguard, ensuring that only designated users or teams can sign off on changes to specific areas of the codebase. This reduces the likelihood of unauthorized or accidental alterations to the code. - Streamlined review mechanism: When you use
CODEOWNERS
, you automate the process of identifying the most appropriate reviewers for each PR. This minimizes delays and ensures that each PR is examined by someone with domain-specific knowledge, elevating the quality of the review. - Increased sense of accountability: Allocating certain code sections to specific maintainers not only speeds up the review process but also instills a greater sense of responsibility. When you’re a named code owner, you’re more likely to be proactive about code quality, documentation, and other best practices.
- Automated processes for greater efficiency: When you incorporate
CODEOWNERS
into your continuous integration, continuous delivery (CI/CD) workflows, you automate the initial step of code review. This means that the right eyes are reviewing the code quickly, which is crucial for rapid development cycles and high-velocity teams.
When you implement CODEOWNERS
, you’re not merely inserting a file into your repository; you’re fundamentally improving how your project is managed, secured, and maintained.
Getting started with CODEOWNERS
If you have a repository without a CODEOWNERS
file, any member can review a PR without restrictions. This means that critical pieces of code can be modified without proper oversight.
To avoid this situation, you need to create a CODEOWNERS
file using the following steps:
Create a new file named CODEOWNERS
inside a docs
folder at the root of your project. Then add your first entry like this:
* @your-username
When someone opens a PR, @your-username
will be asked to review it.
In this scenario, let’s assume you have a sample GitHub repository with the following structure:
sample-codeowners-test/
|-- docs/
| |-- CODEOWNERS
|
|-- src/
| |-- hello.py
|
|-- tests/
| |-- test_hello.py
|
|-- README.md
Please note: Putting the
CODEOWNERS
file in thedocs
folder applies to both GitHub and GitLab. Additionally, make sure you replace the@your-username
with your username.
To enable or disable CODEOWNERS
in your GitHub repository, you need to define a rule set. To do so, you need to go to your repository Settings and click on Rules > Rulesets in the left navigation bar. Then enable Require a pull request before merging and Require review from Code Owners:
If you’re using GitLab, you can enable CODEOWNERS
on a protected branch. For more information on how to do this, refer to this GitLab documentation:
Disabling CODEOWNERS
If you disable the Require review from Code Owners option in your GitHub Settings or if you remove the Require approval from code owners in GitLab, then the PR can be merged without a review from the designated code owners. While this can speed up the merge process, it does so at the expense of code quality and security:
For all the following examples, this option is enabled.
Avoiding common pitfalls with the CODEOWNERS file
Navigating the complexities of repository management can be challenging. Avoiding missteps in the CODEOWNERS
file setup is crucial for streamlined code reviews.
Create a CODEOWNERS file, but leave it empty
If you create a CODEOWNERS
file but leave it empty, no one is assigned to review PRs. While this won’t block the PR process, you lose the advantages of having specified reviewers, which is generally not recommended.
In this scenario, any user with write access can approve code before it’s merged.
Define a path without any users assigned
When setting up a CODEOWNERS file, it’s essential to assign users or teams to specific paths. However, consider this improper configuration:
src/*
tests/*
Here, you define two paths in your CODEOWNERS
file: tests/*
and src/*
. But you don’t assign any users or teams to it. In this scenario, no one is automatically assigned to review PRs affecting files in the tests
and src
directories. This contradicts the purpose of using a CODEOWNERS
file and should be avoided.
Create a team without any members in it
In organizational setups, there may arise a need to initialize a team structure even before members are allocated. Let’s assume the CODEOWNERS
file has the following content:
* @your-org/your-empty-team
If you define a team in your CODEOWNERS
file (ie @your-org/your-empty-team
) but that team has no members, the PR will not have any automatic reviewers. In this case, the merge is blocked unless you add a member to the team. It’s best to make sure that each team has at least one member before adding it to your CODEOWNERS
file:
Using the CODEOWNERS file properly
Effective codebase management requires a deep knowledge of the tools available. This is why it’s crucial to understand how to properly utilize the CODEOWNERS
file, as it facilitates precise delegation of responsibility.
Basic ownership
If you have a simple team and want one or two people to be responsible for all code, your CODEOWNERS
file might look like this:
# The user @your-username is the code owner for the entire repository
* @your-username
Any PR related to changes in your code needs the approval of @your-username
:
Department-based ownership
In a larger organization, you might have different departments responsible for different aspects of the code, like this:
# The Engineering department is responsible for all source code
src/* @Your-Org/EngineeringTeam
# The Quality Assurance team is responsible for all tests
tests/* @Your-Org/QATeam
# The Documentation team is responsible for the README file
/README.md @Your-Org/DocumentationTeam
Any PR related to changes under the src
folder requires the approval of a member from the @EngineeringTeam
. The changes in the tests
folder require approval from a member of the @QATeam
, and the README.md
file require approval from the @DocumentationTeam
:
Please note: When specifying a team, you need to make sure that this team has
write
access to your repository. To define the team’s name, you need to put the organization name followed by a forward slash as well as the team’s name:@Your-Org/QATeam
.
Multilevel ownership
Sometimes, you’ll have a hierarchy of responsibilities. In this scenario, you can specify multiple code owners like this:
# The Core team is responsible for the entire codebase
* @Your-Org/CoreTeam
# But specific modules have additional specialized owners
src/hello.py @Your-Org/PythonExperts @Your-Org/CoreTeam
# The tests have their own owners, in addition to being under the CoreTeam
tests/* @Your-Org/TestTeam @Your-Org/CoreTeam
Here, a change to src/hello.py
requires approval from someone in either @Your-Org/PythonExperts
or @Your-Org/CoreTeam
; whereas changes to something in the tests
folder requires approval from either @Your-Org/TestTeam
or @Your-Org/CoreTeam
.
Exclusion rules
You can also negate ownership for specific files or folders like this:
# The Core team is responsible for the entire codebase
* @Your-Org/CoreTeam
# Except for the hello.py, which is maintained by the Python team
/src/hello.py @Your-Org/PythonTeam
In this scenario, the @Your-Org/CoreTeam
is responsible for everything except src/hello.py
, which is the sole responsibility of the @Your-Org/PythonTeam
.
By choosing the right setup for your team’s needs, you can use the CODEOWNERS
file to enforce code quality and ensure that the right people are reviewing changes to different parts of your codebase.
How team and user permissions affect CODEOWNERS
When managing code, understanding permissions is imperative. In simple terms, permissions decide who can do what in a project. Features like CODEOWNERS
use these permissions to decide who can review and approve code changes. In order to use CODEOWNERS
effectively, you need to know how these permissions are set and what they mean.
In GitHub, you can set permissions at an organization level, at the repository level, or within teams. Your CODEOWNERS
settings are affected by these permissions. For instance, if a user doesn’t have write access to a repo, they can’t be a code owner.
The CODEOWNERS
feature doesn’t operate in isolation; it’s tied to the permissions model of the platform you’re using. Say you set a team as a code owner, but individual members of that team don’t have the necessary repository-level permissions. In this case, the CODEOWNERS
setting won’t function as expected, and the team members won’t be able to act on the PR in the capacity of a code owner. The same applies to users.
In GitLab, the permission model is similar but uses different naming conventions. You have to be at least a Maintainer
in a project to become a code owner. Similar to GitHub, GitLab also demands a certain level of permissions for a user to be named as a code owner. Notably, the Maintainer
role allows for a broad set of permissions, including the ability to merge code and manage the repository. This is essential for code owners to effectively review and approve code changes.
If you designate a Developer
in GitLab as a code owner, the setting will not take effect because the user doesn’t possess the requisite permissions to enforce code ownership rules. For more information on how it works, check out the GitLab documentation.
Regardless of the platform you’re using, understanding the interplay between CODEOWNERS
and permissions is critical for setting up an effective and secure code review process.
Conclusion
In this article, you learned about the importance of implementing CODEOWNERS
in your projects. Not only does it offer an extra layer of security by designating who can approve changes, but it also streamlines the PR review process and fosters a sense of ownership among project maintainers.
Additionally, integrating a CODEOWNERS
file can bring about a cultural shift within your development team. It encourages clear accountability, ensuring that specific individuals or teams are responsible for particular codebases. This clarity can help prevent code rot since everyone knows who to go to for improvements or bug fixes, enhancing long-term maintainability.
Moreover, CODEOWNERS
can serve as an excellent documentation tool. New team members can immediately understand which parts of the codebase are owned by which teams, easing the onboarding process and enhancing project transparency. It can also help external contributors identify whom they should contact for code-specific queries or clarifications, which fosters a more collaborative environment.
Aviator: Automate your cumbersome processes
Aviator automates tedious developer workflows by managing git Pull Requests (PRs) and continuous integration test (CI) runs to help your team avoid broken builds, streamline cumbersome merge processes, manage cross-PR dependencies, and handle flaky tests while maintaining their security compliance.
There are 4 key components to Aviator:
- MergeQueue – an automated queue that manages the merging workflow for your GitHub repository to help protect important branches from broken builds. The Aviator bot uses GitHub Labels to identify Pull Requests (PRs) that are ready to be merged, validates CI checks, processes semantic conflicts, and merges the PRs automatically.
- ChangeSets – workflows to synchronize validating and merging multiple PRs within the same repository or multiple repositories. Useful when your team often sees groups of related PRs that need to be merged together, or otherwise treated as a single broader unit of change.
- TestDeck – a tool to automatically detect, take action on, and process results from flaky tests in your CI infrastructure.
- Stacked PRs CLI – a command line tool that helps developers manage cross-PR dependencies. This tool also automates syncing and merging of stacked PRs. Useful when your team wants to promote a culture of smaller, incremental PRs instead of large changes, or when your workflows involve keeping multiple, dependent PRs in sync.