Skip to main content

github-codeowners

A Python library and CLI for parsing, validating, and managing GitHub CODEOWNERS files. Perfect for CI/CD pipelines and automation workflows.

Features

  • Parse CODEOWNERS files into structured Python objects
  • Validate CODEOWNERS syntax and structure
  • Programmatically add, remove, and modify ownership rules
  • Command-line interface for common operations
  • Support for all CODEOWNERS features:
    • Multiple owner types (@username, @org/team, email addresses)
    • Pattern-based file matching
    • Proper precedence handling

Installation

pip install github-codeowners==0.0.1

For development:

git clone https://github.com/henryupton/github-codeowners.git
cd github-codeowners
pip install -e ".[dev]"

Quick Start

Command Line Usage

The codeowners CLI provides several commands for managing CODEOWNERS files:

# Show parsed CODEOWNERS file
codeowners show
codeowners show --repo /path/to/repo
codeowners show /path/to/CODEOWNERS

# Validate CODEOWNERS syntax
codeowners validate
codeowners validate --repo /path/to/repo

# Add a new rule
codeowners add-rule "*.py" @python-team @user1
codeowners add-rule "docs/**" @docs-team --comment "Documentation owners"

# Remove a rule
codeowners remove-rule "*.py"

# Add an owner to existing rule
codeowners add-owner "*.py" @new-maintainer

# Remove an owner from a rule
codeowners remove-owner "*.py" @old-maintainer

# Reformat the file
codeowners format
codeowners format --output CODEOWNERS.new

Python API Usage

from github_codeowners import (
    parse_codeowners_file,
    write_codeowners_file,
    CodeOwnersFile,
)

# Parse an existing CODEOWNERS file
codeowners = parse_codeowners_file(".github/CODEOWNERS")

# Access rules
for entry in codeowners.get_rules():
    print(f"{entry.pattern}: {[str(o) for o in entry.owners]}")

# Add a new rule
codeowners.add_rule("*.js", ["@frontend-team", "@user1"])

# Add a comment
codeowners.add_comment("Frontend code owners")

# Write back to disk
write_codeowners_file(codeowners, ".github/CODEOWNERS")

CLI Commands

show

Display the parsed CODEOWNERS file with line numbers and entry types.

codeowners show [FILE] [--repo PATH]

validate

Validate the CODEOWNERS file syntax and check for common issues.

codeowners validate [FILE] [--repo PATH]

Exit codes:

  • 0: Valid
  • 1: Validation errors or file not found

format

Parse and rewrite the CODEOWNERS file, normalizing formatting.

codeowners format [FILE] [--repo PATH] [--output PATH]

add-rule

Add a new ownership rule.

codeowners add-rule PATTERN OWNERS... [FILE] [OPTIONS]

Options:
  --repo PATH        Repository root (auto-find CODEOWNERS)
  --output PATH      Output file (default: overwrite input)
  --comment TEXT     Inline comment for the rule

Example:

codeowners add-rule "*.py" @python-team @user1 --comment "Python files"

remove-rule

Remove rules matching a pattern.

codeowners remove-rule PATTERN [FILE] [OPTIONS]

add-owner

Add an owner to an existing rule.

codeowners add-owner PATTERN OWNER [FILE] [OPTIONS]

Example:

codeowners add-owner "*.py" @new-maintainer

remove-owner

Remove an owner from an existing rule.

codeowners remove-owner PATTERN OWNER [FILE] [OPTIONS]

Python API

Parsing

from github_codeowners import parse_codeowners, parse_codeowners_file
from github_codeowners.parser import find_codeowners_file

# Parse from string
content = "*.py @python-team\n*.js @frontend-team"
codeowners = parse_codeowners(content)

# Parse from file
codeowners = parse_codeowners_file("/path/to/CODEOWNERS")

# Auto-find CODEOWNERS in repository
codeowners_path = find_codeowners_file("/path/to/repo")
codeowners = parse_codeowners_file(codeowners_path)

Creating and Modifying

from github_codeowners import CodeOwnersFile, CodeOwner

# Create a new CODEOWNERS file
codeowners = CodeOwnersFile()

