Coverage for tests/test_prepare_release.py: 100%

88 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-10-19 03:36 +0000

1from __future__ import annotations 1abcdefghi

2 

3from datetime import date 1abcdefghi

4from pathlib import Path 1abcdefghi

5 

6import pytest 1abcdefghi

7from typer.testing import CliRunner 1abcdefghi

8 

9from scripts.prepare_release import ( 1abcdefghi

10 BumpType, 

11 app, 

12 bump_version, 

13 get_release_notes_body, 

14 update_release_notes, 

15 update_version_file, 

16) 

17 

18runner = CliRunner() 1abcdefghi

19 

20 

21@pytest.mark.parametrize( 1abcdefghi

22 ("current_version", "bump", "new_version"), 

23 [ 

24 ("0.0.4", "major", "1.0.0"), 

25 ("0.0.4", "minor", "0.1.0"), 

26 ("0.0.4", "patch", "0.0.5"), 

27 ], 

28) 

29def test_bump_version(current_version: str, bump: BumpType, new_version: str) -> None: 1abcdefghi

30 assert bump_version(current_version, bump) == new_version 2LbMbNbObPbQbRbSbTb

31 

32 

33def test_update_version_file() -> None: 1abcdefghi

34 content = 'from .main import Doc as Doc\n\n__version__ = "0.0.4"\n' 1TUVWXYZ01

35 

36 new_content = update_version_file( 1TUVWXYZ01

37 content, "0.0.5", Path("src/annotated_doc/__init__.py") 

38 ) 

39 

40 assert new_content == 'from .main import Doc as Doc\n\n__version__ = "0.0.5"\n' 1TUVWXYZ01

41 

42 

43def test_update_version_file_requires_newer_version() -> None: 1abcdefghi

44 content = '__version__ = "0.0.4"\n' 123456789!

45 

46 with pytest.raises(RuntimeError, match="must be greater"): 123456789!

47 update_version_file(content, "0.0.4", Path("src/annotated_doc/__init__.py")) 123456789!

48 

49 

50def test_update_release_notes() -> None: 1abcdefghi

51 content = """# Release Notes 1#$%'()*+,

52 

53## Latest Changes 

54 

55### Fixes 

56 

57* Fix something. 

58 

59## 0.0.4 (2025-11-10) 

60 

61### Fixes 

62 

63* Previous fix. 

64""" 

65 

66 new_content = update_release_notes( 1#$%'()*+,

67 content, "0.0.5", date(2026, 5, 30), Path("release-notes.md") 

68 ) 

69 

70 assert ( 1#$%'()*+,

71 new_content 

72 == """# Release Notes 

73 

74## Latest Changes 

75 

76## 0.0.5 (2026-05-30) 

77 

78### Fixes 

79 

80* Fix something. 

81 

82## 0.0.4 (2025-11-10) 

83 

84### Fixes 

85 

86* Previous fix. 

87""" 

88 ) 

89 

90 

91def test_update_release_notes_rejects_existing_version() -> None: 1abcdefghi

92 content = """# Release Notes 1-./:;=?@[

93 

94## Latest Changes 

95 

96## 0.0.5 (2026-05-30) 

97""" 

98 

99 with pytest.raises(RuntimeError, match="already contain"): 1-./:;=?@[

100 update_release_notes( 1-./:;=?@[

101 content, "0.0.5", date(2026, 5, 30), Path("release-notes.md") 

102 ) 

103 

104 

105def test_get_release_notes_body_with_dated_heading() -> None: 1abcdefghi

106 content = """# Release Notes 2] ^ _ ` { | } ~ ab

107 

108## Latest Changes 

109 

110## 0.0.5 (2026-05-30) 

111 

112### Fixes 

113 

114* Fix something. 

115 

116## 0.0.4 (2025-11-10) 

117 

118### Fixes 

119 

120* Previous fix. 

121""" 

122 

123 body = get_release_notes_body(content, "0.0.5", Path("release-notes.md")) 2] ^ _ ` { | } ~ ab

124 

125 assert ( 2] ^ _ ` { | } ~ ab

126 body 

127 == """### Fixes 

128 

129* Fix something. 

130""" 

131 ) 

132 

133 

134def test_get_release_notes_body_with_plain_heading() -> None: 1abcdefghi

135 content = """# Release Notes 2bbcbdbebfbgbhbibjb

136 

137## Latest Changes 

138 

139## 0.0.5 

140 

141### Fixes 

142 

143* Fix something. 

144""" 

145 

146 body = get_release_notes_body(content, "0.0.5", Path("release-notes.md")) 2bbcbdbebfbgbhbibjb

147 

148 assert body == "### Fixes\n\n* Fix something.\n" 2bbcbdbebfbgbhbibjb

149 

150 

151def test_get_release_notes_body_allows_non_version_h2_content() -> None: 1abcdefghi

152 content = """# Release Notes 2kblbmbnbobpbqbrbsb

153 

154## Latest Changes 

155 

156## 0.0.5 

157 

158## Highlights 

159 

160* Fix something. 

161 

162## 0.0.4 

163 

164* Previous fix. 

165""" 

166 

167 body = get_release_notes_body(content, "0.0.5", Path("release-notes.md")) 2kblbmbnbobpbqbrbsb

168 

169 assert body == "## Highlights\n\n* Fix something.\n" 2kblbmbnbobpbqbrbsb

170 

171 

172def test_get_release_notes_body_requires_version_section() -> None: 1abcdefghi

173 content = "# Release Notes\n\n## Latest Changes\n" 2tbubvbwbxbybzbAbBb

174 

175 with pytest.raises(RuntimeError, match="Could not find"): 2tbubvbwbxbybzbAbBb

