Code Reviews at Scale in Monorepos: Using CODEOWNERS and GitHub Actions for Automation

As teams scale and repositories grow, especially in monorepos, code reviews can become a bottleneck rather than a safeguard.
Read the articles by Shantanu Das in the Aviator blog. Get professional advice on software product deployment, testing, and other engineering topics.

Code Reviews at Scale in Monorepos: Using CODEOWNERS and GitHub Actions for Automation

As teams scale and repositories grow, especially in monorepos, code reviews can become a bottleneck rather than a safeguard.
code reviews

This article explores real-world problems engineers face in monorepos and how to automate code reviews using CODEOWNERS, GitHub Actions, policy bots, and related technologies. We’ll introduce hands-on solutions, performance trade-offs, and a structured approach to scaling reviews efficiently.

When working with monorepos, you encounter complex challenges during code reviews.

challenges during code reviews

By using tools like CODEOWNERS, GitHub Actions, and policy bots, you can solve these challenges of unclear ownership, overlapping changes, slow approvals, dependency conflicts, and compliance overhead. Automation helps assign ownership of different parts of the code, makes code reviews faster and more organized, and keeps everything consistent and compliant with the rules. With the correct setup, you can enjoy all the benefits of a monorepo without being bogged down by its challenges.

Introduction to CODEOWNERS

The CODEOWNERS file is a GitHub feature that automatically assigns code reviewers based on file paths. It helps distribute code review responsibilities clearly without manual intervention.

Setting Up a CODEOWNERS File

Create a CODEOWNERS file in the root of your repository or in the .github/ folder.

# Assigning reviewers based on file paths
/frontend/      @frontend-team
/backend/       @backend-team
*.js            @javascript-gurus

Now, whenever a pull request modifies files inside /frontend/, GitHub will automatically assign @frontend-team to review it. This system ensures every PR is routed to the right people for the quick and easy review process.

review process

Why Enforce Code Reviews with CODEOWNERS?

If you are collaborating in a team, here’s how CODEOWNERS help:

  1. Everyone knows who is responsible for which parts of the code, so there is no confusion about who should review a PR.
  2. PRs are automatically sent to the correct reviewers, saving time and speeding up the process.
  3. When it’s clear who owns what, teams can collaborate more effectively, avoiding overlap or delays.

For instance, if a developer modifies the payment processing code, the CODEOWNERS file automatically assigns the review task to the payments team. This prevents the developer from accidentally sending the review to someone unfamiliar with the payment code, saving time and reducing errors. However, to truly enforce these reviews and maintain high code quality, teams need a way to ensure that changes aren’t merged without proper approval. This is where GitHub Branch Protection Rules come in.

Setting up Reviews with GitHub Branch Protection Rules

GitHub Branch Protection Rules ensure that certain conditions must be met before the code is merged into a branch. When used with CODEOWNERS, they require code changes to be reviewed by the assigned owners before merging.

Here’s how branch protection rules can help:

  1. Ensuring all changes go through review: Imagine a developer makes updates to the authentication system. Without branch protection, they could accidentally merge unreviewed changes, potentially introducing security vulnerabilities. With protection rules in place, GitHub prevents the merge until the assigned authentication experts review and approve the changes.
  1. Guaranteeing quality with assigned reviewers: Suppose a team is working on a new feature for handling user payments. Since payments are a critical part of the system, the branch protection rule ensures that at least one payments team member, as defined in CODEOWNERS, must approve the pull request before merging. This guarantees that someone with domain expertise has reviewed the code.
  1. Restricting merges unless tests and security scans pass: If a developer modifies an API that handles sensitive customer data, automated security scans and unit tests must run before the merge is allowed. If any security vulnerability or test failure is detected, the merge is blocked, preventing potential issues from reaching production.

Setting Up Branch Protection Rules

Go to your GitHub repository. Click on Settings > Branches. Under Branch protection rules, click New ruleset.

In the Target branches, enter the main or any protected branch.

Enable “Require a pull request before merging”. Enable “Require review from Code Owners”. Optionally, enable “Require status checks to pass” before merging to ensure tests pass.

Click Create to save the ruleset. Now, GitHub will block merges unless the required reviews are completed.