# Add rules
codeowners.add_rule("*.py", ["@python-team", "@user1"])
codeowners.add_rule("docs/**", ["@docs-team"])

# Add comments and blank lines
codeowners.add_blank()
codeowners.add_comment("Frontend section")
codeowners.add_rule("*.js", ["@frontend-team"])

# Find and modify rules
rules = codeowners.find_rules_for_pattern("*.py")
for rule in rules:
    # Add an owner
    rule.owners.append(CodeOwner.from_string("@new-owner"))
    # Modify inline comment
    rule.comment = "Updated comment"

Writing

from github_codeowners import write_codeowners, write_codeowners_file

# Write to string
content = write_codeowners(codeowners)
print(content)

# Write to file
write_codeowners_file(codeowners, ".github/CODEOWNERS")

# Create parent directories if needed
write_codeowners_file(codeowners, ".github/CODEOWNERS", create_dirs=True)

Working with Entries

# Iterate over all entries
for entry in codeowners.entries:
    if entry.is_rule():
        print(f"Pattern: {entry.pattern}")
        print(f"Owners: {[str(o) for o in entry.owners]}")
        if entry.comment:
            print(f"Comment: {entry.comment}")
    elif entry.is_comment():
        print(f"Comment: {entry.comment}")
    elif entry.is_blank():
        print("Blank line")

# Get only rules
rules = codeowners.get_rules()

# Find specific rules
py_rules = codeowners.find_rules_for_pattern("*.py")

# Remove entries
codeowners.remove_entry(entry)

# Clear all entries
codeowners.clear()

CI/CD Integration

GitHub Actions

name: Validate CODEOWNERS

on: [pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.9'
      - name: Install github-codeowners
        run: pip install github-codeowners
      - name: Validate CODEOWNERS
        run: codeowners validate

GitLab CI

validate-codeowners:
  image: python:3.9
  script:
    - pip install github-codeowners
    - codeowners validate
  only:
    - merge_requests

Pre-commit Hook

Add to .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: validate-codeowners
        name: Validate CODEOWNERS
        entry: codeowners validate
        language: system
        pass_filenames: false

CODEOWNERS Format

This library supports the full GitHub CODEOWNERS format:

  • Location: .github/CODEOWNERS, CODEOWNERS, or docs/CODEOWNERS
  • Pattern syntax: Same as .gitignore (with some limitations)
  • Owner types:
    • GitHub usernames: @username
    • Teams: @org/team-name
    • Email addresses: user@example.com
  • Comments: Lines starting with #
  • Inline comments: pattern @owner # comment
  • Precedence: Last matching pattern wins

Example CODEOWNERS file:

# Default owner for everything
* @default-owner

# Frontend
*.js @frontend-team
*.css @frontend-team
*.html @frontend-team

# Backend
*.py @backend-team @senior-dev

# Documentation
docs/** @docs-team @tech-writer

# CI/CD
.github/** @devops-team

Development

# Clone the repository
git clone https://github.com/yourusername/github-codeowners.git
cd github-codeowners

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black src/ tests/

# Type checking
mypy src/

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Metadata

Release files for github-codeowners 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for github-codeowners 0.1.0
File Size Uploaded
github_codeowners-0.1.0.tar.gz 18.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for github-codeowners 0.1.0
File Interpreter ABI Platform
github_codeowners-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 30.1 kB

Release files / github_codeowners-0.1.0.tar.gz

Download URL github_codeowners-0.1.0.tar.gz
Size 18.6 kB
Tags Source
SHA-256 checksum
How to use checksums
c71d707aa779f84f747f7c291c22bd56426557da3ba0026464fec8ebf4c64a09
BLAKE2b-256 checksum
How to use checksums
9149a951629a69de7e91674108dc0526c6a89040e6ce3eb91c9611001d634493
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2025.

Transparency log

Release files / github_codeowners-0.1.0-py3-none-any.whl

Download URL github_codeowners-0.1.0-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e96f0b31c9826bdb5968529f0950eda6ba279185c8a4e5ed28ffbbd845c4bdb1
BLAKE2b-256 checksum
How to use checksums
1609323deb965f09170528e626962786cc89f08524f4ddf5de27b84a6a348229
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page