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