release: fix pyproject.toml version update for PEP 621 projects
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / lint-shell (push) Has been cancelled
Mark stable commit / lint-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled

Update version handling to correctly modify [project].version in pyproject.toml.
The previous implementation only matched top-level version assignments and
failed for PEP 621 layouts.

- Restrict update to the [project] section
- Allow leading whitespace in version lines
- Replace sys.exit() with proper exceptions
- Remove unused sys import

https://chatgpt.com/share/69454836-4698-800f-9d19-7e67e8e789d6
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-19 13:42:26 +01:00
parent 3d5c770def
commit 3e6ef0fd68

View File

@@ -19,7 +19,6 @@ from __future__ import annotations
import os import os
import re import re
import subprocess import subprocess
import sys
import tempfile import tempfile
from datetime import date, datetime from datetime import date, datetime
from typing import Optional, Tuple from typing import Optional, Tuple
@@ -85,53 +84,42 @@ def _open_editor_for_changelog(initial_message: Optional[str] = None) -> str:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def update_pyproject_version( def update_pyproject_version(pyproject_path: str, new_version: str, preview: bool = False) -> None:
pyproject_path: str,
new_version: str,
preview: bool = False,
) -> None:
"""
Update the version in pyproject.toml with the new version.
The function looks for a line matching:
version = "X.Y.Z"
and replaces the version part with the given new_version string.
If the file does not exist, it is skipped without failing the release.
"""
if not os.path.exists(pyproject_path): if not os.path.exists(pyproject_path):
print( print(f"[INFO] pyproject.toml not found at: {pyproject_path}, skipping version update.")
f"[INFO] pyproject.toml not found at: {pyproject_path}, "
"skipping version update."
)
return return
try: try:
with open(pyproject_path, "r", encoding="utf-8") as f: with open(pyproject_path, "r", encoding="utf-8") as f:
content = f.read() content = f.read()
except OSError as exc: except OSError as exc:
print( print(f"[WARN] Could not read pyproject.toml at {pyproject_path}: {exc}. Skipping version update.")
f"[WARN] Could not read pyproject.toml at {pyproject_path}: {exc}. "
"Skipping version update."
)
return return
pattern = r'^(version\s*=\s*")([^"]+)(")' # Find [project] block (PEP 621)
new_content, count = re.subn( m = re.search(r"(?ms)^\s*\[project\]\s*$.*?(?=^\s*\[|\Z)", content)
pattern, if not m:
lambda m: f"{m.group(1)}{new_version}{m.group(3)}", print("[ERROR] Could not find [project] section in pyproject.toml")
content, raise RuntimeError("Missing [project] section in pyproject.toml")
flags=re.MULTILINE,
project_block = m.group(0)
# Replace version line inside that block (allow leading whitespace)
ver_pat = r'(?m)^(\s*version\s*=\s*")([^"]+)(")\s*$'
new_project_block, count = re.subn(
ver_pat,
lambda mm: f"{mm.group(1)}{new_version}{mm.group(3)}",
project_block,
) )
if count == 0: if count == 0:
print("[ERROR] Could not find version line in pyproject.toml") print("[ERROR] Could not find version = \"...\" in [project] section of pyproject.toml")
sys.exit(1) raise RuntimeError("Missing version key in [project] section")
new_content = content[: m.start()] + new_project_block + content[m.end() :]
if preview: if preview:
print(f"[PREVIEW] Would update pyproject.toml version to {new_version}") print(f"[PREVIEW] Would update pyproject.toml [project].version to {new_version}")
return return
with open(pyproject_path, "w", encoding="utf-8") as f: with open(pyproject_path, "w", encoding="utf-8") as f:
@@ -139,7 +127,6 @@ def update_pyproject_version(
print(f"Updated pyproject.toml version to {new_version}") print(f"Updated pyproject.toml version to {new_version}")
def update_flake_version( def update_flake_version(
flake_path: str, flake_path: str,
new_version: str, new_version: str,