By combining branch protection with CODEOWNERS, only assigned teams can approve their code areas. Automated workflows can verify additional quality checks before merging. Also, it ensures regulatory compliance in projects requiring strict review processes. However, manual code reviews can still introduce bottlenecks, especially in large teams or fast-moving projects. This is where GitHub Actions comes in.

Automating Code Reviews with GitHub Actions

Automating workflows with GitHub Actions allows developers to automate tasks like assigning reviewers, running linters, or enforcing security policies when a PR is opened. Instead of relying on manual checks, GitHub Actions ensures PRs meet project standards before reaching a reviewer.

How Does GitHub Actions Work?

GitHub Actions uses a simple .yml file to define workflows. These workflows are triggered by specific events, such as opening a pull request or pushing code to a branch.

Here’s a basic GitHub Actions workflow: .github/workflows/code-review.yml. You can use this to automate the code review process:

Code Review Workflow 
on: 
  pull_request: 
    paths: 
      - "**/*.js" 
      - "**/*.py" 
jobs: 
  review: 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout code 
        uses: actions/checkout@v3 
      - name: Run Linter 
        run: npm run lint 
    - name: Assign Reviewers 
        uses: .github/actions/assign-reviewers  

Here’s what this workflow does:

  1. The workflow starts whenever a PR includes changes to .js or .py files.
  2. It pulls the updated code so the workflow can analyze it.
  3. This step checks that the code follows the required style and quality guidelines.
  4. It automatically tags the right reviewers, guided by the CODEOWNERS file.

GitHub Actions for Code Reviews

Automated workflows save time by letting GitHub handle repetitive tasks like assigning reviewers or running checks. You can catch issues early with tools like linters, and static analysis can detect bugs or style violations before human reviewers even see the code. You can enforce standards to ensure your team follows consistent coding practices across all projects. Setting up GitHub Actions for your code reviews will streamline the process, reduce manual work, and maintain high-quality standards. It’s a smart way to improve your workflows.

While GitHub Actions helps automate code reviews and maintain quality standards, some projects require even stricter guidelines enforcement. This is especially true for teams managing security policies, compliance requirements, or large monorepos with multiple contributors. This is where Policy Bots come in.

What Is a Policy Bot?

A policy bot is like a rules enforcer for your project. Its job is to ensure that every pull request (PR) follows your team’s guidelines, including coding standards, security checks, and avoiding risky changes that could disrupt your project.

Here’s why teams must use a policy bot:

  1. Developers can focus on writing code instead of constantly checking for guideline violations.
  2. A policy bot can handle the heavy lifting, even in large monorepos with lots of contributors.

How to Set Up a Policy Bot

Integrating a policy bot into your project, especially with GitHub Actions, is simple. Here’s an essential guide:

  1. Choose a policy bot tool. Several pre-built tools are available, or you can create a custom one tailored to your needs.
  2. Define the rules it needs to check. For example:
    • The code must follow style guidelines.
    • All tests must pass before merging.
    • No sensitive information, like API keys, should be in the code.
  3. Add a workflow that triggers the bot every time a PR is created or updated.

Here’s an example of how a policy bot might fit into a GitHub Actions setup:

name: Policy Bot 
on: 
  pull_request: 
jobs: 
  policy-check: 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout Code 
        uses: actions/checkout@v3 
      - name: Run Policy Bot Checks 
        run: npm run policy-check  

Here’s what this workflow does:

  1. It runs whenever a PR is created or updated.
  2. It pulls the latest changes so the bot can analyze them.
  3. It executes a script or tool to enforce your project’s rules.

With a policy bot in place, your team can focus on building features, knowing that the bot keeps the codebase in check. It’s a powerful way to ensure quality at scale.

How Automation Transforms Code Reviews

Imagine a SaaS company managing a large monorepo. It’s full of different projects, and multiple teams are working on the same codebase, with multiple teams contributing code daily. While the monorepo helps with collaboration, it’s also causing some headaches. For example, reviews are too slow, and pull requests (PRs) often sit idle, waiting for someone to review them. Unclear Ownership means no one knows who’s responsible for what part of the codebase. Inconsistent Standards give rise to coding guidelines that vary from one PR to another, making the codebase messy.

This company decided to fix the problem by automating its workflow. Here’s what they did:

