diff --git a/CHANGELOG.md b/CHANGELOG.md index d9cefd1..3d42863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to The Scheduler will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.0.1] - 2025-12-14 + +### Changed +- **Version tracking now uses pyproject.toml** as single source of truth + - Added `pyproject.toml` with project metadata and dependencies + - `config.py` reads version from pyproject.toml using `tomllib` + - FastAPI app title and version dynamically loaded from config + - Health endpoint now includes version in response + - Dockerfile updated to include pyproject.toml + ## [1.0.0] - 2025-12-07 ### Added diff --git a/Dockerfile b/Dockerfile index 6d1b211..3a8faa3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ RUN pip install --no-cache-dir -r requirements.txt # Copy application COPY src/ ./src/ COPY setup_database.sql . +COPY pyproject.toml . # Configure git RUN git config --global user.name "The Librarian" && \ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9f8797b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "the-scheduler" +version = "1.0.1" +description = "System-wide maintenance orchestration - backups, doc mirroring, cleanup, task automation" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + # FastAPI ecosystem + "fastapi~=0.124.0", + "uvicorn[standard]~=0.38.0", + "pydantic~=2.12.5", + "pydantic-settings~=2.7.0", + # Task scheduling + "apscheduler~=3.11.1", + "sqlalchemy~=2.0.36", + # Database + "psycopg2-binary~=2.9.11", + "redis~=5.2.0", + # HTTP client + "httpx~=0.28.1", + # Web scraping (for doc mirroring) + "scrapy~=2.12.0", + "beautifulsoup4~=4.12.3", + "lxml~=5.1.0", + # Git operations + "gitpython~=3.1.43", + # Security/Auth + "python-jose[cryptography]~=3.3.0", +] + +[project.optional-dependencies] +test = [ + "pytest~=8.3.4", + "pytest-asyncio~=0.25.2", + "pytest-cov~=6.0.0", + "freezegun~=1.5.1", +] + +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] +include = ["src*"] diff --git a/src/config.py b/src/config.py index 0b24ba3..b2276c8 100644 --- a/src/config.py +++ b/src/config.py @@ -2,17 +2,37 @@ Configuration management for The Scheduler. Uses Pydantic BaseSettings for type-safe environment variable loading. """ +import tomllib from functools import lru_cache +from pathlib import Path from pydantic_settings import BaseSettings from pydantic import Field +def _get_version_from_pyproject() -> tuple[str, str, str]: + """Read version info from pyproject.toml.""" + pyproject_path = Path(__file__).parent.parent / "pyproject.toml" + if pyproject_path.exists(): + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + project = data.get("project", {}) + return ( + project.get("name", "the-scheduler"), + project.get("version", "0.0.0"), + project.get("description", ""), + ) + return ("the-scheduler", "0.0.0", "") + + +_PROJECT_NAME, _PROJECT_VERSION, _PROJECT_DESCRIPTION = _get_version_from_pyproject() + + class Settings(BaseSettings): """Application settings loaded from environment variables.""" # Application - app_name: str = Field(default="The Scheduler", alias="APP_NAME") - app_version: str = Field(default="1.0.0", alias="APP_VERSION") + app_name: str = Field(default=_PROJECT_NAME, alias="APP_NAME") + app_version: str = Field(default=_PROJECT_VERSION, alias="APP_VERSION") debug: bool = Field(default=False, alias="DEBUG") host: str = Field(default="0.0.0.0", alias="HOST") port: int = Field(default=8090, alias="PORT") diff --git a/src/main.py b/src/main.py index 086c888..e5fae36 100644 --- a/src/main.py +++ b/src/main.py @@ -102,9 +102,10 @@ async def lifespan(app: FastAPI): # FastAPI app +settings = get_settings() app = FastAPI( - title="The Scheduler", - version="1.0.0", + title=settings.app_name, + version=settings.app_version, description="System-wide maintenance orchestration - backups, doc mirroring, cleanup, task automation", lifespan=lifespan ) @@ -134,6 +135,7 @@ async def health( """Health check endpoint.""" return { "status": "healthy", + "version": settings.app_version, "scheduler_running": sched.running, "jobs_count": len(sched.get_jobs()), "database": settings.postgres_db