chore: automate development version and release generation (#772)
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled

This change introduces a GitHub Action to automate release creation, including
proper tagging and automatic addition of a development marker to the version.

A hash is also appended to development versions to make their state easier to
distinguish.

Tests and release documentation have been updated to reflect the revised
release workflow. Several files now retrieve the current version dynamically.

The test --full-run option has been rename to --finalize to make
clear it is to do commit finalization testing.

Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
Bobby Noelte
2025-11-20 00:10:19 +01:00
committed by GitHub
parent bdbb0b060d
commit 976a2c8405
28 changed files with 762 additions and 448 deletions

119
tests/test_version.py Normal file
View File

@@ -0,0 +1,119 @@
# tests/test_version.py
import subprocess
import sys
from pathlib import Path
import pytest
import yaml
DIR_PROJECT_ROOT = Path(__file__).parent.parent
GET_VERSION_SCRIPT = DIR_PROJECT_ROOT / "scripts" / "get_version.py"
BUMP_DEV_SCRIPT = DIR_PROJECT_ROOT / "scripts" / "bump_dev_version.py"
UPDATE_SCRIPT = DIR_PROJECT_ROOT / "scripts" / "update_version.py"
# --- Helper to create test files ---
def write_file(path: Path, content: str):
path.write_text(content, encoding="utf-8")
return path
# --- 1⃣ Test get_version.py ---
def test_get_version_prints_non_empty():
result = subprocess.run(
[sys.executable, str(GET_VERSION_SCRIPT)],
capture_output=True,
text=True,
check=True
)
version = result.stdout.strip()
assert version, "get_version.py should print a non-empty version"
assert len(version.split(".")) >= 3, "Version should have at least MAJOR.MINOR.PATCH"
# --- 2⃣ Test update_version.py on multiple file types ---
def test_update_version_multiple_formats(tmp_path):
py_file = write_file(tmp_path / "version.py", '__version__ = "0.1.0"\n')
yaml_file = write_file(tmp_path / "config.yaml", 'version: "0.1.0"\n')
json_file = write_file(tmp_path / "package.json", '{"version": "0.1.0"}\n')
new_version = "0.2.0"
files = [py_file, yaml_file, json_file]
subprocess.run(
[sys.executable, str(UPDATE_SCRIPT), new_version] + [str(f.resolve()) for f in files],
check=True
)
# Verify updates
assert f'__version__ = "{new_version}"' in py_file.read_text()
assert yaml.safe_load(yaml_file.read_text())["version"] == new_version
assert f'"version": "{new_version}"' in json_file.read_text()
# --- 3⃣ Test bump_dev_version.py ---
def test_bump_dev_version_appends_dev(tmp_path):
version_file = write_file(tmp_path / "version.py", 'VERSION_BASE = "0.2.0"\n')
result = subprocess.run(
[sys.executable, str(BUMP_DEV_SCRIPT), str(version_file.resolve())],
capture_output=True,
text=True,
check=True
)
new_version = result.stdout.strip()
assert new_version == "0.2.0+dev"
content = version_file.read_text()
assert f'VERSION_BASE = "{new_version}"' in content
# --- 4⃣ Full workflow simulation with git ---
def test_workflow_git(tmp_path):
# Create git repo
subprocess.run(["git", "init"], cwd=tmp_path, check=True)
subprocess.run(["git", "config", "user.name", "test"], cwd=tmp_path, check=True)
subprocess.run(["git", "config", "user.email", "test@test.com"], cwd=tmp_path, check=True)
# Create files
version_file = write_file(tmp_path / "version.py", 'VERSION_BASE = "0.1.0"\n')
config_file = write_file(tmp_path / "config.yaml", 'version: "0.1.0"\n')
subprocess.run(["git", "add", "."], cwd=tmp_path, check=True)
subprocess.run(["git", "commit", "-m", "initial commit"], cwd=tmp_path, check=True)
# --- Step 1: Calculate version (mock) ---
new_version = "0.2.0"
# --- Step 2: Update files ---
subprocess.run(
[sys.executable, str(UPDATE_SCRIPT), new_version, str(config_file.resolve()), str(version_file.resolve())],
cwd=tmp_path,
check=True
)
# --- Step 3: Commit updated files if needed ---
subprocess.run(["git", "add", str(config_file.resolve()), str(version_file.resolve())], cwd=tmp_path, check=True)
diff_result = subprocess.run(["git", "diff", "--cached", "--quiet"], cwd=tmp_path)
assert diff_result.returncode == 1, "There should be staged changes to commit"
subprocess.run(["git", "commit", "-m", f"chore: bump version to {new_version}"], cwd=tmp_path, check=True)
# --- Step 4: Tag version ---
tag_name = f"v{new_version}"
subprocess.run(["git", "tag", "-a", tag_name, "-m", f"Release {new_version}"], cwd=tmp_path, check=True)
tags = subprocess.run(["git", "tag"], cwd=tmp_path, capture_output=True, text=True, check=True).stdout
assert tag_name in tags
# --- Step 5: Bump dev version ---
result = subprocess.run(
[sys.executable, str(BUMP_DEV_SCRIPT), str(version_file.resolve())],
cwd=tmp_path,
capture_output=True,
text=True,
check=True
)
dev_version = result.stdout.strip()
assert dev_version.endswith("+dev")
assert dev_version.count("+dev") == 1
content = version_file.read_text()
assert f'VERSION_BASE = "{dev_version}"' in content