Add config_auditor module files: cli, discovery, parsers
This commit is contained in:
119
config_auditor/discovery.py
Normal file
119
config_auditor/discovery.py
Normal file
@@ -0,0 +1,119 @@
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConfigFile:
|
||||
path: Path
|
||||
format: str
|
||||
name: str
|
||||
|
||||
|
||||
class ConfigDiscovery:
|
||||
PATTERNS = {
|
||||
"json": [
|
||||
"package.json",
|
||||
"tsconfig*.json",
|
||||
".eslintrc*.json",
|
||||
".prettierrc*.json",
|
||||
".babelrc*.json",
|
||||
"webpack.config.js",
|
||||
"rollup.config.js",
|
||||
"nest-cli.json",
|
||||
"angular.json",
|
||||
"pyproject.toml",
|
||||
"poetry.toml",
|
||||
"mypy.ini",
|
||||
"pytest.ini",
|
||||
"setup.cfg",
|
||||
".coveragerc",
|
||||
"tox.ini",
|
||||
],
|
||||
"yaml": [
|
||||
".gitlab-ci.yml",
|
||||
".github/**/*.yml",
|
||||
".github/**/*.yaml",
|
||||
"docker-compose.yml",
|
||||
"*.k8s.yaml",
|
||||
"*.k8s.yml",
|
||||
".ansible.yml",
|
||||
".ansible/**/*.yml",
|
||||
],
|
||||
"toml": [
|
||||
"pyproject.toml",
|
||||
"poetry.toml",
|
||||
"Cargo.toml",
|
||||
"PDM.toml",
|
||||
],
|
||||
}
|
||||
|
||||
def __init__(self, max_depth: int = 3):
|
||||
self.max_depth = max_depth
|
||||
|
||||
def discover(self, path: Path) -> List[ConfigFile]:
|
||||
config_files = []
|
||||
|
||||
for format_patterns in self.PATTERNS.values():
|
||||
for pattern in format_patterns:
|
||||
matches = self._find_matches(path, pattern)
|
||||
for match in matches:
|
||||
format_type = self._detect_format(match)
|
||||
if format_type:
|
||||
config_files.append(ConfigFile(
|
||||
path=match,
|
||||
format=format_type,
|
||||
name=match.name
|
||||
))
|
||||
|
||||
return config_files
|
||||
|
||||
def _find_matches(self, base_path: Path, pattern: str) -> List[Path]:
|
||||
matches = []
|
||||
|
||||
if "**" in pattern:
|
||||
parts = pattern.split("**")
|
||||
if len(parts) > 1:
|
||||
search_pattern = parts[-1].lstrip("/")
|
||||
else:
|
||||
search_pattern = "*"
|
||||
for p in base_path.rglob(search_pattern):
|
||||
if p.is_file() and self._matches_pattern(p.name, search_pattern):
|
||||
matches.append(p)
|
||||
elif "*" in pattern:
|
||||
for p in base_path.rglob(pattern):
|
||||
if p.is_file():
|
||||
matches.append(p)
|
||||
else:
|
||||
full_path = base_path / pattern
|
||||
if full_path.exists():
|
||||
matches.append(full_path)
|
||||
|
||||
return list(set(matches))
|
||||
|
||||
def _matches_pattern(self, filename: str, pattern: str) -> bool:
|
||||
from fnmatch import fnmatch
|
||||
return fnmatch(filename, pattern)
|
||||
|
||||
def _detect_format(self, path: Path) -> Optional[str]:
|
||||
suffix = path.suffix.lower()
|
||||
name = path.name.lower()
|
||||
|
||||
if suffix == ".json" or "eslintrc" in name or "babelrc" in name:
|
||||
return "json"
|
||||
elif suffix in (".yaml", ".yml"):
|
||||
return "yaml"
|
||||
elif suffix == ".toml" or name == "pyproject.toml":
|
||||
return "toml"
|
||||
|
||||
if path.exists():
|
||||
try:
|
||||
content = path.read_text()
|
||||
if content.strip().startswith("{") or content.strip().startswith("["):
|
||||
return "json"
|
||||
elif content.strip().startswith("---") or ":" in content.split("\n")[0]:
|
||||
return "yaml"
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user