176 get_release_notes_body(content, "0.0.5", Path("release-notes.md")) 2tbubvbwbxbybzbAbBb

177 

178 

179def test_get_release_notes_body_requires_non_empty_section() -> None: 1abcdefghi

180 content = """# Release Notes 2CbDbEbFbGbHbIbJbKb

181 

182## Latest Changes 

183 

184## 0.0.5 

185 

186## 0.0.4 

187 

188* Previous fix. 

189""" 

190 

191 with pytest.raises(RuntimeError, match="is empty"): 2CbDbEbFbGbHbIbJbKb

192 get_release_notes_body(content, "0.0.5", Path("release-notes.md")) 2CbDbEbFbGbHbIbJbKb

193 

194 

195def test_cli_updates_configured_files(tmp_path: Path) -> None: 1abcdefghi

196 version_file = tmp_path / "src" / "annotated_doc" / "__init__.py" 1stuvwxyzA

197 version_file.parent.mkdir(parents=True) 1stuvwxyzA

198 version_file.write_text('from .main import Doc as Doc\n\n__version__ = "0.0.4"\n') 1stuvwxyzA

199 release_notes_file = tmp_path / "release-notes.md" 1stuvwxyzA

200 release_notes_file.write_text( 1stuvwxyzA

201 """# Release Notes 

202 

203## Latest Changes 

204 

205### Fixes 

206 

207* Fix something. 

208""" 

209 ) 

210 

211 result = runner.invoke( 1stuvwxyzA

212 app, 

213 [ 

214 "prepare", 

215 "patch", 

216 "--version-file", 

217 str(version_file), 

218 "--release-notes-file", 

219 str(release_notes_file), 

220 "--date", 

221 "2026-05-30", 

222 ], 

223 ) 

224 

225 assert result.exit_code == 0, result.output 1stuvwxyzA

226 assert "Prepared release 0.0.5 (2026-05-30)" in result.output 1stuvwxyzA

227 assert version_file.read_text() == ( 1stuvwxyzA

228 'from .main import Doc as Doc\n\n__version__ = "0.0.5"\n' 

229 ) 

230 assert "## 0.0.5 (2026-05-30)" in release_notes_file.read_text() 1stuvwxyzA

231 

232 

233def test_cli_accepts_env_vars(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: 1abcdefghi

234 version_file = tmp_path / "src" / "annotated_doc" / "__init__.py" 1jklmnopqr

235 version_file.parent.mkdir(parents=True) 1jklmnopqr

236 version_file.write_text('__version__ = "0.0.4"\n') 1jklmnopqr

237 release_notes_file = tmp_path / "release-notes.md" 1jklmnopqr

238 release_notes_file.write_text("# Release Notes\n\n## Latest Changes\n") 1jklmnopqr

239 monkeypatch.setenv("PREPARE_RELEASE_BUMP", "minor") 1jklmnopqr

240 monkeypatch.setenv("PREPARE_RELEASE_VERSION_FILE", str(version_file)) 1jklmnopqr

241 monkeypatch.setenv("PREPARE_RELEASE_RELEASE_NOTES_FILE", str(release_notes_file)) 1jklmnopqr

242 monkeypatch.setenv("PREPARE_RELEASE_DATE", "2026-05-30") 1jklmnopqr

243 

244 result = runner.invoke(app, ["prepare"]) 1jklmnopqr

245 

246 assert result.exit_code == 0, result.output 1jklmnopqr

247 assert "Prepared release 0.1.0 (2026-05-30)" in result.output 1jklmnopqr

248 assert version_file.read_text() == '__version__ = "0.1.0"\n' 1jklmnopqr

249 assert "## 0.1.0 (2026-05-30)" in release_notes_file.read_text() 1jklmnopqr

250 

251 

252def test_cli_prints_current_version(tmp_path: Path) -> None: 1abcdefghi

253 version_file = tmp_path / "src" / "annotated_doc" / "__init__.py" 1KLMNOPQRS

254 version_file.parent.mkdir(parents=True) 1KLMNOPQRS

255 version_file.write_text('__version__ = "0.0.4"\n') 1KLMNOPQRS

256 

257 result = runner.invoke( 1KLMNOPQRS

258 app, 

259 [ 

260 "current-version", 

261 "--version-file", 

262 str(version_file), 

263 ], 

264 ) 

265 

266 assert result.exit_code == 0, result.output 1KLMNOPQRS

267 assert result.output == "0.0.4\n" 1KLMNOPQRS

268 

269 

270def test_cli_prints_release_notes(tmp_path: Path) -> None: 1abcdefghi

271 version_file = tmp_path / "src" / "annotated_doc" / "__init__.py" 1BCDEFGHIJ

272 version_file.parent.mkdir(parents=True) 1BCDEFGHIJ

273 version_file.write_text('__version__ = "0.0.5"\n') 1BCDEFGHIJ

274 release_notes_file = tmp_path / "release-notes.md" 1BCDEFGHIJ

275 release_notes_file.write_text( 1BCDEFGHIJ

276 """# Release Notes 

277 

278## Latest Changes 

279 

280## 0.0.5 (2026-05-30) 

281 

282### Fixes 

283 

284* Fix something. 

285""" 

286 ) 

287 

288 result = runner.invoke( 1BCDEFGHIJ

289 app, 

290 [ 

291 "release-notes", 

292 "--version-file", 

293 str(version_file), 

294 "--release-notes-file", 

295 str(release_notes_file), 

296 ], 

297 ) 

298 

299 assert result.exit_code == 0, result.output 1BCDEFGHIJ

300 assert result.output == "### Fixes\n\n* Fix something.\n" 1BCDEFGHIJ