A Python library and CLI for parsing and managing GitHub CODEOWNERS files
Project description
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, ordocs/CODEOWNERS - Pattern syntax: Same as
.gitignore(with some limitations) - Owner types:
- GitHub usernames:
@username - Teams:
@org/team-name - Email addresses:
user@example.com
- GitHub usernames:
- 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.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file github_codeowners-0.1.0.tar.gz.
File metadata
- Download URL: github_codeowners-0.1.0.tar.gz
- Upload date:
- Size: 18.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c71d707aa779f84f747f7c291c22bd56426557da3ba0026464fec8ebf4c64a09
|
|
| MD5 |
65fdc5eaa717a648809ce4bf82f02a57
|
|
| BLAKE2b-256 |
9149a951629a69de7e91674108dc0526c6a89040e6ce3eb91c9611001d634493
|
Provenance
The following attestation bundles were made for github_codeowners-0.1.0.tar.gz:
Publisher:
increment-version-and-publish.yml on henryupton/github-codeowners
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
github_codeowners-0.1.0.tar.gz -
Subject digest:
c71d707aa779f84f747f7c291c22bd56426557da3ba0026464fec8ebf4c64a09 - Sigstore transparency entry: 611246598
- Sigstore integration time:
-
Permalink:
henryupton/github-codeowners@e66d933e5571fdb05100ff7a1a24d3fb0e0f1e3b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/henryupton
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
increment-version-and-publish.yml@e66d933e5571fdb05100ff7a1a24d3fb0e0f1e3b -
Trigger Event:
push
-
Statement type:
File details
Details for the file github_codeowners-0.1.0-py3-none-any.whl.
File metadata
- Download URL: github_codeowners-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e96f0b31c9826bdb5968529f0950eda6ba279185c8a4e5ed28ffbbd845c4bdb1
|
|
| MD5 |
7579ed08489f2048bd62714f0a2be5bc
|
|
| BLAKE2b-256 |
1609323deb965f09170528e626962786cc89f08524f4ddf5de27b84a6a348229
|
Provenance
The following attestation bundles were made for github_codeowners-0.1.0-py3-none-any.whl:
Publisher:
increment-version-and-publish.yml on henryupton/github-codeowners
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
github_codeowners-0.1.0-py3-none-any.whl -
Subject digest:
e96f0b31c9826bdb5968529f0950eda6ba279185c8a4e5ed28ffbbd845c4bdb1 - Sigstore transparency entry: 611246609
- Sigstore integration time:
-
Permalink:
henryupton/github-codeowners@e66d933e5571fdb05100ff7a1a24d3fb0e0f1e3b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/henryupton
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
increment-version-and-publish.yml@e66d933e5571fdb05100ff7a1a24d3fb0e0f1e3b -
Trigger Event:
push
-
Statement type: