1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
import pytest
import tempfile
import shutil
import time
from pathlib import Path
from packaging_tools.sdk_update_version import main as update_version_main
@pytest.fixture
def temp_package():
temp_dir = tempfile.mkdtemp()
package_path = Path(temp_dir)
yield package_path
shutil.rmtree(temp_dir)
@pytest.fixture
def temp_arm_package():
temp_dir = tempfile.mkdtemp()
package_path = Path(temp_dir) / "azure-mgmt-test"
package_path.mkdir(parents=True, exist_ok=True)
yield package_path
shutil.rmtree(temp_dir)
def test_preview_to_stable_version_update(temp_package):
package_path = temp_package
# seed version file
version_file = package_path / "_version.py"
version_file.write_text('VERSION = "1.0.0b2"\n')
# seed changelog
changelog = package_path / "CHANGELOG.md"
changelog.write_text("## 1.0.0b2 (Unreleased)\n\n### Features\n\n- Something\n")
package_result = {
"version": "1.0.0b2",
"tagIsStable": True,
"changelog": {"content": "### Features"},
}
update_version_main(package_path, package_result=package_result)
# version file updated to stable
assert 'VERSION = "1.0.0"' in version_file.read_text()
# changelog first line updated
first_line = changelog.read_text().splitlines()[0]
assert first_line.startswith("## 1.0.0 (")
def test_initial_version_generated(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
package_result = {"version": "", "tagIsStable": False, "changelog": {"content": "### Features"}}
update_version_main(pkg, package_result=package_result)
assert 'VERSION = "1.0.0b1"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 1.0.0b1 (")
def test_bugfix_increments_patch_beta(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "1.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 1.0.0 (Unreleased)\n\n### Bugs Fixed\n- Fix\n")
package_result = {"version": "1.0.0", "tagIsStable": False, "changelog": {"content": "### Bugs Fixed"}}
update_version_main(pkg, package_result=package_result)
assert 'VERSION = "1.0.1b1"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 1.0.1b1 (")
def test_preview_increments_beta_counter(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "1.2.0b3"\n')
(pkg / "CHANGELOG.md").write_text("## 1.2.0b3 (Unreleased)\n\n### Features\n")
package_result = {"version": "1.2.0b3", "tagIsStable": False, "changelog": {"content": "### Features"}}
update_version_main(pkg, package_result=package_result)
assert 'VERSION = "1.2.0b4"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 1.2.0b4 (")
def test_breaking_change_increments_major_beta(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "1.4.2"\n')
(pkg / "CHANGELOG.md").write_text("## 1.4.2 (Unreleased)\n\n### Breaking Changes\n- Remove X\n")
package_result = {"version": "1.4.2", "tagIsStable": False, "changelog": {"content": "### Breaking Changes"}}
update_version_main(pkg, package_result=package_result)
assert 'VERSION = "2.0.0b1"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 2.0.0b1 (")
def test_feature_change_increments_minor_beta(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "1.4.2"\n')
(pkg / "CHANGELOG.md").write_text("## 1.4.2 (Unreleased)\n\n### Features\n- Add Y\n")
package_result = {"version": "1.4.2", "tagIsStable": False, "changelog": {"content": "### Features"}}
update_version_main(pkg, package_result=package_result)
assert 'VERSION = "1.5.0b1"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 1.5.0b1 (")
def test_initial_version_generated_without_package_result(temp_package):
# Ensure code path works when package_result is None (falsy)
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
# Call without a package_result dict to exercise else branch logic
update_version_main(pkg) # type: ignore[arg-type]
# Should compute first preview version
assert 'VERSION = "1.0.0b1"' in (pkg / "_version.py").read_text()
assert (pkg / "CHANGELOG.md").read_text().splitlines()[0].startswith("## 1.0.0b1 (")
def test_explicit_version_and_release_date_used(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
desired_version = "2.3.4b5"
desired_date = "2025-02-15"
update_version_main(pkg, version=desired_version, release_date=desired_date, release_type="beta")
assert f'VERSION = "{desired_version}"' in (pkg / "_version.py").read_text()
first_line = (pkg / "CHANGELOG.md").read_text().splitlines()[0]
assert first_line == f"## {desired_version} ({desired_date})" # exact match
def test_invalid_version_format_fallbacks_to_calculated(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
# Provide invalid version string; should be ignored and computed as 1.0.0b1
update_version_main(pkg, version="v1.0.0", release_type="beta")
assert 'VERSION = "1.0.0b1"' in (pkg / "_version.py").read_text()
first_line = (pkg / "CHANGELOG.md").read_text().splitlines()[0]
assert first_line.startswith("## 1.0.0b1 (")
def test_invalid_release_type_defaults_to_beta_flow(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
# release_type invalid; treated as beta; initial version should be computed preview
update_version_main(pkg, release_type="foo")
assert 'VERSION = "1.0.0b1"' in (pkg / "_version.py").read_text()
lines = (pkg / "CHANGELOG.md").read_text()
assert lines.splitlines()[0].startswith("## 1.0.0b1 (")
# Unreleased should be replaced with date
assert "## 0.0.0 (Unreleased)" not in "".join(lines)
def test_invalid_release_date_uses_current_date(temp_package):
pkg = temp_package
(pkg / "_version.py").write_text('VERSION = "0.0.0"\n')
(pkg / "CHANGELOG.md").write_text("## 0.0.0 (Unreleased)\n\n### Features\n")
today = time.strftime("%Y-%m-%d", time.localtime())
# Provide invalid release_date; should fall back to today's date
update_version_main(pkg, release_date="13-2025-11")
first_line = (pkg / "CHANGELOG.md").read_text().splitlines()[0]
assert first_line.startswith("## 1.0.0b1 ("), "Expected computed version line"
assert today in first_line, f"Expected fallback date {today} in changelog line"
def test_invalid_changelog_warning_log_for_arm_sdk(monkeypatch, temp_arm_package):
package_path = temp_arm_package
log_level = None
def mock_log_failed_message(message: str, enable_log_error: bool):
nonlocal log_level
log_level = enable_log_error
package_result = {
"changelog": {
"content": "",
}
}
monkeypatch.setattr("packaging_tools.sdk_update_version.log_failed_message", mock_log_failed_message)
update_version_main(package_path, package_result=package_result)
assert (
log_level is False
), "Expected warning log to be enabled for invalid changelog content in ARM SDK if in pipeline"
def test_invalid_changelog_error_log_for_arm_sdk(monkeypatch, temp_arm_package):
package_path = temp_arm_package
log_level = None
def mock_get_changelog_content(*args, **kwargs):
return ("", "")
def mock_log_failed_message(message: str, enable_log_error: bool):
nonlocal log_level
log_level = enable_log_error
monkeypatch.setattr("packaging_tools.sdk_update_version.get_changelog_content", mock_get_changelog_content)
monkeypatch.setattr("packaging_tools.sdk_update_version.log_failed_message", mock_log_failed_message)
update_version_main(package_path)
assert (
log_level is True
), "Expected error log to be enabled for invalid changelog content in ARM SDK if not in pipeline"
def test_valid_changelog_no_log_for_arm_sdk(monkeypatch, temp_arm_package):
package_path = temp_arm_package
log_level = None
def mock_log_failed_message(message: str, enable_log_error: bool):
nonlocal log_level
log_level = enable_log_error
package_result = {
"changelog": {
"content": "### Features Added\n- New feature",
}
}
monkeypatch.setattr("packaging_tools.sdk_update_version.log_failed_message", mock_log_failed_message)
update_version_main(package_path, package_result=package_result)
assert log_level is None, "Expected no error log for valid changelog content in ARM SDK"
def test_invalid_changelog_no_log_for_non_arm_sdk(monkeypatch, temp_package):
package_path = temp_package
log_level = None
def mock_log_failed_message(message: str, enable_log_error: bool):
nonlocal log_level
log_level = enable_log_error
package_result = {
"changelog": {
"content": "### Features Added\n- New feature",
}
}
monkeypatch.setattr("packaging_tools.sdk_update_version.log_failed_message", mock_log_failed_message)
update_version_main(package_path, package_result=package_result)
assert log_level is None, "Expected no error log for valid changelog content in non-ARM SDK"
def test_invalid_changelog_no_log_for_arm_sdk_with_version(monkeypatch, temp_arm_package):
package_path = temp_arm_package
log_level = None
def mock_get_changelog_content(*args, **kwargs):
return ("", "")
def mock_log_failed_message(message: str, enable_log_error: bool):
nonlocal log_level
log_level = enable_log_error
monkeypatch.setattr("packaging_tools.sdk_update_version.get_changelog_content", mock_get_changelog_content)
monkeypatch.setattr("packaging_tools.sdk_update_version.log_failed_message", mock_log_failed_message)
update_version_main(package_path, version="1.0.0")
assert (
log_level is None
), "Expected no error log for invalid changelog content in ARM SDK when version is explicitly provided"
|