mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-11-13 09:13:30 +01:00
fix(version): keep VERSION_DATE in _version_date.py up to date
Additional fixes Use a portable shebang instead of the workspace .venv in update_version.py Update the stale VERSION_DATE of 2026-02-24 to 2026-11-12 Assisted-by: Claude Code (claude-opus-5-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
14e439c265
commit
88904874e7
@@ -57,6 +57,9 @@ and the generated documentation:
|
|||||||
make prepare-version
|
make prepare-version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the version string changes, `make prepare-version` also sets `VERSION_DATE`
|
||||||
|
in src/akkudoktoreos/core/_version_date.py. Do not edit this file by hand.
|
||||||
|
|
||||||
Check the changes by:
|
Check the changes by:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+74
-30
@@ -1,19 +1,30 @@
|
|||||||
#!.venv/bin/python
|
#!/usr/bin/env python3
|
||||||
"""General version replacement script.
|
"""General version replacement script.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python scripts/update_version.py <version> <file1> [file2 ...]
|
python scripts/update_version.py <version> [<file1> [file2 ...]]
|
||||||
|
|
||||||
|
Without files, the version is replaced in DEFAULT_VERSION_FILES.
|
||||||
|
|
||||||
|
If the version string changed in one of the project's version files
|
||||||
|
(DEFAULT_VERSION_FILES), a new version was created and
|
||||||
|
``src/akkudoktoreos/core/_version_date.py`` is regenerated. Its
|
||||||
|
VERSION_DATE is the date ``_version_date_hash()`` computes: the date of the
|
||||||
|
last commit touching package files, or the current UTC time if package files
|
||||||
|
have uncommitted changes (a commit is expected soon).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#!/usr/bin/env python3
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from datetime import timezone
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import TYPE_CHECKING, List
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from datetime import datetime # type of the dates of akkudoktoreos.core.version
|
||||||
|
|
||||||
PROJECT_ROOT = Path(__file__).parent.parent
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
PACKAGE_DIR = PROJECT_ROOT / "src" / "akkudoktoreos"
|
|
||||||
|
|
||||||
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
||||||
SRC_DIR = PROJECT_ROOT / "src"
|
SRC_DIR = PROJECT_ROOT / "src"
|
||||||
@@ -103,25 +114,65 @@ def update_version_in_file(file_path: Path, new_version: str) -> bool:
|
|||||||
return file_would_be_updated
|
return file_would_be_updated
|
||||||
|
|
||||||
|
|
||||||
def update_version_date_file() -> str:
|
def write_version_date(version_date: datetime, date_file: Path) -> bool:
|
||||||
"""Write current version date to _version_date.py, only if changed."""
|
"""Write VERSION_DATE to a version date file if the version date changes.
|
||||||
|
|
||||||
|
The file is left untouched when it already holds a date in the
|
||||||
|
VERSION_DATE_FORMAT that gives the same dev version date digits (the same
|
||||||
|
hour) as ``version_date``.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version_date: Version date to write; naive datetimes are taken as UTC.
|
||||||
|
date_file: Path of the version date file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the file was written.
|
||||||
|
"""
|
||||||
|
from akkudoktoreos.core.version import (
|
||||||
|
format_version_date_file,
|
||||||
|
parse_version_date_file,
|
||||||
|
version_date_digits,
|
||||||
|
)
|
||||||
|
|
||||||
|
if date_file.exists():
|
||||||
|
stored_content = date_file.read_text(encoding="utf-8")
|
||||||
|
stored_date = parse_version_date_file(stored_content)
|
||||||
|
if (
|
||||||
|
stored_date is not None
|
||||||
|
and stored_content == format_version_date_file(stored_date)
|
||||||
|
and version_date_digits(stored_date) == version_date_digits(version_date)
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
with date_file.open("w", encoding="utf-8", newline="\n") as file:
|
||||||
|
file.write(format_version_date_file(version_date))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def update_version_date_file() -> None:
|
||||||
|
"""Write the current version date to _version_date.py if it changes."""
|
||||||
from akkudoktoreos.core.version import VERSION_DATE_FILE, _version_date_hash
|
from akkudoktoreos.core.version import VERSION_DATE_FILE, _version_date_hash
|
||||||
|
|
||||||
version_date, _ = _version_date_hash()
|
version_date, _ = _version_date_hash()
|
||||||
version_date_utc = version_date.astimezone(timezone.utc)
|
if write_version_date(version_date, VERSION_DATE_FILE):
|
||||||
version_date_str = version_date_utc.isoformat()
|
print(f"Updated {VERSION_DATE_FILE}: {VERSION_DATE_FILE.read_text(encoding='utf-8').strip()}")
|
||||||
new_content = f'VERSION_DATE = "{version_date_str}"\n'
|
else:
|
||||||
|
|
||||||
if VERSION_DATE_FILE.exists() and VERSION_DATE_FILE.read_text(encoding="utf-8") == new_content:
|
|
||||||
print(f"No change to {VERSION_DATE_FILE}")
|
print(f"No change to {VERSION_DATE_FILE}")
|
||||||
return str(VERSION_DATE_FILE)
|
|
||||||
|
|
||||||
with VERSION_DATE_FILE.open("w", encoding="utf-8", newline="\n") as file:
|
|
||||||
file.write(new_content)
|
|
||||||
print(f"Updated {VERSION_DATE_FILE} with UTC date {version_date_str}")
|
|
||||||
return str(VERSION_DATE_FILE)
|
|
||||||
|
|
||||||
|
|
||||||
def main(version: str, files: List[str]):
|
def main(version: str, files: List[str]) -> None:
|
||||||
|
"""Replace the version string in the given files.
|
||||||
|
|
||||||
|
If the version string changed in one of the project's version files
|
||||||
|
(DEFAULT_VERSION_FILES), the version date file is regenerated as well.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version: New version string.
|
||||||
|
files: Files to update.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If no version or no files are given.
|
||||||
|
"""
|
||||||
if not version:
|
if not version:
|
||||||
raise ValueError("No version provided")
|
raise ValueError("No version provided")
|
||||||
if not files:
|
if not files:
|
||||||
@@ -138,16 +189,9 @@ def main(version: str, files: List[str]):
|
|||||||
|
|
||||||
if updated_files:
|
if updated_files:
|
||||||
print(f"Updated files: {', '.join(updated_files)}")
|
print(f"Updated files: {', '.join(updated_files)}")
|
||||||
|
version_files = {path.resolve() for path in DEFAULT_VERSION_FILES}
|
||||||
# Only update VERSION_DATE_FILE if a real package file was touched
|
if any(Path(f).resolve() in version_files for f in updated_files):
|
||||||
# Exclude VERSION_DATE_FILE itself to avoid a self-referencing loop
|
update_version_date_file()
|
||||||
from akkudoktoreos.core.version import VERSION_DATE_FILE
|
|
||||||
package_files_updated = any(
|
|
||||||
str(PACKAGE_DIR) in f and Path(f).resolve() != VERSION_DATE_FILE.resolve()
|
|
||||||
for f in updated_files
|
|
||||||
)
|
|
||||||
if package_files_updated:
|
|
||||||
updated_files.append(update_version_date_file())
|
|
||||||
else:
|
else:
|
||||||
print("No files updated.")
|
print("No files updated.")
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VERSION_DATE = "2026-02-24T16:58:00Z"
|
VERSION_DATE = "2026-11-12T12:35:37Z"
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ VERSION_DEV_HASH_PRECISION = 8
|
|||||||
# File to hold the date of the latest commit.
|
# File to hold the date of the latest commit.
|
||||||
VERSION_DATE_FILE = Path(__file__).parent / "_version_date.py"
|
VERSION_DATE_FILE = Path(__file__).parent / "_version_date.py"
|
||||||
|
|
||||||
|
# Format of VERSION_DATE in VERSION_DATE_FILE (UTC)
|
||||||
|
VERSION_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
||||||
|
|
||||||
|
# Format of the date digits in dev versions; dev versions resolve the date to the hour
|
||||||
|
VERSION_DATE_DEV_FORMAT = "%y%m%d%H"
|
||||||
|
|
||||||
|
# Assignment of VERSION_DATE in VERSION_DATE_FILE
|
||||||
|
VERSION_DATE_PATTERN = re.compile(r'^VERSION_DATE\s*=\s*"(?P<date>[^"]+)"', re.MULTILINE)
|
||||||
|
|
||||||
# Hashing configuration
|
# Hashing configuration
|
||||||
DIR_PACKAGE_ROOT = Path(__file__).resolve().parent.parent
|
DIR_PACKAGE_ROOT = Path(__file__).resolve().parent.parent
|
||||||
ALLOWED_SUFFIXES: set[str] = {".py", ".md", ".json"}
|
ALLOWED_SUFFIXES: set[str] = {".py", ".md", ".json"}
|
||||||
@@ -197,6 +206,67 @@ def hash_tree(
|
|||||||
return digest, files
|
return digest, files
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Version date file format
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def version_date_utc(version_date: datetime) -> datetime:
|
||||||
|
"""Return a version date in UTC.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version_date: Version date; a naive datetime is taken as UTC, not converted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The version date in UTC.
|
||||||
|
"""
|
||||||
|
if version_date.tzinfo is None:
|
||||||
|
version_date = version_date.replace(tzinfo=timezone.utc)
|
||||||
|
return version_date.astimezone(timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
|
def version_date_digits(version_date: datetime) -> str:
|
||||||
|
"""Return the date digits a version date gives in a dev version.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version_date: Version date; a naive datetime is taken as UTC.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The UTC date in VERSION_DATE_DEV_FORMAT, e.g. ``"26111214"``.
|
||||||
|
"""
|
||||||
|
return version_date_utc(version_date).strftime(VERSION_DATE_DEV_FORMAT)
|
||||||
|
|
||||||
|
|
||||||
|
def format_version_date_file(version_date: datetime) -> str:
|
||||||
|
"""Return the content of VERSION_DATE_FILE for a version date.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version_date: Version date; a naive datetime is taken as UTC.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The file content: one line, e.g. ``VERSION_DATE = "2026-11-12T14:28:49Z"``.
|
||||||
|
"""
|
||||||
|
return f'VERSION_DATE = "{version_date_utc(version_date).strftime(VERSION_DATE_FORMAT)}"\n'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_version_date_file(content: str) -> Optional[datetime]:
|
||||||
|
"""Return the version date stored in the content of VERSION_DATE_FILE.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content: Content of a version date file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The stored date in UTC, or None if the content holds no valid date.
|
||||||
|
"""
|
||||||
|
match = VERSION_DATE_PATTERN.search(content)
|
||||||
|
if match is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return version_date_utc(datetime.fromisoformat(match.group("date")))
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def newest_commit_or_dirty_datetime(files: list[Path]) -> datetime:
|
def newest_commit_or_dirty_datetime(files: list[Path]) -> datetime:
|
||||||
"""Return the newest relevant datetime for the given files in UTC.
|
"""Return the newest relevant datetime for the given files in UTC.
|
||||||
|
|
||||||
@@ -249,16 +319,11 @@ def newest_commit_or_dirty_datetime(files: list[Path]) -> datetime:
|
|||||||
# Fallback to VERSION_DATE_FILE
|
# Fallback to VERSION_DATE_FILE
|
||||||
if VERSION_DATE_FILE.exists():
|
if VERSION_DATE_FILE.exists():
|
||||||
try:
|
try:
|
||||||
ns: dict[str, str] = {}
|
stored_date = parse_version_date_file(VERSION_DATE_FILE.read_text(encoding="utf-8"))
|
||||||
exec(VERSION_DATE_FILE.read_text(), {}, ns) # noqa: S102
|
except OSError:
|
||||||
date_str = ns.get("VERSION_DATE")
|
stored_date = None
|
||||||
if date_str:
|
if stored_date is not None:
|
||||||
dt = datetime.fromisoformat(date_str)
|
return stored_date
|
||||||
if dt.tzinfo is None:
|
|
||||||
dt = dt.replace(tzinfo=timezone.utc) # treat naive as UTC, don't convert
|
|
||||||
return dt.astimezone(timezone.utc)
|
|
||||||
except Exception: # noqa: S110
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise RuntimeError("This should not happen - No version date info available")
|
raise RuntimeError("This should not happen - No version date info available")
|
||||||
|
|
||||||
@@ -312,7 +377,7 @@ def _version_calculate() -> str:
|
|||||||
hash_digits = str(hash_value % (10**VERSION_DEV_HASH_PRECISION)).zfill(
|
hash_digits = str(hash_value % (10**VERSION_DEV_HASH_PRECISION)).zfill(
|
||||||
VERSION_DEV_HASH_PRECISION
|
VERSION_DEV_HASH_PRECISION
|
||||||
)
|
)
|
||||||
date_digits = version_date.strftime("%y%m%d%H") if version_date else "00000000"
|
date_digits = version_date_digits(version_date) if version_date else "00000000"
|
||||||
return f"{VERSION_BASE}{date_digits}{hash_digits}"
|
return f"{VERSION_BASE}{date_digits}{hash_digits}"
|
||||||
else:
|
else:
|
||||||
# Release version - use base as-is
|
# Release version - use base as-is
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
# tests/test_version.py
|
# tests/test_version.py
|
||||||
|
import importlib.util
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from types import ModuleType
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -347,6 +350,134 @@ def test_update_version_multiple_formats(tmp_path):
|
|||||||
assert f'"version": "{new_version}"' in json_file.read_text()
|
assert f'"version": "{new_version}"' in json_file.read_text()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def update_version() -> ModuleType:
|
||||||
|
"""Load scripts/update_version.py as a module."""
|
||||||
|
spec = importlib.util.spec_from_file_location("update_version", UPDATE_SCRIPT)
|
||||||
|
if spec is None or spec.loader is None:
|
||||||
|
raise ImportError(f"Cannot load {UPDATE_SCRIPT}")
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class TestWriteVersionDate:
|
||||||
|
"""Tests for writing VERSION_DATE with update_version.py."""
|
||||||
|
|
||||||
|
def test_writes_utc_z_format(self, update_version: ModuleType, tmp_path: Path) -> None:
|
||||||
|
"""A new file gets the date in UTC with a Z suffix, without microseconds."""
|
||||||
|
date_file = tmp_path / "_version_date.py"
|
||||||
|
version_date = to_datetime("2026-11-12T15:30:45.123456+01:00")
|
||||||
|
|
||||||
|
assert update_version.write_version_date(version_date, date_file) is True
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T14:30:45Z"\n'
|
||||||
|
|
||||||
|
def test_same_hour_is_not_written(self, update_version: ModuleType, tmp_path: Path) -> None:
|
||||||
|
"""A date in the same hour gives the same dev version, so the file stays as it is."""
|
||||||
|
date_file = write_file(tmp_path / "_version_date.py", 'VERSION_DATE = "2026-11-12T14:00:00Z"\n')
|
||||||
|
|
||||||
|
written = update_version.write_version_date(to_datetime("2026-11-12T14:59:59Z"), date_file)
|
||||||
|
|
||||||
|
assert written is False
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T14:00:00Z"\n'
|
||||||
|
|
||||||
|
def test_same_hour_in_other_format_is_written(
|
||||||
|
self, update_version: ModuleType, tmp_path: Path
|
||||||
|
) -> None:
|
||||||
|
"""A stored date in the same hour but not in the Z format is rewritten in the Z format."""
|
||||||
|
date_file = write_file(tmp_path / "_version_date.py", 'VERSION_DATE = "2026-11-12T14:00:00+00:00"\n')
|
||||||
|
|
||||||
|
written = update_version.write_version_date(to_datetime("2026-11-12T14:59:59Z"), date_file)
|
||||||
|
|
||||||
|
assert written is True
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T14:59:59Z"\n'
|
||||||
|
|
||||||
|
def test_other_hour_is_written(self, update_version: ModuleType, tmp_path: Path) -> None:
|
||||||
|
"""A date in another hour replaces the stored date."""
|
||||||
|
date_file = write_file(tmp_path / "_version_date.py", 'VERSION_DATE = "2026-02-24T16:58:00Z"\n')
|
||||||
|
|
||||||
|
written = update_version.write_version_date(to_datetime("2026-11-12T15:00:00Z"), date_file)
|
||||||
|
|
||||||
|
assert written is True
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T15:00:00Z"\n'
|
||||||
|
|
||||||
|
def test_naive_date_is_taken_as_utc(self, update_version: ModuleType, tmp_path: Path) -> None:
|
||||||
|
"""A date without time zone is written as UTC, not converted from local time."""
|
||||||
|
date_file = tmp_path / "_version_date.py"
|
||||||
|
|
||||||
|
# Stdlib datetime on purpose: to_datetime always adds a time zone.
|
||||||
|
written = update_version.write_version_date(datetime(2026, 11, 12, 15, 0, 0), date_file)
|
||||||
|
|
||||||
|
assert written is True
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T15:00:00Z"\n'
|
||||||
|
|
||||||
|
def test_invalid_stored_date_is_replaced(
|
||||||
|
self, update_version: ModuleType, tmp_path: Path
|
||||||
|
) -> None:
|
||||||
|
"""A file without a valid date is rewritten."""
|
||||||
|
date_file = write_file(tmp_path / "_version_date.py", 'VERSION_DATE = "not a date"\n')
|
||||||
|
|
||||||
|
written = update_version.write_version_date(to_datetime("2026-11-12T15:00:00Z"), date_file)
|
||||||
|
|
||||||
|
assert written is True
|
||||||
|
assert date_file.read_text(encoding="utf-8") == 'VERSION_DATE = "2026-11-12T15:00:00Z"\n'
|
||||||
|
|
||||||
|
def test_written_date_is_read_by_version_fallback(
|
||||||
|
self, update_version: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
"""The written file is understood by the fallback in newest_commit_or_dirty_datetime."""
|
||||||
|
import akkudoktoreos.core.version as version_module
|
||||||
|
|
||||||
|
date_file = tmp_path / "_version_date.py"
|
||||||
|
update_version.write_version_date(to_datetime("2026-11-12T15:30:00Z"), date_file)
|
||||||
|
|
||||||
|
monkeypatch.setattr(version_module, "IS_GITHUB_ACTIONS", True)
|
||||||
|
monkeypatch.setattr(version_module, "VERSION_DATE_FILE", date_file)
|
||||||
|
|
||||||
|
result = version_module.newest_commit_or_dirty_datetime([])
|
||||||
|
|
||||||
|
assert result == to_datetime("2026-11-12T15:30:00Z")
|
||||||
|
|
||||||
|
|
||||||
|
class TestUpdateVersionMain:
|
||||||
|
"""Tests for when update_version.py main() regenerates the version date file."""
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"is_version_file, via_symlink, old_version, expected_calls",
|
||||||
|
[
|
||||||
|
(True, False, "0.1.0", 1),
|
||||||
|
(True, False, "0.2.0", 0),
|
||||||
|
(False, False, "0.1.0", 0),
|
||||||
|
(True, True, "0.1.0", 1),
|
||||||
|
],
|
||||||
|
ids=["new-version", "same-version", "other-file", "symlinked-version-file"],
|
||||||
|
)
|
||||||
|
def test_date_updated_only_for_new_version_in_version_file(
|
||||||
|
self,
|
||||||
|
update_version: ModuleType,
|
||||||
|
tmp_path: Path,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
is_version_file: bool,
|
||||||
|
via_symlink: bool,
|
||||||
|
old_version: str,
|
||||||
|
expected_calls: int,
|
||||||
|
) -> None:
|
||||||
|
"""main() regenerates the version date only if a project version file gets a new version."""
|
||||||
|
config_file = write_file(tmp_path / "config.yaml", f'version: "{old_version}"\n')
|
||||||
|
version_file = tmp_path / "linked-config.yaml" if via_symlink else config_file
|
||||||
|
if via_symlink:
|
||||||
|
version_file.symlink_to(config_file)
|
||||||
|
calls: list[bool] = []
|
||||||
|
monkeypatch.setattr(
|
||||||
|
update_version, "DEFAULT_VERSION_FILES", [version_file] if is_version_file else []
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(update_version, "update_version_date_file", lambda: calls.append(True))
|
||||||
|
|
||||||
|
update_version.main("0.2.0", [str(config_file)])
|
||||||
|
|
||||||
|
assert len(calls) == expected_calls
|
||||||
|
|
||||||
|
|
||||||
# --- 3️⃣ Test bump_dev_version.py ---
|
# --- 3️⃣ Test bump_dev_version.py ---
|
||||||
def test_bump_dev_version_appends_dev(tmp_path):
|
def test_bump_dev_version_appends_dev(tmp_path):
|
||||||
version_file = write_file(tmp_path / "version.py", 'VERSION_BASE = "0.2.0"\n')
|
version_file = write_file(tmp_path / "version.py", 'VERSION_BASE = "0.2.0"\n')
|
||||||
|
|||||||
Reference in New Issue
Block a user