Conventional-Commit-driven version bumps (scripts/bump.py), a commit-msg validation hook, and a /release-notes workflow that produces a human-reviewed CHANGELOG.md. Adds an in-app version badge + 'What's new' dialog on the launcher. The version is single-sourced from pyproject.toml (cim_suite.__version__), and the deterministic bump backbone lives in scripts/release/ with tests in tests/release/. Marks the 1.0.0 baseline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
"""CIMTechniques Service Suite — unified desktop suite of instrument service tools."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def _candidate_pyprojects() -> list[Path]:
|
|
"""Places pyproject.toml may live, in priority order (frozen bundle, then source)."""
|
|
candidates = []
|
|
meipass = getattr(sys, "_MEIPASS", None)
|
|
if meipass is not None:
|
|
candidates.append(Path(meipass) / "pyproject.toml")
|
|
candidates.append(Path(__file__).resolve().parent.parent / "pyproject.toml")
|
|
return candidates
|
|
|
|
|
|
def _detect_version() -> str:
|
|
"""Resolve the suite version from its single source of truth, ``pyproject.toml``.
|
|
|
|
A source checkout (incl. editable installs) reads the live file, so a
|
|
``scripts/bump.py`` edit shows up immediately with no reinstall; the frozen build
|
|
bundles the same file (see packaging/suite.spec). A plain wheel install with no
|
|
pyproject alongside the package falls back to the baked-in distribution metadata.
|
|
"""
|
|
for pyproject in _candidate_pyprojects():
|
|
if pyproject.is_file():
|
|
try:
|
|
import tomllib
|
|
|
|
return tomllib.loads(pyproject.read_text("utf-8"))["project"]["version"]
|
|
except Exception: # pragma: no cover - malformed pyproject falls through
|
|
pass
|
|
try:
|
|
from importlib.metadata import PackageNotFoundError, version
|
|
|
|
return version("cim-service-suite")
|
|
except PackageNotFoundError: # pragma: no cover - not installed and no pyproject
|
|
return "0.0.0"
|
|
|
|
|
|
__version__ = _detect_version()
|
|
|
|
|
|
def changelog_path() -> Path | None:
|
|
"""Locate the bundled ``CHANGELOG.md`` (repo root in source, bundle dir when frozen)."""
|
|
candidates = []
|
|
meipass = getattr(sys, "_MEIPASS", None)
|
|
if meipass is not None:
|
|
candidates.append(Path(meipass) / "CHANGELOG.md")
|
|
candidates.append(Path(__file__).resolve().parent.parent / "CHANGELOG.md")
|
|
for path in candidates:
|
|
if path.is_file():
|
|
return path
|
|
return None
|
|
|
|
|
|
def changelog_markdown() -> str:
|
|
"""The release notes as markdown, or a friendly placeholder if none is bundled."""
|
|
path = changelog_path()
|
|
if path is None:
|
|
return "# Changelog\n\nNo release notes are available in this build."
|
|
return path.read_text("utf-8")
|