Coverage for tests/test_prepare_release.py: 100%
99 statements
« prev ^ index » next coverage.py v7.6.1, created at 2026-10-15 15:22 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2026-10-15 15:22 +0000
1import importlib.util 1ab
2from datetime import date 1ab
3from pathlib import Path 1ab
5import pytest 1ab
6from typer.testing import CliRunner 1ab
8prepare_release_path = Path(__file__).parents[1] / "scripts" / "prepare_release.py" 1ab
9spec = importlib.util.spec_from_file_location("prepare_release", prepare_release_path) 1ab
10assert spec is not None 1ab
11assert spec.loader is not None 1ab
12prepare_release = importlib.util.module_from_spec(spec) 1ab
13spec.loader.exec_module(prepare_release) 1ab
15BumpType = prepare_release.BumpType 1ab
16app = prepare_release.app 1ab
17bump_version = prepare_release.bump_version 1ab
18get_release_notes_body = prepare_release.get_release_notes_body 1ab
19update_release_notes = prepare_release.update_release_notes 1ab
20update_version_file = prepare_release.update_version_file 1ab
22runner = CliRunner() 1ab
25@pytest.mark.parametrize( 1ab
26 ("current_version", "bump", "new_version"),
27 [
28 ("0.0.8", BumpType.major, "1.0.0"),
29 ("0.0.8", BumpType.minor, "0.1.0"),
30 ("0.0.8", BumpType.patch, "0.0.9"),
31 ],
32)
33def test_bump_version(current_version: str, bump: BumpType, new_version: str) -> None: 1ab
34 assert bump_version(current_version, bump) == new_version 1CD
37def test_update_version_file() -> None: 1ab
38 content = '__version__ = "0.0.8"\n' 1kl
40 new_content = update_version_file( 1kl
41 content, "0.0.9", Path("src/markdown_include_variants/_version.py")
42 )
44 assert new_content == '__version__ = "0.0.9"\n' 1kl
47def test_update_version_file_requires_newer_version() -> None: 1ab
48 content = '__version__ = "0.0.8"\n' 1mn
50 with pytest.raises(RuntimeError, match="must be greater"): 1mn
51 update_version_file( 1mn
52 content, "0.0.8", Path("src/markdown_include_variants/_version.py")
53 )
56def test_update_release_notes() -> None: 1ab
57 content = """# Release Notes 1op
59## Latest Changes
61### Fixes
63* Fix something.
65## 0.0.8 (2025-12-12)
67### Fixes
69* Previous fix.
70"""
72 new_content = update_release_notes( 1op
73 content, "0.0.9", date(2026, 5, 30), Path("release-notes.md")
74 )
76 assert ( 1op
77 new_content
78 == """# Release Notes
80## Latest Changes
82## 0.0.9 (2026-05-30)
84### Fixes
86* Fix something.
88## 0.0.8 (2025-12-12)
90### Fixes
92* Previous fix.
93"""
94 )
97def test_update_release_notes_rejects_existing_version() -> None: 1ab
98 content = """# Release Notes 1qr
100## Latest Changes
102## 0.0.9 (2026-05-30)
103"""
105 with pytest.raises(RuntimeError, match="already contain"): 1qr
106 update_release_notes( 1qr
107 content, "0.0.9", date(2026, 5, 30), Path("release-notes.md")
108 )
111def test_get_release_notes_body_with_dated_heading() -> None: 1ab
112 content = """# Release Notes 1st
114## Latest Changes
116## 0.0.9 (2026-05-30)
118### Fixes
120* Fix something.
122## 0.0.8 (2025-12-12)
124### Fixes
126* Previous fix.
127"""
129 body = get_release_notes_body(content, "0.0.9", Path("release-notes.md")) 1st
131 assert ( 1st
132 body
133 == """### Fixes
135* Fix something.
136"""
137 )
140def test_get_release_notes_body_with_plain_heading() -> None: 1ab
141 content = """# Release Notes 1uv
143## Latest Changes
145## 0.0.9
147### Fixes
149* Fix something.
150"""
152 body = get_release_notes_body(content, "0.0.9", Path("release-notes.md")) 1uv
154 assert body == "### Fixes\n\n* Fix something.\n" 1uv
157def test_get_release_notes_body_allows_non_version_h2_content() -> None: 1ab
158 content = """# Release Notes 1wx
160## Latest Changes
162## 0.0.9
164## Highlights
166* Fix something.
168## 0.0.8
170* Previous fix.
171"""
173 body = get_release_notes_body(content, "0.0.9", Path("release-notes.md")) 1wx
175 assert body == "## Highlights\n\n* Fix something.\n" 1wx
178def test_get_release_notes_body_requires_version_section() -> None: 1ab
179 content = "# Release Notes\n\n## Latest Changes\n" 1yz
181 with pytest.raises(RuntimeError, match="Could not find"): 1yz
182 get_release_notes_body(content, "0.0.9", Path("release-notes.md")) 1yz
185def test_get_release_notes_body_requires_non_empty_section() -> None: 1ab
186 content = """# Release Notes 1AB
188## Latest Changes
190## 0.0.9
192## 0.0.8
194* Previous fix.
195"""
197 with pytest.raises(RuntimeError, match="is empty"): 1AB
198 get_release_notes_body(content, "0.0.9", Path("release-notes.md")) 1AB
201def test_cli_updates_configured_files(tmp_path: Path) -> None: 1ab
202 version_file = tmp_path / "src" / "markdown_include_variants" / "_version.py" 1ef
203 version_file.parent.mkdir(parents=True) 1ef
204 version_file.write_text('__version__ = "0.0.8"\n') 1ef
205 release_notes_file = tmp_path / "release-notes.md" 1ef
206 release_notes_file.write_text( 1ef
207 """# Release Notes
209## Latest Changes
211### Fixes
213* Fix something.
214"""
215 )
217 result = runner.invoke( 1ef
218 app,
219 [
220 "prepare",
221 "patch",
222 "--version-file",
223 str(version_file),
224 "--release-notes-file",
225 str(release_notes_file),
226 "--date",
227 "2026-05-30",
228 ],
229 )
231 assert result.exit_code == 0, result.output 1ef
232 assert "Prepared release 0.0.9 (2026-05-30)" in result.output 1ef
233 assert version_file.read_text() == '__version__ = "0.0.9"\n' 1ef
234 assert "## 0.0.9 (2026-05-30)" in release_notes_file.read_text() 1ef
237def test_cli_accepts_env_vars(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: 1ab
238 version_file = tmp_path / "src" / "markdown_include_variants" / "_version.py" 1cd
239 version_file.parent.mkdir(parents=True) 1cd
240 version_file.write_text('__version__ = "0.0.8"\n') 1cd
241 release_notes_file = tmp_path / "release-notes.md" 1cd
242 release_notes_file.write_text("# Release Notes\n\n## Latest Changes\n") 1cd
243 monkeypatch.setenv("PREPARE_RELEASE_BUMP", "minor") 1cd
244 monkeypatch.setenv("PREPARE_RELEASE_VERSION_FILE", str(version_file)) 1cd
245 monkeypatch.setenv("PREPARE_RELEASE_RELEASE_NOTES_FILE", str(release_notes_file)) 1cd
246 monkeypatch.setenv("PREPARE_RELEASE_DATE", "2026-05-30") 1cd
248 result = runner.invoke(app, ["prepare"]) 1cd
250 assert result.exit_code == 0, result.output 1cd
251 assert "Prepared release 0.1.0 (2026-05-30)" in result.output 1cd
252 assert version_file.read_text() == '__version__ = "0.1.0"\n' 1cd
253 assert "## 0.1.0 (2026-05-30)" in release_notes_file.read_text() 1cd
256def test_cli_prints_current_version(tmp_path: Path) -> None: 1ab
257 version_file = tmp_path / "src" / "markdown_include_variants" / "_version.py" 1ij
258 version_file.parent.mkdir(parents=True) 1ij
259 version_file.write_text('__version__ = "0.0.8"\n') 1ij
261 result = runner.invoke( 1ij
262 app,
263 [
264 "current-version",
265 "--version-file",
266 str(version_file),
267 ],
268 )
270 assert result.exit_code == 0, result.output 1ij
271 assert result.output == "0.0.8\n" 1ij
274def test_cli_prints_release_notes(tmp_path: Path) -> None: 1ab
275 version_file = tmp_path / "src" / "markdown_include_variants" / "_version.py" 1gh
276 version_file.parent.mkdir(parents=True) 1gh
277 version_file.write_text('__version__ = "0.0.9"\n') 1gh
278 release_notes_file = tmp_path / "release-notes.md" 1gh
279 release_notes_file.write_text( 1gh
280 """# Release Notes
282## Latest Changes
284## 0.0.9 (2026-05-30)
286### Fixes
288* Fix something.
289"""
290 )
292 result = runner.invoke( 1gh
293 app,
294 [
295 "release-notes",
296 "--version-file",
297 str(version_file),
298 "--release-notes-file",
299 str(release_notes_file),
300 ],
301 )
303 assert result.exit_code == 0, result.output 1gh
304 assert result.output == "### Fixes\n\n* Fix something.\n" 1gh