A repo whose Cargo.toml has a [package] section now gets its version set to the release version, and the matching local [[package]] entry in Cargo.lock (same name, no source line) follows in the same release commit, so cargo build --locked keeps passing. Workspaces without [package] and repos without Cargo.toml release as before; a Cargo.lock without the local entry aborts the release before any file is written. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
|
|
|
|
def _read(path: str) -> str:
|
|
with open(path, encoding="utf-8") as f:
|
|
return f.read()
|
|
|
|
|
|
def _write(path: str, content: str) -> None:
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(content)
|
|
|
|
|
|
def update_cargo_version(
|
|
repo_root: str, new_version: str, preview: bool = False
|
|
) -> list[str]:
|
|
"""
|
|
Set the root crate's version in Cargo.toml and its entry in Cargo.lock.
|
|
|
|
Args:
|
|
repo_root: repository root that may hold Cargo.toml and Cargo.lock.
|
|
new_version: release version without the leading "v".
|
|
preview: only print what would change.
|
|
|
|
Returns:
|
|
The paths that were (or in preview would be) changed.
|
|
"""
|
|
toml_path = os.path.join(repo_root, "Cargo.toml")
|
|
if not os.path.exists(toml_path):
|
|
print("[INFO] No Cargo.toml found. Skipping Cargo version update.")
|
|
return []
|
|
|
|
toml = _read(toml_path)
|
|
block = re.search(r"(?ms)^\[package\]\s*$.*?(?=^\s*\[|\Z)", toml)
|
|
if not block:
|
|
print("[INFO] Cargo.toml has no [package] section. Skipping.")
|
|
return []
|
|
|
|
name = re.search(r'(?m)^\s*name\s*=\s*"([^"]+)"', block.group(0))
|
|
if not name:
|
|
raise RuntimeError("Missing name key in [package] section of Cargo.toml")
|
|
new_block, count = re.subn(
|
|
r'(?m)^(\s*version\s*=\s*")[^"]+(")',
|
|
lambda m: f"{m.group(1)}{new_version}{m.group(2)}",
|
|
block.group(0),
|
|
count=1,
|
|
)
|
|
if count == 0:
|
|
raise RuntimeError("Missing version key in [package] section of Cargo.toml")
|
|
changes = {toml_path: toml[: block.start()] + new_block + toml[block.end() :]}
|
|
|
|
lock_path = os.path.join(repo_root, "Cargo.lock")
|
|
if os.path.exists(lock_path):
|
|
lock, count = re.subn(
|
|
rf'(?m)^(\[\[package\]\]\nname = "{re.escape(name.group(1))}"\n'
|
|
r'version = ")[^"]+("\n)(?!source = )',
|
|
lambda m: f"{m.group(1)}{new_version}{m.group(2)}",
|
|
_read(lock_path),
|
|
)
|
|
if count != 1:
|
|
raise RuntimeError(
|
|
f"Expected one local {name.group(1)!r} package in Cargo.lock, "
|
|
f"found {count}"
|
|
)
|
|
changes[lock_path] = lock
|
|
|
|
for path, content in changes.items():
|
|
if preview:
|
|
print(f"[PREVIEW] Would update {path} version to {new_version}")
|
|
else:
|
|
_write(path, content)
|
|
print(f"Updated {path} version to {new_version}")
|
|
return list(changes)
|