1. Added a CODEOWNERS File: They assigned ownership of different parts of the codebase. For example:

  • /frontend/ was assigned to the frontend team.
  • /backend/ was assigned to the backend team.

When someone makes changes, the right people are automatically notified for review.

2. Set Up GitHub Actions: They created workflows to handle repetitive tasks like running linters to check code style, performing static analysis to catch bugs early, and automatically tagging the correct reviewers for PRs.

3. Deployed a Policy Bot: The bot was configured to enforce coding standards. For example, rejecting PRs with hardcoded API keys, ensuring all tests pass before merging, and verifying compliance with style guidelines.

General Benefits of Automation in Code Reviews:

  • Automating reviewer assignments and checks significantly reduces delays.
  • Tools enforce consistent coding standards, catching bugs early and avoiding errors.
  • Developers spend more time on needle-moving tasks than repetitive ones.

Open Policy Agent (OPA) for Policy Enforcement

For small teams, simple rule-based policy bots may be enough. However, as projects grow, especially in infrastructure-as-code environments like Terraform, Kubernetes, and cloud deployments, manual enforcement of policies becomes impractical. This is where Open Policy Agent (OPA) shines.

OPA provides a centralized, flexible way to enforce policies across different systems, including code reviews, CI/CD pipelines, and infrastructure provisioning. It ensures that only compliant changes are merged, reducing security risks and misconfigurations.

OPA works with policy bots by:

  1. Defining policies in Rego, a declarative language for writing rules.
  2. Evaluating PRs against policies before allowing merges.
  3. Blocking PRs that introduce security vulnerabilities or violate coding standards.

Implementing OPA in a Policy Bot

Create a Rego policy file to define rules in policy.rego.

package policy

violation["Avoid TODO comments in production code"] {
    input.content contains "TODO"
}

Install OPA in your CI/CD pipeline and update the GitHub Actions workflow to enforce the policy:

name: Policy Bot with OPA
on: pull_request
jobs:
  policy-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3
      - name: Setup OPA
        uses: open-policy-agent/setup-opa@v2
        with:
          version: latest
      - name: Run OPA Policy Check
        run: |
          opa eval --data policy.rego --input input.json --format pretty
    -  name: Run Policy Bot Checks
        run: npm run policy-check

With OPA integrated, the policy bot will automatically reject PRs that contain TODO comments or other violations while also running additional custom policy checks.

How to Maintain Scalable Code Reviews

You can maintain scalable code reviews by:

  1. Reflecting team changes and shifting responsibilities in your CODEOWNERS file.
  2. Assigning the same file to multiple teams can create confusion and delays.
  3. Periodically audit your CODEOWNERS file and workflows to ensure they align with your current needs.
  4. Automating as much as possible to catch issues early.
  5. Ensure everyone understands how to effectively use CODEOWNERS and GitHub Actions.

Conclusion

Managing code reviews in a monorepo doesn’t have to be complicated. By leveraging CODEOWNERS, GitHub Actions, policy bots, and Open Policy Agent (OPA), teams can:

  1. Automate reviewer assignments with CODEOWNERS to ensure the right people review changes.
  2. Enforce structured review processes using GitHub Branch Protection Rules.
  3. Streamline quality checks with GitHub Actions, automating linting, security scans, and CI/CD validation.
  4. Apply consistent policies with policy bots and OPA, blocking non-compliant or risky changes before they are merged.

FAQs

1. What Challenges do Monorepos Present for Code Reviews?

Monorepos can make it difficult to assign ownership, and maintainers get confused about who owns what part of the code, leading to slower reviews due to overlapping responsibilities. It also adds complexity in managing dependencies and setting coding standards.

2. How does a CODEOWNERS File Work in GitHub?

The CODEOWNERS file maps specific files or folders in a repository to teams or people responsible for reviewing changes. This means that the pull requests are automatically assigned to the right reviewers.

3. Where Should I Place the CODEOWNERS File in a Repository?

The CODEOWNERS file is typically placed in the repository’s root directory, .github/, or a specific subfolder.

Subscribe

Be the first to know once we publish a new blog post

Join our Discord

Learn best practices from modern engineering teams

Get a free 30-min consultation with the Aviator team to improve developer experience across your organization.

Powered by WordPress