chore: iti-system

main
NoahLan 1 week ago
parent b8551a2d12
commit 1688647421

@ -236,7 +236,9 @@ def handle_create(args: argparse.Namespace) -> int:
def handle_release(args: argparse.Namespace) -> int: def handle_release(args: argparse.Namespace) -> int:
ctx = require_project({"framework"}) ctx = require_project({"framework", "system"})
if ctx.kind == "system":
return release_system(ctx.root, args.version)
return release_framework(ctx.root, args.version) return release_framework(ctx.root, args.version)
@ -340,9 +342,16 @@ def detect_project(cwd: Path) -> ProjectContext:
and (root / "app").is_dir() and (root / "app").is_dir()
and (root / "migrations" / "alembic.ini").is_file() and (root / "migrations" / "alembic.ini").is_file()
) )
is_system = (
project_name == "iti-system"
and (root / "iti_system" / "module.py").is_file()
and (root / "iti_system" / "cli.py").is_file()
)
if is_framework: if is_framework:
kind = "framework" kind = "framework"
elif is_system:
kind = "system"
elif is_business: elif is_business:
kind = "business" kind = "business"
else: else:
@ -474,7 +483,7 @@ def project_env(root: Path, extra_env: dict[str, str] | None = None) -> dict[str
def release_framework(root: Path, version_arg: str | None) -> int: def release_framework(root: Path, version_arg: str | None) -> int:
current_version = read_current_version(root) current_version = read_current_version(root / "iti" / "__about__.py")
target_version = normalize_version(version_arg) if version_arg else bump_patch(current_version) target_version = normalize_version(version_arg) if version_arg else bump_patch(current_version)
target_tag = f"v{target_version}" target_tag = f"v{target_version}"
@ -524,6 +533,47 @@ def release_framework(root: Path, version_arg: str | None) -> int:
return 0 return 0
def release_system(root: Path, version_arg: str | None) -> int:
current_version = read_current_version(root / "iti_system" / "__about__.py")
target_version = normalize_version(version_arg) if version_arg else bump_patch(current_version)
target_tag = f"v{target_version}"
if target_version == current_version:
raise CliError(f"version already set to {target_version}")
if not version_is_newer(current_version, target_version):
raise CliError(f"target version must be newer than {current_version}")
if git_output(root, ["status", "--porcelain"]).strip():
raise CliError("working tree is not clean")
branch = git_output(root, ["symbolic-ref", "--quiet", "--short", "HEAD"]).strip()
if not branch:
raise CliError("release requires a branch checkout")
if subprocess.run(["git", "rev-parse", "--verify", "--quiet", f"refs/tags/{target_tag}"], cwd=root).returncode == 0:
raise CliError(f"tag already exists: {target_tag}")
code = run(["uv", "run", "pytest", "-q"], root)
if code:
return code
write_system_release_files(root, target_version)
code = run(["git", "add", "iti_system/__about__.py", "pyproject.toml", "README.md"], root)
if code:
return code
code = run(["git", "commit", "-m", f"chore: release {target_tag}"], root)
if code:
return code
code = run(["git", "tag", "-a", target_tag, "-m", f"release {target_tag}"], root)
if code:
return code
code = run(["git", "push", "origin", branch, target_tag], root)
if code:
return code
print(f"released {target_tag}")
return 0
def git_output(root: Path, args: Sequence[str]) -> str: def git_output(root: Path, args: Sequence[str]) -> str:
completed = subprocess.run( completed = subprocess.run(
["git", *args], ["git", *args],
@ -538,8 +588,7 @@ def git_output(root: Path, args: Sequence[str]) -> str:
return completed.stdout return completed.stdout
def read_current_version(root: Path) -> str: def read_current_version(about_file: Path) -> str:
about_file = root / "iti" / "__about__.py"
match = re.search(r'^__version__\s*=\s*"([^"]+)"', about_file.read_text(encoding="utf-8"), re.MULTILINE) match = re.search(r'^__version__\s*=\s*"([^"]+)"', about_file.read_text(encoding="utf-8"), re.MULTILINE)
if not match: if not match:
raise CliError(f"version not found in {about_file}") raise CliError(f"version not found in {about_file}")
@ -572,6 +621,35 @@ def write_framework_release_files(root: Path, target_version: str) -> None:
) )
def write_system_release_files(root: Path, target_version: str) -> None:
replace_first_line(
root / "iti_system" / "__about__.py",
lambda line: line.startswith("__version__ = "),
f'__version__ = "{target_version}"',
)
replace_first_line(
root / "pyproject.toml",
lambda line: line.startswith('iti-flask = { git = "https://git.noahlan.cn/iti-framework/iTi-Flask.git", tag = "'),
f'iti-flask = {{ git = "https://git.noahlan.cn/iti-framework/iTi-Flask.git", tag = "v{target_version}" }}',
)
replace_first_line(
root / "README.md",
lambda line: line.startswith(' "iti-flask @ git+https://git.noahlan.cn/iti-framework/iTi-Flask.git@v'),
f' "iti-flask @ git+https://git.noahlan.cn/iti-framework/iTi-Flask.git@v{target_version}",',
)
replace_first_line(
root / "README.md",
lambda line: line.startswith(' "iti-system @ git+https://git.noahlan.cn/iti-framework/iTi-System.git@v'),
f' "iti-system @ git+https://git.noahlan.cn/iti-framework/iTi-System.git@v{target_version}",',
)
replace_first_line(
root / "README.md",
lambda line: line.startswith("iticli release v"),
f"iticli release v{target_version}",
count=2,
)
def replace_first_line(path: Path, predicate: Any, new_line: str, count: int = 1) -> None: def replace_first_line(path: Path, predicate: Any, new_line: str, count: int = 1) -> None:
lines = path.read_text(encoding="utf-8").splitlines() lines = path.read_text(encoding="utf-8").splitlines()
updated = 0 updated = 0

@ -59,6 +59,23 @@ dependencies = [
assert ctx.has_system is True assert ctx.has_system is True
def test_detect_system_project(tmp_path: Path) -> None:
write(
tmp_path / "pyproject.toml",
"""
[project]
name = "iti-system"
dependencies = ["iti-flask"]
""",
)
write(tmp_path / "iti_system" / "module.py", "")
write(tmp_path / "iti_system" / "cli.py", "")
ctx = detect_project(tmp_path)
assert ctx.kind == "system"
def test_detect_from_child_directory(tmp_path: Path) -> None: def test_detect_from_child_directory(tmp_path: Path) -> None:
write( write(
tmp_path / "pyproject.toml", tmp_path / "pyproject.toml",

Loading…
Cancel
Save