Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 0 additions & 67 deletions .circleci/config.yml

This file was deleted.

59 changes: 59 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: CI

on:
push:
branches:
- master
pull_request:

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: install dependencies
run: uv sync --python ${{ matrix.python-version }}

- name: tests
run: ./s/test

lint:
runs-on: ubuntu-latest
env:
CI: "true"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true

- name: Set up Python
run: uv python install 3.13

- name: install dependencies
run: uv sync --python 3.13

- name: lints
run: ./s/lint
7 changes: 0 additions & 7 deletions .isort.cfg

This file was deleted.

2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Migrate tooling to GitHub Actions, uv, and Ruff, and update the supported Python versions.

# 0.8.0 - 2025-04-25

- Fix `**/` to only match whole path segments. Thanks @RedBeard0531!
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# codeowners [![CircleCI](https://circleci.com/gh/sbdchd/codeowners.svg?style=svg)](https://circleci.com/gh/sbdchd/codeowners) [![pypi](https://img.shields.io/pypi/v/codeowners.svg)](https://pypi.org/project/codeowners/)
# codeowners [![CI](https://github.com/sbdchd/codeowners/actions/workflows/ci.yml/badge.svg)](https://github.com/sbdchd/codeowners/actions/workflows/ci.yml) [![pypi](https://img.shields.io/pypi/v/codeowners.svg)](https://pypi.org/project/codeowners/)

> Python codeowners parser based on [softprops's Rust
> library](https://crates.io/crates/codeowners) and [hmarr's Go
Expand Down Expand Up @@ -38,7 +38,7 @@ assert owners.of("test.js") == [('USERNAME', '@ghost')]
## Dev

```shell
poetry install
uv sync

s/test

Expand All @@ -55,7 +55,8 @@ s/lint
# commit release commit to GitHub

# build and publish
poetry publish --build
uv build
uv publish

# create a release in the GitHub UI
```
5 changes: 1 addition & 4 deletions codeowners/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import re
from typing import Generator, List, Optional, Pattern, Tuple

from typing_extensions import Literal
from typing import Generator, List, Literal, Optional, Pattern, Tuple

__all__ = ["CodeOwners"]

Expand Down Expand Up @@ -56,7 +54,6 @@ def path_to_regex(pattern: str) -> Pattern[str]:

iterator = enumerate(pattern_trimmed)
for i, ch in iterator:

if escaped:
regex += re.escape(ch)
escaped = False
Expand Down
57 changes: 28 additions & 29 deletions codeowners/test_codeowners.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import subprocess
import tempfile
from pathlib import Path
from typing import Dict, Iterable, List, NamedTuple, Tuple
from typing import Dict, Iterable, List, Literal, NamedTuple, Tuple

import pytest
from typing_extensions import Literal

from codeowners import CodeOwners

Expand Down Expand Up @@ -100,24 +99,24 @@ def test_github_example_matches(
) -> None:
owners = CodeOwners(EXAMPLE)
actual = owners.of(path)
assert (
actual == expected
), f"mismatch for {path}, expected: {expected}, got: {actual}"
assert actual == expected, (
f"mismatch for {path}, expected: {expected}, got: {actual}"
)


def test_gitlab_sections() -> None:
owners = CodeOwners(EXAMPLE)
code_path = "build/logs/foo.go"
actual_section_name = owners.section_name(code_path)
assert (
actual_section_name == "Logs"
), f"Expected section name of Logs for {code_path} got {actual_section_name}"
assert actual_section_name == "Logs", (
f"Expected section name of Logs for {code_path} got {actual_section_name}"
)

code_path = "foo/apps/foo.js"
actual_section_name = owners.section_name(code_path)
assert (
actual_section_name == "Another team trailing whitespace"
), f"Expected section name of 'Another team trailing whitespace' for {code_path} got {actual_section_name}"
assert actual_section_name == "Another team trailing whitespace", (
f"Expected section name of 'Another team trailing whitespace' for {code_path} got {actual_section_name}"
)


@pytest.mark.parametrize(
Expand All @@ -142,18 +141,18 @@ def test_github_example_matches_with_lines(
actual_owners, actual_line_num, actual_path, section_name = owners.matching_line(
path
)
assert (
section_name is None
), f"section name should have been None but found {section_name}"
assert (
actual_owners == expected_owners
), f"mismatch for {path}, expected: {expected_owners}, got: {actual_owners}"
assert (
actual_line_num == expected_line_num
), f"mismatch for {path}, expected linenum: {expected_line_num}, got: {actual_line_num}"
assert (
actual_line_num == expected_line_num
), f"mismatch for {path}, expected linenum: {expected_path}, got: {actual_path}"
assert section_name is None, (
f"section name should have been None but found {section_name}"
)
assert actual_owners == expected_owners, (
f"mismatch for {path}, expected: {expected_owners}, got: {actual_owners}"
)
assert actual_line_num == expected_line_num, (
f"mismatch for {path}, expected linenum: {expected_line_num}, got: {actual_line_num}"
)
assert actual_line_num == expected_line_num, (
f"mismatch for {path}, expected linenum: {expected_path}, got: {actual_path}"
)


def test_rule_missing_owner() -> None:
Expand Down Expand Up @@ -562,9 +561,9 @@ def test_specific_pattern_path_matching(
owners = CodeOwners(f"{pattern} @js-user")
matches = owners.of(path) == [("USERNAME", "@js-user")]
regex, *_ = owners.paths[0]
assert (
matches == expected
), f"""{pattern} {regex} {"matches" if expected else "shouldn't match"} {path}"""
assert matches == expected, (
f"""{pattern} {regex} {"matches" if expected else "shouldn't match"} {path}"""
)


@pytest.mark.parametrize(
Expand All @@ -591,6 +590,6 @@ def test_specific_patterns_against_git(
["git", "check-ignore", path], cwd=directory, capture_output=True
)
actual = res.returncode == 0
assert (
actual is expected
), f"match for pattern:{pattern} and path:{path} failed, expected: {expected}, actual: {actual}"
assert actual is expected, (
f"match for pattern:{pattern} and path:{path} failed, expected: {expected}, actual: {actual}"
)
1 change: 1 addition & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[mypy]
python_version = 3.10
show_column_numbers=True
pretty=False
show_error_codes = True
Expand Down
Loading