codeowners-coverage 0.2.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/PKG-INFO +11 -4
  2. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/README.md +8 -2
  3. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/pyproject.toml +4 -2
  4. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/__init__.py +1 -1
  5. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/cli.py +28 -10
  6. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/ollama_matcher.py +10 -2
  7. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/PKG-INFO +11 -4
  8. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/requires.txt +3 -1
  9. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_ollama_matcher.py +8 -4
  10. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/setup.cfg +0 -0
  11. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/__main__.py +0 -0
  12. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/checker.py +0 -0
  13. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/config.py +0 -0
  14. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/directory_consolidator.py +0 -0
  15. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/git_analyzer.py +0 -0
  16. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/github_client.py +0 -0
  17. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/matcher.py +0 -0
  18. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/suggest_cache.py +0 -0
  19. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage/suggester.py +0 -0
  20. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/SOURCES.txt +0 -0
  21. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/dependency_links.txt +0 -0
  22. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/entry_points.txt +0 -0
  23. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/src/codeowners_coverage.egg-info/top_level.txt +0 -0
  24. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_checker.py +0 -0
  25. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_config.py +0 -0
  26. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_directory_consolidator.py +0 -0
  27. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_git_analyzer.py +0 -0
  28. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_github_client.py +0 -0
  29. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_matcher.py +0 -0
  30. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_suggest_cache.py +0 -0
  31. {codeowners_coverage-0.2.1 → codeowners_coverage-0.3.0}/tests/test_suggester.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeowners-coverage
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Measure and enforce CODEOWNERS coverage
5
5
  Author-email: Sentry Team <hello@sentry.io>
6
6
  License: Apache-2.0
@@ -10,7 +10,8 @@ Requires-Dist: pathspec>=0.12.0
10
10
  Requires-Dist: PyYAML>=6.0
11
11
  Requires-Dist: click>=8.0
12
12
  Requires-Dist: requests>=2.31.0
13
- Requires-Dist: ollama>=0.3.0
13
+ Provides-Extra: suggest
14
+ Requires-Dist: ollama>=0.3.0; extra == "suggest"
14
15
  Provides-Extra: dev
15
16
  Requires-Dist: pytest>=7.0; extra == "dev"
16
17
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
@@ -57,7 +58,11 @@ just ollama-setup # Downloads and configures Ollama model
57
58
  ## Installation
58
59
 
59
60
  ```bash
61
+ # Core (check + baseline commands)
60
62
  pip install codeowners-coverage
63
+
64
+ # With AI-powered suggestions (requires Ollama)
65
+ pip install codeowners-coverage[suggest]
61
66
  ```
62
67
 
63
68
  ## Usage
@@ -76,6 +81,8 @@ codeowners-coverage baseline
76
81
 
77
82
  ### Suggest CODEOWNERS entries (AI-powered)
78
83
 
84
+ > Requires the `[suggest]` extra: `pip install codeowners-coverage[suggest]`
85
+
79
86
  Use local LLM to intelligently suggest team ownership based on git history.
80
87
 
81
88
  **GitHub Token Setup:**
@@ -251,8 +258,8 @@ just release
251
258
  ### Manual commands
252
259
 
253
260
  ```bash
254
- # Install in development mode
255
- uv pip install -e ".[dev]"
261
+ # Install in development mode (all features)
262
+ uv pip install -e ".[dev,suggest]"
256
263
 
257
264
  # Run tests
258
265
  pytest tests/ -v
@@ -36,7 +36,11 @@ just ollama-setup # Downloads and configures Ollama model
36
36
  ## Installation
37
37
 
38
38
  ```bash
39
+ # Core (check + baseline commands)
39
40
  pip install codeowners-coverage
41
+
42
+ # With AI-powered suggestions (requires Ollama)
43
+ pip install codeowners-coverage[suggest]
40
44
  ```
41
45
 
42
46
  ## Usage
@@ -55,6 +59,8 @@ codeowners-coverage baseline
55
59
 
56
60
  ### Suggest CODEOWNERS entries (AI-powered)
57
61
 
62
+ > Requires the `[suggest]` extra: `pip install codeowners-coverage[suggest]`
63
+
58
64
  Use local LLM to intelligently suggest team ownership based on git history.
59
65
 
60
66
  **GitHub Token Setup:**
@@ -230,8 +236,8 @@ just release
230
236
  ### Manual commands
231
237
 
232
238
  ```bash
233
- # Install in development mode
234
- uv pip install -e ".[dev]"
239
+ # Install in development mode (all features)
240
+ uv pip install -e ".[dev,suggest]"
235
241
 
236
242
  # Run tests
