~bumpversion
This commit is contained in:
@@ -84,7 +84,7 @@ from .runner import CliExitCode, CliRunner
|
|||||||
from .storage import JSONBackend, MemoryBackend, StateBackend
|
from .storage import JSONBackend, MemoryBackend, StateBackend
|
||||||
from .task import TaskCmd, TaskEvent, TaskResult, TaskSpec, TaskStatus
|
from .task import TaskCmd, TaskEvent, TaskResult, TaskSpec, TaskStatus
|
||||||
|
|
||||||
__version__ = "0.1.13"
|
__version__ = "0.1.14"
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"IS_LINUX",
|
"IS_LINUX",
|
||||||
|
|||||||
+128
-72
@@ -5,97 +5,153 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import subprocess
|
import argparse
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Literal, get_args
|
||||||
|
|
||||||
import pyflowx as px
|
import pyflowx as px
|
||||||
|
|
||||||
# ============================================================================
|
BumpVersionType = Literal["patch", "minor", "major"]
|
||||||
# 辅助函数
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
def bump_version(part: str = "patch", tag: bool = False, commit: bool = False) -> None:
|
_VERSION_PATTERN = re.compile(
|
||||||
"""递增版本号.
|
r"(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)"
|
||||||
|
r"(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"
|
||||||
|
r"(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def bump_file_version(file_path: Path, part: BumpVersionType = "patch") -> str | None:
|
||||||
|
"""更新文件中的版本号.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
part : str
|
file_path : Path
|
||||||
|
要更新的文件路径
|
||||||
|
part : BumpVersionType
|
||||||
版本部分: patch, minor, major
|
版本部分: patch, minor, major
|
||||||
tag : bool
|
|
||||||
是否创建 Git 标签
|
Returns
|
||||||
commit : bool
|
-------
|
||||||
是否提交更改
|
str | None
|
||||||
|
更新后的新版本号,如果文件中未找到版本号则返回 None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subprocess.run(["bumpversion", part], check=True)
|
content = file_path.read_text(encoding="utf-8")
|
||||||
if commit:
|
except Exception as e:
|
||||||
subprocess.run(["git", "add", "."], check=True)
|
print(f"读取文件 {file_path} 时出错: {e}")
|
||||||
subprocess.run(["git", "commit", "-m", f"bump version {part}"], check=True)
|
|
||||||
if tag:
|
|
||||||
# 获取当前版本号
|
|
||||||
result = subprocess.run(
|
|
||||||
["git", "describe", "--tags", "--abbrev=0"],
|
|
||||||
check=True,
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
)
|
|
||||||
version = result.stdout.strip() if result.returncode == 0 else f"v{part}"
|
|
||||||
subprocess.run(
|
|
||||||
["git", "tag", "-a", version, "-m", f"version {part}"],
|
|
||||||
check=True,
|
|
||||||
)
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("未找到 bumpversion 工具,请先安装: pip install bumpversion")
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
match = _VERSION_PATTERN.search(content)
|
||||||
|
if not match:
|
||||||
|
print(f"文件 {file_path} 中未找到版本号模式")
|
||||||
|
return None
|
||||||
|
|
||||||
|
major = int(match.group("major"))
|
||||||
|
minor = int(match.group("minor"))
|
||||||
|
patch = int(match.group("patch"))
|
||||||
|
|
||||||
|
# 计算新版本号
|
||||||
|
if part == "major":
|
||||||
|
new_major = major + 1
|
||||||
|
new_version_str = f"{new_major}.0.0"
|
||||||
|
elif part == "minor":
|
||||||
|
new_minor = minor + 1
|
||||||
|
new_version_str = f"{major}.{new_minor}.0"
|
||||||
|
else: # patch
|
||||||
|
new_patch = patch + 1
|
||||||
|
new_version_str = f"{major}.{minor}.{new_patch}"
|
||||||
|
|
||||||
|
content = content.replace(match.group(0), new_version_str)
|
||||||
|
|
||||||
def bump_version_alpha(part: str = "patch") -> None:
|
|
||||||
"""递增版本号并添加 alpha 预发布标识."""
|
|
||||||
try:
|
try:
|
||||||
subprocess.run(["bumpversion", part, "--new-version", f"{part}-alpha"], check=True)
|
file_path.write_text(content, encoding="utf-8")
|
||||||
except FileNotFoundError:
|
except Exception as e:
|
||||||
print("未找到 bumpversion 工具,请先安装: pip install bumpversion")
|
print(f"更新文件 {file_path} 版本号时出错: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
return new_version_str
|
||||||
# ============================================================================
|
|
||||||
# TaskSpec 定义
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
bump_patch: px.TaskSpec = px.TaskSpec("bump_patch", fn=lambda: bump_version("patch"))
|
|
||||||
bump_minor: px.TaskSpec = px.TaskSpec("bump_minor", fn=lambda: bump_version("minor"))
|
|
||||||
bump_major: px.TaskSpec = px.TaskSpec("bump_major", fn=lambda: bump_version("major"))
|
|
||||||
bump_patch_tag: px.TaskSpec = px.TaskSpec("bump_patch_tag", fn=lambda: bump_version("patch", tag=True))
|
|
||||||
bump_minor_tag: px.TaskSpec = px.TaskSpec("bump_minor_tag", fn=lambda: bump_version("minor", tag=True))
|
|
||||||
bump_major_tag: px.TaskSpec = px.TaskSpec("bump_major_tag", fn=lambda: bump_version("major", tag=True))
|
|
||||||
bump_patch_alpha: px.TaskSpec = px.TaskSpec("bump_patch_alpha", fn=lambda: bump_version_alpha("patch"))
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# CLI Runner
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""版本号管理工具主函数."""
|
"""版本号管理工具主函数."""
|
||||||
runner = px.CliRunner(
|
parser = argparse.ArgumentParser(description="BumpVersion - 版本号自动管理工具")
|
||||||
strategy="thread",
|
parser.add_argument(
|
||||||
description="BumpVersion - 版本号自动管理工具",
|
"part",
|
||||||
graphs={
|
type=str,
|
||||||
# 递增补丁号 (1.0.0 -> 1.0.1)
|
nargs="?",
|
||||||
"p": px.Graph.from_specs([bump_patch]),
|
default="patch",
|
||||||
# 递增次版本号 (1.0.0 -> 1.1.0)
|
choices=get_args(BumpVersionType),
|
||||||
"m": px.Graph.from_specs([bump_minor]),
|
help=f"版本部分: {get_args(BumpVersionType)}",
|
||||||
# 递增主版本号 (1.0.0 -> 2.0.0)
|
|
||||||
"M": px.Graph.from_specs([bump_major]),
|
|
||||||
# 递增补丁号并创建标签
|
|
||||||
"pt": px.Graph.from_specs([bump_patch_tag]),
|
|
||||||
# 递增次版本号并创建标签
|
|
||||||
"mt": px.Graph.from_specs([bump_minor_tag]),
|
|
||||||
# 递增主版本号并创建标签
|
|
||||||
"Mt": px.Graph.from_specs([bump_major_tag]),
|
|
||||||
# 递增补丁号并添加 alpha 预发布标识
|
|
||||||
"pa": px.Graph.from_specs([bump_patch_alpha]),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
runner.run_cli()
|
parser.add_argument(
|
||||||
|
"--no-tag",
|
||||||
|
action="store_true",
|
||||||
|
help="提交后不创建 git tag",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
part = args.part
|
||||||
|
|
||||||
|
# 搜索文件,排除常见的虚拟环境和缓存目录
|
||||||
|
ignore_dirs = {".venv", "venv", ".git", "__pycache__", ".tox", "node_modules", "build", "dist", ".eggs"}
|
||||||
|
all_files = set()
|
||||||
|
|
||||||
|
for pattern in ["__init__.py", "pyproject.toml"]:
|
||||||
|
for file in Path.cwd().rglob(pattern):
|
||||||
|
# 检查路径中是否包含需要忽略的目录
|
||||||
|
if not any(ignore_dir in file.parts for ignore_dir in ignore_dirs):
|
||||||
|
all_files.add(file)
|
||||||
|
|
||||||
|
if not all_files:
|
||||||
|
print("未找到包含版本号的文件")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"找到 {len(all_files)} 个文件需要更新版本号")
|
||||||
|
for file in sorted(all_files):
|
||||||
|
print(f" - {file.relative_to(Path.cwd())}")
|
||||||
|
|
||||||
|
# 更新所有文件的版本号(使用顺序执行避免竞争条件)
|
||||||
|
# 使用相对于 cwd 的路径作为任务名,确保唯一性
|
||||||
|
graph = px.Graph.from_specs([
|
||||||
|
px.TaskSpec(
|
||||||
|
f"bump_{file.relative_to(Path.cwd())}".replace("\\", "_").replace("/", "_").replace(".", "_"),
|
||||||
|
fn=bump_file_version,
|
||||||
|
args=(file, part),
|
||||||
|
)
|
||||||
|
for file in all_files
|
||||||
|
])
|
||||||
|
report = px.run(graph, strategy="sequential")
|
||||||
|
|
||||||
|
# 收集新版本号(取第一个成功的结果)
|
||||||
|
new_version = None
|
||||||
|
for task_name in report:
|
||||||
|
result = report[task_name]
|
||||||
|
if result is not None:
|
||||||
|
new_version = result
|
||||||
|
break
|
||||||
|
|
||||||
|
if not new_version:
|
||||||
|
print("未能获取新版本号")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"版本号已更新为: {new_version}")
|
||||||
|
|
||||||
|
# 提交修改
|
||||||
|
graph = px.Graph.from_specs([
|
||||||
|
px.TaskSpec("git_add", cmd=["git", "add", "."]),
|
||||||
|
px.TaskSpec(
|
||||||
|
"git_commit", cmd=["git", "commit", "-m", f"bump version to {new_version}"], depends_on=["git_add"]
|
||||||
|
),
|
||||||
|
])
|
||||||
|
px.run(graph, strategy="sequential")
|
||||||
|
|
||||||
|
# 创建 git tag
|
||||||
|
if not args.no_tag:
|
||||||
|
tag_name = f"v{new_version}"
|
||||||
|
graph = px.Graph.from_specs([
|
||||||
|
px.TaskSpec("git_tag", cmd=["git", "tag", "-a", tag_name, "-m", f"Release {tag_name}"]),
|
||||||
|
])
|
||||||
|
px.run(graph, strategy="sequential")
|
||||||
|
print(f"已创建标签: {tag_name}")
|
||||||
|
|||||||
+221
-73
@@ -2,105 +2,253 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from unittest.mock import MagicMock, patch
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import pyflowx as px
|
|
||||||
from pyflowx.cli import bumpversion
|
from pyflowx.cli import bumpversion
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
# bump_version
|
# bump_file_version
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
class TestBumpVersion:
|
class TestBumpFileVersion:
|
||||||
"""Test bump_version function."""
|
"""Test bump_file_version function."""
|
||||||
|
|
||||||
def test_bump_version_patch(self) -> None:
|
def test_bump_patch_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump patch version."""
|
"""Should bump patch version correctly."""
|
||||||
with patch("subprocess.run") as mock_run:
|
test_file = tmp_path / "test.txt"
|
||||||
mock_run.return_value = MagicMock(returncode=0)
|
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
||||||
bumpversion.bump_version("patch")
|
|
||||||
assert mock_run.called
|
|
||||||
|
|
||||||
def test_bump_version_minor(self) -> None:
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
"""Should bump minor version."""
|
|
||||||
with patch("subprocess.run") as mock_run:
|
|
||||||
mock_run.return_value = MagicMock(returncode=0)
|
|
||||||
bumpversion.bump_version("minor")
|
|
||||||
assert mock_run.called
|
|
||||||
|
|
||||||
def test_bump_version_major(self) -> None:
|
assert result == "1.2.4"
|
||||||
"""Should bump major version."""
|
assert test_file.read_text(encoding="utf-8") == "version = 1.2.4"
|
||||||
with patch("subprocess.run") as mock_run:
|
|
||||||
mock_run.return_value = MagicMock(returncode=0)
|
|
||||||
bumpversion.bump_version("major")
|
|
||||||
assert mock_run.called
|
|
||||||
|
|
||||||
def test_bump_version_with_tag(self) -> None:
|
def test_bump_minor_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump version with tag."""
|
"""Should bump minor version correctly."""
|
||||||
with patch("subprocess.run") as mock_run:
|
test_file = tmp_path / "test.txt"
|
||||||
mock_run.return_value = MagicMock(returncode=0, stdout="v1.0.0")
|
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
||||||
bumpversion.bump_version("patch", tag=True)
|
|
||||||
assert mock_run.called
|
|
||||||
|
|
||||||
def test_bump_version_with_commit(self) -> None:
|
result = bumpversion.bump_file_version(test_file, "minor")
|
||||||
"""Should bump version with commit."""
|
|
||||||
with patch("subprocess.run") as mock_run:
|
|
||||||
mock_run.return_value = MagicMock(returncode=0)
|
|
||||||
bumpversion.bump_version("patch", commit=True)
|
|
||||||
assert mock_run.called
|
|
||||||
|
|
||||||
def test_bump_version_file_not_found(self) -> None:
|
assert result == "1.3.0"
|
||||||
"""Should handle FileNotFoundError."""
|
assert test_file.read_text(encoding="utf-8") == "version = 1.3.0"
|
||||||
with patch("subprocess.run", side_effect=FileNotFoundError), pytest.raises(FileNotFoundError):
|
|
||||||
bumpversion.bump_version("patch")
|
def test_bump_major_version(self, tmp_path: Path) -> None:
|
||||||
|
"""Should bump major version correctly."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "major")
|
||||||
|
|
||||||
|
assert result == "2.0.0"
|
||||||
|
assert test_file.read_text(encoding="utf-8") == "version = 2.0.0"
|
||||||
|
|
||||||
|
def test_version_pattern_with_prerelease(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle version with prerelease suffix."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("version = 1.2.3-alpha.1", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.2.4"
|
||||||
|
# 预发布版本应该被清除
|
||||||
|
content = test_file.read_text(encoding="utf-8")
|
||||||
|
assert "alpha" not in content
|
||||||
|
|
||||||
|
def test_version_pattern_with_build_metadata(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle version with build metadata."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("version = 1.2.3+build.123", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.2.4"
|
||||||
|
# 构建元数据应该被清除
|
||||||
|
content = test_file.read_text(encoding="utf-8")
|
||||||
|
assert "build" not in content
|
||||||
|
|
||||||
|
def test_no_version_found(self, tmp_path: Path, capsys) -> None:
|
||||||
|
"""Should return None when no version pattern found."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("no version here", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result is None
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert "未找到版本号模式" in captured.out
|
||||||
|
|
||||||
|
def test_utf8_encoding(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle UTF-8 encoded files correctly."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("版本 = 1.2.3", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.2.4"
|
||||||
|
assert test_file.read_text(encoding="utf-8") == "版本 = 1.2.4"
|
||||||
|
|
||||||
|
def test_pyproject_toml_format(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle pyproject.toml format correctly."""
|
||||||
|
test_file = tmp_path / "pyproject.toml"
|
||||||
|
content = """
|
||||||
|
[project]
|
||||||
|
name = "test"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Test project"
|
||||||
|
"""
|
||||||
|
test_file.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "minor")
|
||||||
|
|
||||||
|
assert result == "0.2.0"
|
||||||
|
updated = test_file.read_text(encoding="utf-8")
|
||||||
|
assert 'version = "0.2.0"' in updated
|
||||||
|
assert 'name = "test"' in updated
|
||||||
|
|
||||||
|
def test_init_py_format(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle __init__.py format correctly."""
|
||||||
|
test_file = tmp_path / "__init__.py"
|
||||||
|
content = '''"""Package info."""
|
||||||
|
|
||||||
|
__version__ = "1.0.0"
|
||||||
|
'''
|
||||||
|
test_file.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "major")
|
||||||
|
|
||||||
|
assert result == "2.0.0"
|
||||||
|
updated = test_file.read_text(encoding="utf-8")
|
||||||
|
assert '__version__ = "2.0.0"' in updated
|
||||||
|
|
||||||
|
def test_multiple_versions_in_file(self, tmp_path: Path) -> None:
|
||||||
|
"""Should only bump the first version occurrence."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("version1 = 1.0.0\nversion2 = 2.0.0", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.0.1"
|
||||||
|
content = test_file.read_text(encoding="utf-8")
|
||||||
|
assert "version1 = 1.0.1" in content
|
||||||
|
assert "version2 = 2.0.0" in content
|
||||||
|
|
||||||
|
def test_file_read_error(self, tmp_path: Path, capsys) -> None:
|
||||||
|
"""Should handle file read errors."""
|
||||||
|
# 创建一个目录而不是文件
|
||||||
|
test_file = tmp_path / "test_dir"
|
||||||
|
test_file.mkdir()
|
||||||
|
|
||||||
|
with pytest.raises(Exception): # noqa: B017
|
||||||
|
bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
def test_file_write_error(self, tmp_path: Path, capsys) -> None:
|
||||||
|
"""Should handle file write errors."""
|
||||||
|
# 在只读目录中创建文件(这个测试在某些系统上可能不适用)
|
||||||
|
test_file = tmp_path / "readonly.txt"
|
||||||
|
test_file.write_text("version = 1.0.0", encoding="utf-8")
|
||||||
|
# 设置为只读
|
||||||
|
test_file.chmod(0o444)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
finally:
|
||||||
|
# 恢复权限以便清理
|
||||||
|
test_file.chmod(0o644)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
# bump_version_alpha
|
# Version pattern tests
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
class TestBumpVersionAlpha:
|
class TestVersionPattern:
|
||||||
"""Test bump_version_alpha function."""
|
"""Test version pattern matching."""
|
||||||
|
|
||||||
def test_bump_version_alpha_patch(self) -> None:
|
def test_simple_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump alpha patch version."""
|
"""Should match simple version."""
|
||||||
with patch("subprocess.run") as mock_run:
|
test_file = tmp_path / "test.txt"
|
||||||
mock_run.return_value = MagicMock(returncode=0)
|
test_file.write_text("1.0.0", encoding="utf-8")
|
||||||
bumpversion.bump_version_alpha("patch")
|
|
||||||
assert mock_run.called
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.0.1"
|
||||||
|
|
||||||
|
def test_version_with_zeros(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle versions with zeros correctly."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("0.0.0", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "0.0.1"
|
||||||
|
|
||||||
|
def test_large_version_numbers(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle large version numbers."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("10.20.30", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "minor")
|
||||||
|
|
||||||
|
assert result == "10.21.0"
|
||||||
|
|
||||||
|
def test_version_in_url(self, tmp_path: Path) -> None:
|
||||||
|
"""Should only match first version in complex text."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("https://example.com/v1.2.3/download", encoding="utf-8")
|
||||||
|
|
||||||
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
|
assert result == "1.2.4"
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
# TaskSpec definitions
|
# Edge cases
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
class TestTaskSpecDefinitions:
|
class TestEdgeCases:
|
||||||
"""Test that all TaskSpec definitions are valid."""
|
"""Test edge cases and error handling."""
|
||||||
|
|
||||||
def test_bump_patch_spec(self) -> None:
|
def test_empty_file(self, tmp_path: Path, capsys) -> None:
|
||||||
"""bump_patch spec should be properly defined."""
|
"""Should handle empty file."""
|
||||||
assert bumpversion.bump_patch.name == "bump_patch"
|
test_file = tmp_path / "empty.txt"
|
||||||
assert bumpversion.bump_patch.fn is not None
|
test_file.write_text("", encoding="utf-8")
|
||||||
|
|
||||||
def test_bump_minor_spec(self) -> None:
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
"""bump_minor spec should be properly defined."""
|
|
||||||
assert bumpversion.bump_minor.name == "bump_minor"
|
|
||||||
assert bumpversion.bump_minor.fn is not None
|
|
||||||
|
|
||||||
def test_bump_major_spec(self) -> None:
|
assert result is None
|
||||||
"""bump_major spec should be properly defined."""
|
captured = capsys.readouterr()
|
||||||
assert bumpversion.bump_major.name == "bump_major"
|
assert "未找到版本号模式" in captured.out
|
||||||
assert bumpversion.bump_major.fn is not None
|
|
||||||
|
|
||||||
|
def test_file_with_special_chars(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle file with special characters."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
content = "# 中文注释\nversion = 1.0.0\n# 特殊字符: @#$%"
|
||||||
|
test_file.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
# ---------------------------------------------------------------------- #
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
# main function
|
|
||||||
# ---------------------------------------------------------------------- #
|
|
||||||
class TestMain:
|
|
||||||
"""Test main function."""
|
|
||||||
|
|
||||||
def test_main_calls_run_cli(self) -> None:
|
assert result == "1.0.1"
|
||||||
"""main() should create a CliRunner and call run_cli()."""
|
updated = test_file.read_text(encoding="utf-8")
|
||||||
with patch.object(px.CliRunner, "run_cli") as mock_run_cli:
|
assert "# 中文注释" in updated
|
||||||
bumpversion.main()
|
assert "# 特殊字符: @#$%" in updated
|
||||||
assert mock_run_cli.called
|
|
||||||
|
def test_consecutive_bumps(self, tmp_path: Path) -> None:
|
||||||
|
"""Should handle consecutive version bumps correctly."""
|
||||||
|
test_file = tmp_path / "test.txt"
|
||||||
|
test_file.write_text("version = 1.0.0", encoding="utf-8")
|
||||||
|
|
||||||
|
# 第一次 bump
|
||||||
|
result1 = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
assert result1 == "1.0.1"
|
||||||
|
|
||||||
|
# 第二次 bump
|
||||||
|
result2 = bumpversion.bump_file_version(test_file, "minor")
|
||||||
|
assert result2 == "1.1.0"
|
||||||
|
|
||||||
|
# 第三次 bump
|
||||||
|
result3 = bumpversion.bump_file_version(test_file, "major")
|
||||||
|
assert result3 == "2.0.0"
|
||||||
|
|
||||||
|
# 验证最终结果
|
||||||
|
assert test_file.read_text(encoding="utf-8") == "version = 2.0.0"
|
||||||
|
|||||||
@@ -2184,7 +2184,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyflowx"
|
name = "pyflowx"
|
||||||
version = "0.1.12"
|
version = "0.1.13"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "graphlib-backport", marker = "python_full_version < '3.9'" },
|
{ name = "graphlib-backport", marker = "python_full_version < '3.9'" },
|
||||||
|
|||||||
Reference in New Issue
Block a user