feat(bumpversion): 重构版本号更新工具,支持多文件类型并新增minor版本命令
1. 重构bumpversion模块,支持自动识别pyproject.toml和__init__.py文件的版本号格式 2. 提取版本计算、替换字符串构建逻辑,提升代码可维护性 3. 在pymake.py中新增bumpmi命令用于执行次版本号更新 4. 全面升级测试用例,适配新的版本匹配逻辑,修正测试文件类型 5. 保留原始引号和格式,不破坏文件原有排版
This commit is contained in:
+136
-32
@@ -14,13 +14,105 @@ import pyflowx as px
|
|||||||
|
|
||||||
BumpVersionType = Literal["patch", "minor", "major"]
|
BumpVersionType = Literal["patch", "minor", "major"]
|
||||||
|
|
||||||
|
# 针对不同文件类型的版本号匹配模式
|
||||||
_VERSION_PATTERN = re.compile(
|
# pyproject.toml: version = "X.Y.Z" 或 version = 'X.Y.Z'
|
||||||
|
_PYPROJECT_VERSION_PATTERN = re.compile(
|
||||||
|
r'(?:^|\n)\s*version\s*=\s*["\']'
|
||||||
r"(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)"
|
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<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-]+)*))?",
|
r"(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?"
|
||||||
|
r'["\']',
|
||||||
|
re.MULTILINE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# __init__.py: __version__ = "X.Y.Z" 或 __version__ = 'X.Y.Z'
|
||||||
|
_INIT_VERSION_PATTERN = re.compile(
|
||||||
|
r'(?:^|\n)\s*__version__\s*=\s*["\']'
|
||||||
|
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-]+)*))?"
|
||||||
|
r'["\']',
|
||||||
|
re.MULTILINE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pattern_for_file(file_name: str) -> re.Pattern[str] | None:
|
||||||
|
"""根据文件类型获取对应的正则表达式.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
file_name : str
|
||||||
|
文件名
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
re.Pattern[str] | None
|
||||||
|
对应的正则表达式,如果无法确定则返回 None
|
||||||
|
"""
|
||||||
|
if file_name == "pyproject.toml":
|
||||||
|
return _PYPROJECT_VERSION_PATTERN
|
||||||
|
if file_name == "__init__.py":
|
||||||
|
return _INIT_VERSION_PATTERN
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _calculate_new_version(major: int, minor: int, patch: int, part: BumpVersionType) -> str:
|
||||||
|
"""计算新版本号.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
major : int
|
||||||
|
当前主版本号
|
||||||
|
minor : int
|
||||||
|
当前次版本号
|
||||||
|
patch : int
|
||||||
|
当前补丁版本号
|
||||||
|
part : BumpVersionType
|
||||||
|
要更新的部分
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
新版本号
|
||||||
|
"""
|
||||||
|
if part == "major":
|
||||||
|
return f"{major + 1}.0.0"
|
||||||
|
if part == "minor":
|
||||||
|
return f"{major}.{minor + 1}.0"
|
||||||
|
return f"{major}.{minor}.{patch + 1}"
|
||||||
|
|
||||||
|
|
||||||
|
def _build_replacement_string(original_match: str, new_version: str, file_name: str) -> str:
|
||||||
|
"""构建替换字符串,保留原始格式.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
original_match : str
|
||||||
|
原始匹配的字符串
|
||||||
|
new_version : str
|
||||||
|
新版本号
|
||||||
|
file_name : str
|
||||||
|
文件名
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
替换字符串
|
||||||
|
"""
|
||||||
|
quote_char = '"' if '"' in original_match else "'"
|
||||||
|
|
||||||
|
if file_name == "pyproject.toml":
|
||||||
|
prefix_match = re.match(r'(\s*version\s*=\s*)["\']', original_match)
|
||||||
|
prefix = prefix_match.group(1) if prefix_match else "version = "
|
||||||
|
return f"{prefix}{quote_char}{new_version}{quote_char}"
|
||||||
|
|
||||||
|
if file_name == "__init__.py":
|
||||||
|
prefix_match = re.match(r'(\s*__version__\s*=\s*)["\']', original_match)
|
||||||
|
prefix = prefix_match.group(1) if prefix_match else "__version__ = "
|
||||||
|
return f"{prefix}{quote_char}{new_version}{quote_char}"
|
||||||
|
|
||||||
|
return new_version
|
||||||
|
|
||||||
|
|
||||||
def bump_file_version(file_path: Path, part: BumpVersionType = "patch") -> str | None:
|
def bump_file_version(file_path: Path, part: BumpVersionType = "patch") -> str | None:
|
||||||
"""更新文件中的版本号.
|
"""更新文件中的版本号.
|
||||||
@@ -43,27 +135,33 @@ def bump_file_version(file_path: Path, part: BumpVersionType = "patch") -> str |
|
|||||||
print(f"读取文件 {file_path} 时出错: {e}")
|
print(f"读取文件 {file_path} 时出错: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
match = _VERSION_PATTERN.search(content)
|
# 获取文件对应的正则表达式
|
||||||
|
pattern = _get_pattern_for_file(file_path.name)
|
||||||
|
|
||||||
|
# 对于未知文件类型,尝试两种模式
|
||||||
|
if pattern:
|
||||||
|
match = pattern.search(content)
|
||||||
|
else:
|
||||||
|
match = _PYPROJECT_VERSION_PATTERN.search(content) or _INIT_VERSION_PATTERN.search(content)
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
print(f"文件 {file_path} 中未找到版本号模式")
|
print(f"文件 {file_path} 中未找到版本号模式")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 提取当前版本号
|
||||||
major = int(match.group("major"))
|
major = int(match.group("major"))
|
||||||
minor = int(match.group("minor"))
|
minor = int(match.group("minor"))
|
||||||
patch = int(match.group("patch"))
|
patch = int(match.group("patch"))
|
||||||
|
|
||||||
# 计算新版本号
|
# 计算新版本号
|
||||||
if part == "major":
|
new_version = _calculate_new_version(major, minor, patch, part)
|
||||||
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)
|
# 构建替换字符串
|
||||||
|
original_match = match.group(0)
|
||||||
|
replacement = _build_replacement_string(original_match, new_version, file_path.name)
|
||||||
|
|
||||||
|
# 更新文件内容
|
||||||
|
content = content.replace(original_match, replacement)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
file_path.write_text(content, encoding="utf-8")
|
file_path.write_text(content, encoding="utf-8")
|
||||||
@@ -71,7 +169,7 @@ def bump_file_version(file_path: Path, part: BumpVersionType = "patch") -> str |
|
|||||||
print(f"更新文件 {file_path} 版本号时出错: {e}")
|
print(f"更新文件 {file_path} 版本号时出错: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return new_version_str
|
return new_version
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -114,14 +212,16 @@ def main() -> None:
|
|||||||
|
|
||||||
# 更新所有文件的版本号(使用顺序执行避免竞争条件)
|
# 更新所有文件的版本号(使用顺序执行避免竞争条件)
|
||||||
# 使用相对于 cwd 的路径作为任务名,确保唯一性
|
# 使用相对于 cwd 的路径作为任务名,确保唯一性
|
||||||
graph = px.Graph.from_specs([
|
graph = px.Graph.from_specs(
|
||||||
px.TaskSpec(
|
[
|
||||||
f"bump_{file.relative_to(Path.cwd())}".replace("\\", "_").replace("/", "_").replace(".", "_"),
|
px.TaskSpec(
|
||||||
fn=bump_file_version,
|
f"bump_{file.relative_to(Path.cwd())}".replace("\\", "_").replace("/", "_").replace(".", "_"),
|
||||||
args=(file, part),
|
fn=bump_file_version,
|
||||||
)
|
args=(file, part),
|
||||||
for file in all_files
|
)
|
||||||
])
|
for file in all_files
|
||||||
|
]
|
||||||
|
)
|
||||||
report = px.run(graph, strategy="sequential")
|
report = px.run(graph, strategy="sequential")
|
||||||
|
|
||||||
# 收集新版本号(取第一个成功的结果)
|
# 收集新版本号(取第一个成功的结果)
|
||||||
@@ -139,19 +239,23 @@ def main() -> None:
|
|||||||
print(f"版本号已更新为: {new_version}")
|
print(f"版本号已更新为: {new_version}")
|
||||||
|
|
||||||
# 提交修改
|
# 提交修改
|
||||||
graph = px.Graph.from_specs([
|
graph = px.Graph.from_specs(
|
||||||
px.TaskSpec("git_add", cmd=["git", "add", "."]),
|
[
|
||||||
px.TaskSpec(
|
px.TaskSpec("git_add", cmd=["git", "add", "."]),
|
||||||
"git_commit", cmd=["git", "commit", "-m", f"bump version to {new_version}"], depends_on=["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")
|
px.run(graph, strategy="sequential")
|
||||||
|
|
||||||
# 创建 git tag
|
# 创建 git tag
|
||||||
if not args.no_tag:
|
if not args.no_tag:
|
||||||
tag_name = f"v{new_version}"
|
tag_name = f"v{new_version}"
|
||||||
graph = px.Graph.from_specs([
|
graph = px.Graph.from_specs(
|
||||||
px.TaskSpec("git_tag", cmd=["git", "tag", "-a", tag_name, "-m", f"Release {tag_name}"]),
|
[
|
||||||
])
|
px.TaskSpec("git_tag", cmd=["git", "tag", "-a", tag_name, "-m", f"Release {tag_name}"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
px.run(graph, strategy="sequential")
|
px.run(graph, strategy="sequential")
|
||||||
print(f"已创建标签: {tag_name}")
|
print(f"已创建标签: {tag_name}")
|
||||||
|
|||||||
@@ -20,15 +20,13 @@ def maturin_build_cmd() -> list[str]:
|
|||||||
"""
|
"""
|
||||||
command = ["maturin", "build", "-r"].copy()
|
command = ["maturin", "build", "-r"].copy()
|
||||||
if Constants.IS_WINDOWS:
|
if Constants.IS_WINDOWS:
|
||||||
command.extend(
|
command.extend([
|
||||||
[
|
"--target",
|
||||||
"--target",
|
"x86_64-win7-windows-msvc",
|
||||||
"x86_64-win7-windows-msvc",
|
"-Zbuild-std",
|
||||||
"-Zbuild-std",
|
"-i",
|
||||||
"-i",
|
"python3.8",
|
||||||
"python3.8",
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
@@ -118,6 +116,7 @@ def main():
|
|||||||
"c": px.Graph.from_specs([git_clean]),
|
"c": px.Graph.from_specs([git_clean]),
|
||||||
# 开发工具
|
# 开发工具
|
||||||
"bump": px.Graph.from_specs(["c", "tc", git_add_all, bump]),
|
"bump": px.Graph.from_specs(["c", "tc", git_add_all, bump]),
|
||||||
|
"bumpmi": px.Graph.from_specs([px.TaskSpec("bumpversion_minor", cmd=["bumpversion", "minor"])]),
|
||||||
"cov": px.Graph.from_specs([git_clean, test_coverage]),
|
"cov": px.Graph.from_specs([git_clean, test_coverage]),
|
||||||
"doc": px.Graph.from_specs([doc]),
|
"doc": px.Graph.from_specs([doc]),
|
||||||
"lint": px.Graph.from_specs([ruff_lint, ruff_format]),
|
"lint": px.Graph.from_specs([ruff_lint, ruff_format]),
|
||||||
|
|||||||
@@ -17,38 +17,38 @@ class TestBumpFileVersion:
|
|||||||
|
|
||||||
def test_bump_patch_version(self, tmp_path: Path) -> None:
|
def test_bump_patch_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump patch version correctly."""
|
"""Should bump patch version correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
test_file.write_text('version = "1.2.3"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
assert result == "1.2.4"
|
assert result == "1.2.4"
|
||||||
assert test_file.read_text(encoding="utf-8") == "version = 1.2.4"
|
assert test_file.read_text(encoding="utf-8") == 'version = "1.2.4"'
|
||||||
|
|
||||||
def test_bump_minor_version(self, tmp_path: Path) -> None:
|
def test_bump_minor_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump minor version correctly."""
|
"""Should bump minor version correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
test_file.write_text('version = "1.2.3"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "minor")
|
result = bumpversion.bump_file_version(test_file, "minor")
|
||||||
|
|
||||||
assert result == "1.3.0"
|
assert result == "1.3.0"
|
||||||
assert test_file.read_text(encoding="utf-8") == "version = 1.3.0"
|
assert test_file.read_text(encoding="utf-8") == 'version = "1.3.0"'
|
||||||
|
|
||||||
def test_bump_major_version(self, tmp_path: Path) -> None:
|
def test_bump_major_version(self, tmp_path: Path) -> None:
|
||||||
"""Should bump major version correctly."""
|
"""Should bump major version correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version = 1.2.3", encoding="utf-8")
|
test_file.write_text('version = "1.2.3"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "major")
|
result = bumpversion.bump_file_version(test_file, "major")
|
||||||
|
|
||||||
assert result == "2.0.0"
|
assert result == "2.0.0"
|
||||||
assert test_file.read_text(encoding="utf-8") == "version = 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:
|
def test_version_pattern_with_prerelease(self, tmp_path: Path) -> None:
|
||||||
"""Should handle version with prerelease suffix."""
|
"""Should handle version with prerelease suffix."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version = 1.2.3-alpha.1", encoding="utf-8")
|
test_file.write_text('version = "1.2.3-alpha.1"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
@@ -59,8 +59,8 @@ class TestBumpFileVersion:
|
|||||||
|
|
||||||
def test_version_pattern_with_build_metadata(self, tmp_path: Path) -> None:
|
def test_version_pattern_with_build_metadata(self, tmp_path: Path) -> None:
|
||||||
"""Should handle version with build metadata."""
|
"""Should handle version with build metadata."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version = 1.2.3+build.123", encoding="utf-8")
|
test_file.write_text('version = "1.2.3+build.123"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
@@ -82,13 +82,13 @@ class TestBumpFileVersion:
|
|||||||
|
|
||||||
def test_utf8_encoding(self, tmp_path: Path) -> None:
|
def test_utf8_encoding(self, tmp_path: Path) -> None:
|
||||||
"""Should handle UTF-8 encoded files correctly."""
|
"""Should handle UTF-8 encoded files correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
test_file.write_text("版本 = 1.2.3", encoding="utf-8")
|
test_file.write_text('__version__ = "1.2.3"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
assert result == "1.2.4"
|
assert result == "1.2.4"
|
||||||
assert test_file.read_text(encoding="utf-8") == "版本 = 1.2.4"
|
assert test_file.read_text(encoding="utf-8") == '__version__ = "1.2.4"'
|
||||||
|
|
||||||
def test_pyproject_toml_format(self, tmp_path: Path) -> None:
|
def test_pyproject_toml_format(self, tmp_path: Path) -> None:
|
||||||
"""Should handle pyproject.toml format correctly."""
|
"""Should handle pyproject.toml format correctly."""
|
||||||
@@ -124,16 +124,23 @@ __version__ = "1.0.0"
|
|||||||
assert '__version__ = "2.0.0"' in updated
|
assert '__version__ = "2.0.0"' in updated
|
||||||
|
|
||||||
def test_multiple_versions_in_file(self, tmp_path: Path) -> None:
|
def test_multiple_versions_in_file(self, tmp_path: Path) -> None:
|
||||||
"""Should only bump the first version occurrence."""
|
"""Should only bump the project version, not dependencies."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "pyproject.toml"
|
||||||
test_file.write_text("version1 = 1.0.0\nversion2 = 2.0.0", encoding="utf-8")
|
content = """
|
||||||
|
[project]
|
||||||
|
version = "1.0.0"
|
||||||
|
dependencies = ["lib >= 2.0.0", "other >= 3.0.0"]
|
||||||
|
"""
|
||||||
|
test_file.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
assert result == "1.0.1"
|
assert result == "1.0.1"
|
||||||
content = test_file.read_text(encoding="utf-8")
|
updated = test_file.read_text(encoding="utf-8")
|
||||||
assert "version1 = 1.0.1" in content
|
assert 'version = "1.0.1"' in updated
|
||||||
assert "version2 = 2.0.0" in content
|
# 确保 dependencies 中的版本没有被更新
|
||||||
|
assert "lib >= 2.0.0" in updated
|
||||||
|
assert "other >= 3.0.0" in updated
|
||||||
|
|
||||||
def test_file_read_error(self, tmp_path: Path, capsys) -> None:
|
def test_file_read_error(self, tmp_path: Path, capsys) -> None:
|
||||||
"""Should handle file read errors."""
|
"""Should handle file read errors."""
|
||||||
@@ -147,13 +154,13 @@ __version__ = "1.0.0"
|
|||||||
def test_file_write_error(self, tmp_path: Path, capsys) -> None:
|
def test_file_write_error(self, tmp_path: Path, capsys) -> None:
|
||||||
"""Should handle file write errors."""
|
"""Should handle file write errors."""
|
||||||
# 在只读目录中创建文件(这个测试在某些系统上可能不适用)
|
# 在只读目录中创建文件(这个测试在某些系统上可能不适用)
|
||||||
test_file = tmp_path / "readonly.txt"
|
test_file = tmp_path / "readonly.toml"
|
||||||
test_file.write_text("version = 1.0.0", encoding="utf-8")
|
test_file.write_text('version = "1.0.0"', encoding="utf-8")
|
||||||
# 设置为只读
|
# 设置为只读
|
||||||
test_file.chmod(0o444)
|
test_file.chmod(0o444)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception): # noqa: B017
|
||||||
bumpversion.bump_file_version(test_file, "patch")
|
bumpversion.bump_file_version(test_file, "patch")
|
||||||
finally:
|
finally:
|
||||||
# 恢复权限以便清理
|
# 恢复权限以便清理
|
||||||
@@ -168,8 +175,8 @@ class TestVersionPattern:
|
|||||||
|
|
||||||
def test_simple_version(self, tmp_path: Path) -> None:
|
def test_simple_version(self, tmp_path: Path) -> None:
|
||||||
"""Should match simple version."""
|
"""Should match simple version."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
test_file.write_text("1.0.0", encoding="utf-8")
|
test_file.write_text('__version__ = "1.0.0"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
@@ -177,8 +184,8 @@ class TestVersionPattern:
|
|||||||
|
|
||||||
def test_version_with_zeros(self, tmp_path: Path) -> None:
|
def test_version_with_zeros(self, tmp_path: Path) -> None:
|
||||||
"""Should handle versions with zeros correctly."""
|
"""Should handle versions with zeros correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
test_file.write_text("0.0.0", encoding="utf-8")
|
test_file.write_text('__version__ = "0.0.0"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
@@ -186,21 +193,22 @@ class TestVersionPattern:
|
|||||||
|
|
||||||
def test_large_version_numbers(self, tmp_path: Path) -> None:
|
def test_large_version_numbers(self, tmp_path: Path) -> None:
|
||||||
"""Should handle large version numbers."""
|
"""Should handle large version numbers."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
test_file.write_text("10.20.30", encoding="utf-8")
|
test_file.write_text('__version__ = "10.20.30"', encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "minor")
|
result = bumpversion.bump_file_version(test_file, "minor")
|
||||||
|
|
||||||
assert result == "10.21.0"
|
assert result == "10.21.0"
|
||||||
|
|
||||||
def test_version_in_url(self, tmp_path: Path) -> None:
|
def test_version_in_url(self, tmp_path: Path) -> None:
|
||||||
"""Should only match first version in complex text."""
|
"""Should not match version in URL or other contexts."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "test.txt"
|
||||||
test_file.write_text("https://example.com/v1.2.3/download", encoding="utf-8")
|
test_file.write_text("https://example.com/v1.2.3/download", encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
|
|
||||||
assert result == "1.2.4"
|
# 不应该匹配 URL 中的版本号
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------- #
|
||||||
@@ -222,8 +230,8 @@ class TestEdgeCases:
|
|||||||
|
|
||||||
def test_file_with_special_chars(self, tmp_path: Path) -> None:
|
def test_file_with_special_chars(self, tmp_path: Path) -> None:
|
||||||
"""Should handle file with special characters."""
|
"""Should handle file with special characters."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
content = "# 中文注释\nversion = 1.0.0\n# 特殊字符: @#$%"
|
content = '# 中文注释\n__version__ = "1.0.0"\n# 特殊字符: @#$%'
|
||||||
test_file.write_text(content, encoding="utf-8")
|
test_file.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
result = bumpversion.bump_file_version(test_file, "patch")
|
result = bumpversion.bump_file_version(test_file, "patch")
|
||||||
@@ -235,8 +243,8 @@ class TestEdgeCases:
|
|||||||
|
|
||||||
def test_consecutive_bumps(self, tmp_path: Path) -> None:
|
def test_consecutive_bumps(self, tmp_path: Path) -> None:
|
||||||
"""Should handle consecutive version bumps correctly."""
|
"""Should handle consecutive version bumps correctly."""
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "__init__.py"
|
||||||
test_file.write_text("version = 1.0.0", encoding="utf-8")
|
test_file.write_text('__version__ = "1.0.0"', encoding="utf-8")
|
||||||
|
|
||||||
# 第一次 bump
|
# 第一次 bump
|
||||||
result1 = bumpversion.bump_file_version(test_file, "patch")
|
result1 = bumpversion.bump_file_version(test_file, "patch")
|
||||||
@@ -251,4 +259,4 @@ class TestEdgeCases:
|
|||||||
assert result3 == "2.0.0"
|
assert result3 == "2.0.0"
|
||||||
|
|
||||||
# 验证最终结果
|
# 验证最终结果
|
||||||
assert test_file.read_text(encoding="utf-8") == "version = 2.0.0"
|
assert test_file.read_text(encoding="utf-8") == '__version__ = "2.0.0"'
|
||||||
|
|||||||
Reference in New Issue
Block a user