237
243
  pytest tests/ -v
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codeowners-coverage"
7
- version = "0.2.1"
7
+ version = "0.3.0"
8
8
  description = "Measure and enforce CODEOWNERS coverage"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -17,13 +17,15 @@ dependencies = [
17
17
  "PyYAML>=6.0", # Config file parsing
18
18
  "click>=8.0", # CLI framework
19
19
  "requests>=2.31.0", # For GitHub API
20
- "ollama>=0.3.0", # For local LLM integration
21
20
  ]
22
21
 
23
22
  [project.scripts]
24
23
  codeowners-coverage = "codeowners_coverage.__main__:main"
25
24
 
26
25
  [project.optional-dependencies]
26
+ suggest = [
27
+ "ollama>=0.3.0", # For local LLM integration (suggest command)
28
+ ]
27
29
  dev = [
28
30
  "pytest>=7.0",
29
31
  "pytest-cov>=4.0",
@@ -1,6 +1,6 @@
1
1
  """CODEOWNERS coverage checking tool."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.3.0"
4
4
 
5
5
  from .checker import CoverageChecker
6
6
  from .config import Config
@@ -6,21 +6,18 @@ import json
6
6
  import sys
7
7
  from datetime import datetime
8
8
  from pathlib import Path
9
- from typing import Any, Dict, List, Tuple, cast
9
+ from typing import TYPE_CHECKING, Any, Dict, List, Tuple, cast
10
10
 
11
11
  import click
12
12
 
13
- from .checker import CoverageChecker
14
- from .config import Config
15
- from .directory_consolidator import DirectoryConsolidator
16
- from .git_analyzer import GitHistoryAnalyzer
17
- from .github_client import GitHubClient
18
- from .matcher import CodeOwnersPatternMatcher
19
- from .ollama_matcher import OllamaLLMMatcher, TeamSuggestion
20
- from .suggest_cache import SuggestCache
21
- from .suggester import OwnershipSuggester, SuggestionResult
22
13
  from . import __version__
23
14
 
15
+ if TYPE_CHECKING:
16
+ from .config import Config
17
+ from .ollama_matcher import TeamSuggestion
18
+ from .suggest_cache import SuggestCache
19
+ from .suggester import SuggestionResult
20
+
24
21
 
25
22
  @click.group()
26
23
  @click.version_option(version=__version__)
@@ -42,6 +39,9 @@ def check(output_json: bool, files: Tuple[str, ...], config: str) -> None:
42
39
  New uncovered files will cause the check to fail.
43
40
  """
44
41
  try:
42
+ from .checker import CoverageChecker
43
+ from .config import Config
44
+
45
45
  cfg = Config.load(config)
46
46
  checker = CoverageChecker(cfg)
47
47
 
@@ -95,6 +95,9 @@ def baseline(config: str, files: Tuple[str, ...]) -> None:
95
95
  allowing existing gaps.
96
96
  """
97
97
  try:
98
+ from .checker import CoverageChecker
99
+ from .config import Config
100
+
98
101
  cfg = Config.load(config)
99
102
  checker = CoverageChecker(cfg)
100
103
 
@@ -198,6 +201,16 @@ def suggest(
198
201
  Requires Ollama to be installed and running.
199
202
  """
200
203
  try:
204
+ from .checker import CoverageChecker
205
+ from .config import Config
206
+ from .directory_consolidator import DirectoryConsolidator
207
+ from .git_analyzer import GitHistoryAnalyzer
208
+ from .github_client import GitHubClient
209
+ from .matcher import CodeOwnersPatternMatcher
210
+ from .ollama_matcher import OllamaLLMMatcher, TeamSuggestion
211
+ from .suggest_cache import SuggestCache
212
+ from .suggester import OwnershipSuggester, SuggestionResult
213
+
201
214
  # Load config
202
215
  cfg = Config.load(config)
203
216
 
@@ -308,6 +321,9 @@ def suggest(
308
321
  f"✓ Connected to Ollama "
309
322
  f"(model: {cfg.ollama_model})"
310
323
  )
324
+ except ImportError as e:
325
+ click.echo(f"❌ {e}", err=True)
326
+ sys.exit(1)
311
327
  except Exception as e:
312
328
  click.echo(
313
329
  f"❌ Failed to connect to Ollama: {e}",
@@ -397,6 +413,8 @@ def _setup_cache(
397
413
  files: List[str],
398
414
  ) -> SuggestCache | None:
399
415
  """Load or initialize the suggest cache."""
416
+ from .suggest_cache import SuggestCache
417
+
400
418
  if no_cache:
401
419
  click.echo(" Cache: disabled (--no-cache)")
402
420
  return None
@@ -6,7 +6,10 @@ import json
6
6
  from dataclasses import dataclass
7
7
  from typing import Dict, List, Tuple
8
8
 
9
- import ollama
9
+ try:
10
+ import ollama
11
+ except ImportError:
12
+ ollama = None # type: ignore[assignment]
10
13
 
11
14
 
12
15
  @dataclass
@@ -38,10 +41,15 @@ class OllamaLLMMatcher:
38
41
  Raises:
39
42
  Exception: If unable to connect to Ollama
40
43
  """
44
+ if ollama is None:
45
+ raise ImportError(
46
+ "The 'ollama' package is required for the suggest command. "
47
+ "Install it with: pip install codeowners-coverage[suggest]"
48
+ )
49
+
41
50
  self.model = model
42
51
  self.base_url = base_url
43
52
 
44
- # Verify Ollama is available
45
53
  try:
46
54
  ollama.list()
47
55
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeowners-coverage
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Measure and enforce CODEOWNERS coverage
5
5
  Author-email: Sentry Team <hello@sentry.io>
6
6
  License: Apache-2.0
@@ -10,7 +10,8 @@ Requires-Dist: pathspec>=0.12.0
10
10
  Requires-Dist: PyYAML>=6.0
11
11
  Requires-Dist: click>=8.0
12
12
  Requires-Dist: requests>=2.31.0
13
- Requires-Dist: ollama>=0.3.0
13
+ Provides-Extra: suggest
14
+ Requires-Dist: ollama>=0.3.0; extra == "suggest"
14
15
  Provides-Extra: dev
15
16
  Requires-Dist: pytest>=7.0; extra == "dev"
16
17
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
@@ -57,7 +58,11 @@ just ollama-setup # Downloads and configures Ollama model
57
58
  ## Installation
58
59
 
59
60
  ```bash
61
+ # Core (check + baseline commands)
60
62
  pip install codeowners-coverage
63
+
64
+ # With AI-powered suggestions (requires Ollama)
65
+ pip install codeowners-coverage[suggest]
61
66
  ```
62
67
 
63
68
  ## Usage
@@ -76,6 +81,8 @@ codeowners-coverage baseline
76
81
 
77
82
  ### Suggest CODEOWNERS entries (AI-powered)
78
83
 
84
+ > Requires the `[suggest]` extra: `pip install codeowners-coverage[suggest]`
85
+
79
86
  Use local LLM to intelligently suggest team ownership based on git history.
80
87
 
81
88
  **GitHub Token Setup:**
@@ -251,8 +258,8 @@ just release
251
258
  ### Manual commands
252
259
 
253
260
  ```bash
254
- # Install in development mode
255
- uv pip install -e ".[dev]"
261
+ # Install in development mode (all features)
262
+ uv pip install -e ".[dev,suggest]"
256
263
 
257
264
  # Run tests
258
265
  pytest tests/ -v
@@ -2,7 +2,6 @@ pathspec>=0.12.0
2
2
  PyYAML>=6.0
3
3
  click>=8.0
4
4
  requests>=2.31.0
5
- ollama>=0.3.0
6
5
 
7
6
  [dev]
8
7
  pytest>=7.0
@@ -11,3 +10,6 @@ mypy>=1.0
11
10
  ruff>=0.1.0
12
11
  types-requests>=2.31.0
13
12
  types-PyYAML>=6.0
13
+
14
+ [suggest]
15
+ ollama>=0.3.0
@@ -2,17 +2,21 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from unittest.mock import patch
5
+ from unittest.mock import MagicMock, patch
6
6
 
7
7
  import pytest
8
8
 
9
+ from codeowners_coverage import ollama_matcher
9
10
  from codeowners_coverage.ollama_matcher import OllamaLLMMatcher
10
11
 
12
+ _mock_ollama_module = MagicMock()
13
+ _mock_ollama_module.list.return_value = []
14
+
11
15
 
12
16
  @pytest.fixture
13
17
  def mock_ollama() -> None:
14
18
  """Mock Ollama availability check."""
15
- with patch("ollama.list", return_value=[]):
19
+ with patch.object(ollama_matcher, "ollama", _mock_ollama_module):
16
20
  yield
17
21
 
18
22
 
@@ -91,7 +95,7 @@ def test_match_file_to_team(mock_ollama: None) -> None:
91
95
  }
92
96
  }
93
97
 
94
- with patch("ollama.chat", return_value=mock_response):
98
+ with patch.object(_mock_ollama_module, "chat", return_value=mock_response):
95
99
  suggestion = matcher.match_file_to_team(
96
100
  filepath="src/components/Button.tsx",
97
101
  contributors=[("alice@example.com", 5)],
@@ -292,7 +296,7 @@ def test_match_file_passes_allowlist(mock_ollama: None) -> None:
292
296
  }
293
297
  }
294
298
 
295
- with patch("ollama.chat", return_value=mock_response):
299
+ with patch.object(_mock_ollama_module, "chat", return_value=mock_response):
296
300
  suggestion = matcher.match_file_to_team(
297
301
  filepath="src/components/Button.tsx",
298
302
  contributors=[("alice@example.com", 5)],