Add utils, templates, config, interactive, and github modules
This commit is contained in:
183
src/auto_readme/config/__init__.py
Normal file
183
src/auto_readme/config/__init__.py
Normal file
@@ -0,0 +1,183 @@
|
||||
"""Configuration file support for the Auto README Generator."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import yaml
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
try:
|
||||
import tomli as tomllib
|
||||
except ImportError:
|
||||
tomllib = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReadmeConfig:
|
||||
"""Configuration for README generation."""
|
||||
|
||||
project_name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
template: str = "base"
|
||||
interactive: bool = False
|
||||
sections: dict = field(default_factory=dict)
|
||||
output_filename: str = "README.md"
|
||||
custom_fields: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
class ConfigLoader:
|
||||
"""Loads and validates configuration files."""
|
||||
|
||||
CONFIG_FILES = [".readmerc", ".readmerc.yaml", ".readmerc.yml", "readme.config.yaml"]
|
||||
|
||||
@classmethod
|
||||
def find_config(cls, directory: Path) -> Optional[Path]:
|
||||
"""Find a configuration file in the directory."""
|
||||
for config_name in cls.CONFIG_FILES:
|
||||
config_path = directory / config_name
|
||||
if config_path.exists():
|
||||
return config_path
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def load(cls, path: Path) -> ReadmeConfig:
|
||||
"""Load configuration from a file."""
|
||||
if not path.exists():
|
||||
return ReadmeConfig()
|
||||
|
||||
config = ReadmeConfig()
|
||||
|
||||
if path.suffix in (".yaml", ".yml"):
|
||||
config = cls._load_yaml(path, config)
|
||||
elif path.suffix == ".toml":
|
||||
config = cls._load_toml(path, config)
|
||||
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def _load_yaml(cls, path: Path, config: ReadmeConfig) -> ReadmeConfig:
|
||||
"""Load configuration from YAML file."""
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
except yaml.YAMLError as e:
|
||||
raise ValueError(f"Invalid YAML in config file: {e}")
|
||||
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("Config file must contain a dictionary")
|
||||
|
||||
if "project_name" in data:
|
||||
config.project_name = data["project_name"]
|
||||
if "description" in data:
|
||||
config.description = data["description"]
|
||||
if "template" in data:
|
||||
config.template = data["template"]
|
||||
if "interactive" in data:
|
||||
config.interactive = data["interactive"]
|
||||
if "filename" in data:
|
||||
config.output_filename = data["filename"]
|
||||
if "sections" in data:
|
||||
config.sections = data["sections"]
|
||||
if "custom_fields" in data:
|
||||
config.custom_fields = data["custom_fields"]
|
||||
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def _load_toml(cls, path: Path, config: ReadmeConfig) -> ReadmeConfig:
|
||||
"""Load configuration from TOML file."""
|
||||
if tomllib is None:
|
||||
raise ValueError("TOML support requires Python 3.11+ or tomli package")
|
||||
try:
|
||||
with open(path, "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Invalid TOML in config file: {e}")
|
||||
|
||||
if "auto-readme" in data:
|
||||
auto_readme = data["auto-readme"]
|
||||
if "filename" in auto_readme:
|
||||
config.output_filename = auto_readme["filename"]
|
||||
if "sections" in auto_readme:
|
||||
config.sections = auto_readme["sections"]
|
||||
|
||||
return config
|
||||
|
||||
|
||||
class ConfigValidator:
|
||||
"""Validates configuration files."""
|
||||
|
||||
VALID_TEMPLATES = ["base", "minimal", "detailed"]
|
||||
VALID_SECTIONS = [
|
||||
"title",
|
||||
"description",
|
||||
"badges",
|
||||
"table_of_contents",
|
||||
"overview",
|
||||
"installation",
|
||||
"usage",
|
||||
"features",
|
||||
"api",
|
||||
"contributing",
|
||||
"license",
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config: ReadmeConfig) -> list[str]:
|
||||
"""Validate a configuration and return any errors."""
|
||||
errors = []
|
||||
|
||||
if config.template and config.template not in cls.VALID_TEMPLATES:
|
||||
errors.append(f"Invalid template: {config.template}. Valid options: {cls.VALID_TEMPLATES}")
|
||||
|
||||
if config.sections:
|
||||
if "order" in config.sections:
|
||||
for section in config.sections["order"]:
|
||||
if section not in cls.VALID_SECTIONS:
|
||||
errors.append(f"Invalid section in order: {section}")
|
||||
|
||||
return errors
|
||||
|
||||
@classmethod
|
||||
def generate_template(cls) -> str:
|
||||
"""Generate a template configuration file."""
|
||||
template = """# Auto README Configuration File
|
||||
# https://github.com/yourusername/yourrepo
|
||||
|
||||
# Project metadata
|
||||
project_name: "My Project"
|
||||
description: "A brief description of your project"
|
||||
|
||||
# Template to use
|
||||
template: "base"
|
||||
|
||||
# Interactive mode
|
||||
interactive: false
|
||||
|
||||
# Output filename
|
||||
filename: "README.md"
|
||||
|
||||
# Section configuration
|
||||
sections:
|
||||
order:
|
||||
- title
|
||||
- description
|
||||
- overview
|
||||
- installation
|
||||
- usage
|
||||
- features
|
||||
- api
|
||||
- contributing
|
||||
- license
|
||||
optional:
|
||||
Contributing: false
|
||||
|
||||
# Custom fields to include
|
||||
custom_fields:
|
||||
author: "Your Name"
|
||||
email: "your.email@example.com"
|
||||
"""
|
||||
return template
|
||||
Reference in New Issue
Block a user