From 90fcdb4b4f422f7ad8cc7645d49e45f14c0dd5e3 Mon Sep 17 00:00:00 2001 From: samypr100 <3933065+samypr100@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:22:33 -0400 Subject: [PATCH] feat: support file substitutions --- src/rooster/_cli.py | 14 ++++++++++---- src/rooster/_config.py | 12 +++++++++++- src/rooster/_versions.py | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/rooster/_cli.py b/src/rooster/_cli.py index 5720df9..66ef15f 100644 --- a/src/rooster/_cli.py +++ b/src/rooster/_cli.py @@ -6,7 +6,7 @@ Changelog, VersionSection, ) -from rooster._config import Config +from rooster._config import Config, SubstitutionEntry from rooster._git import ( GitLookupError, get_commit_for_tag, @@ -23,6 +23,7 @@ Version, bump_version, get_latest_version, + process_substitutions, update_version_file, versions_from_git_tags, ) @@ -286,10 +287,15 @@ def release( typer.echo("Updated changelog") if update_version_files: + old_version = last_version or Version("0.0.0") for version_file in config.version_files: - update_version_file( - version_file, last_version or Version("0.0.0"), new_version - ) + if isinstance(version_file, SubstitutionEntry): + for match in directory.glob(version_file.target): + process_substitutions( + match, old_version, new_version, version_file.replace + ) + else: + update_version_file(version_file, old_version, new_version) typer.echo(f"Updated version in {version_file}") diff --git a/src/rooster/_config.py b/src/rooster/_config.py index e23d6b2..f0bf4ba 100644 --- a/src/rooster/_config.py +++ b/src/rooster/_config.py @@ -47,7 +47,9 @@ class Config(pydantic.BaseModel): trim_title_prefixes: frozenset[str] = frozenset() # Paths to files to replace versions at - version_files: list[Path | VersionFile] = [Path("pyproject.toml")] + version_files: list[Path | VersionFile | SubstitutionEntry] = [ + Path("pyproject.toml") + ] # The default version bump to use default_bump_type: BumpType = BumpType.patch @@ -108,6 +110,14 @@ def __str__(self): return str(self.path) +class SubstitutionEntry(pydantic.BaseModel): + target: str + replace: str | None = None + + def __str__(self): + return str(self.target) + + class SubmoduleLabels(pydantic.BaseModel): submodule: str labels: frozenset[str] = frozenset() diff --git a/src/rooster/_versions.py b/src/rooster/_versions.py index 741de8d..ccbf9ff 100644 --- a/src/rooster/_versions.py +++ b/src/rooster/_versions.py @@ -170,6 +170,26 @@ def update_version_file( ) +def process_substitutions( + match: Path, + old_version: Version, + new_version: Version, + replacement: str | None = None, +) -> None: + """Process substitutions in a matched file. + + When the replacement is None it will replace instances + of the last version with the new version. + """ + new_version_str = str(new_version) + contents = match.read_text() + if replacement is None: + contents = contents.replace(str(old_version), new_version_str) + else: + contents = contents.replace(replacement, new_version_str) + match.write_text(contents) + + def update_text_version(path: Path, old_version: str, new_version: str) -> None: """ Update the version in a basic text file.