Skip to content

Commit e1f8fa6

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 64ec2c0 commit e1f8fa6

File tree

2 files changed

+83
-45
lines changed

2 files changed

+83
-45
lines changed

vcs-versioning/src/vcs_versioning/_version_schemes_towncrier.py

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This version scheme analyzes changelog fragments in the changelog.d/ directory
44
to determine the appropriate version bump:
55
- Major bump: if 'removal' fragments are present
6-
- Minor bump: if 'feature' or 'deprecation' fragments are present
6+
- Minor bump: if 'feature' or 'deprecation' fragments are present
77
- Patch bump: if only 'bugfix', 'doc', or 'misc' fragments are present
88
99
Falls back to guess-next-dev if no fragments are found.
@@ -12,10 +12,13 @@
1212
from __future__ import annotations
1313

1414
import logging
15-
import os
1615
from pathlib import Path
1716

18-
from ._version_schemes import ScmVersion, guess_next_dev_version, guess_next_simple_semver
17+
from ._version_schemes import (
18+
ScmVersion,
19+
guess_next_dev_version,
20+
guess_next_simple_semver,
21+
)
1922

2023
log = logging.getLogger(__name__)
2124

@@ -27,104 +30,106 @@
2730
ALL_FRAGMENT_TYPES = MAJOR_FRAGMENT_TYPES | MINOR_FRAGMENT_TYPES | PATCH_FRAGMENT_TYPES
2831

2932

30-
def _find_fragments(root: Path, changelog_dir: str = "changelog.d") -> dict[str, list[str]]:
33+
def _find_fragments(
34+
root: Path, changelog_dir: str = "changelog.d"
35+
) -> dict[str, list[str]]:
3136
"""Find and categorize changelog fragments.
32-
37+
3338
Args:
3439
root: Root directory to search from
3540
changelog_dir: Name of the changelog directory
36-
41+
3742
Returns:
3843
Dictionary mapping fragment types to lists of fragment filenames
3944
"""
4045
fragments: dict[str, list[str]] = {ftype: [] for ftype in ALL_FRAGMENT_TYPES}
41-
46+
4247
changelog_path = root / changelog_dir
4348
if not changelog_path.exists():
4449
log.debug("No changelog directory found at %s", changelog_path)
4550
return fragments
46-
51+
4752
for entry in changelog_path.iterdir():
4853
if not entry.is_file():
4954
continue
50-
55+
5156
# Skip template, README, and .gitkeep files
5257
if entry.name in ("template.md", "README.md", ".gitkeep"):
5358
continue
54-
59+
5560
# Fragment naming: {number}.{type}.md
5661
parts = entry.name.split(".")
5762
if len(parts) >= 2:
5863
fragment_type = parts[1]
5964
if fragment_type in ALL_FRAGMENT_TYPES:
6065
fragments[fragment_type].append(entry.name)
6166
log.debug("Found %s fragment: %s", fragment_type, entry.name)
62-
67+
6368
return fragments
6469

6570

6671
def _determine_bump_type(fragments: dict[str, list[str]]) -> str | None:
6772
"""Determine version bump type from fragments.
68-
73+
6974
Returns:
7075
'major', 'minor', 'patch', or None if no fragments found
7176
"""
7277
# Check for any fragments at all
7378
total_fragments = sum(len(files) for files in fragments.values())
7479
if total_fragments == 0:
7580
return None
76-
81+
7782
# Major bump if any removal fragments
7883
if any(fragments[ftype] for ftype in MAJOR_FRAGMENT_TYPES):
7984
return "major"
80-
85+
8186
# Minor bump if any feature/deprecation fragments
8287
if any(fragments[ftype] for ftype in MINOR_FRAGMENT_TYPES):
8388
return "minor"
84-
89+
8590
# Patch bump for other fragments
8691
if any(fragments[ftype] for ftype in PATCH_FRAGMENT_TYPES):
8792
return "patch"
88-
93+
8994
return None
9095

9196

9297
def version_from_fragments(version: ScmVersion) -> str:
9398
"""Version scheme that determines version from towncrier fragments.
94-
99+
95100
This is the main entry point registered as a setuptools_scm version scheme.
96-
101+
97102
Args:
98103
version: ScmVersion object from VCS
99-
104+
100105
Returns:
101106
Formatted version string
102107
"""
103108
# If we're exactly on a tag, return it
104109
if version.exact:
105110
return version.format_with("{tag}")
106-
111+
107112
# Try to find the root directory (where changelog.d/ should be)
108113
# The config object should have the root
109114
root = Path(version.config.absolute_root)
110-
115+
111116
log.debug("Analyzing fragments in %s", root)
112-
117+
113118
# Find and analyze fragments
114119
fragments = _find_fragments(root)
115120
bump_type = _determine_bump_type(fragments)
116-
121+
117122
if bump_type is None:
118123
log.debug("No fragments found, falling back to guess-next-dev")
119124
return guess_next_dev_version(version)
120-
125+
121126
log.info("Determined version bump type from fragments: %s", bump_type)
122-
127+
123128
# Determine the next version based on bump type
124129
if bump_type == "major":
125130
# Major bump: increment major version, reset minor and patch to 0
126131
from . import _modify_version
127-
132+
128133
def guess_next_major(v: ScmVersion) -> str:
129134
tag_version = _modify_version.strip_local(str(v.tag))
130135
parts = tag_version.split(".")
@@ -134,16 +139,21 @@ def guess_next_major(v: ScmVersion) -> str:
134139
# Fallback to bump_dev
135140
bumped = _modify_version._bump_dev(tag_version)
136141
return bumped if bumped is not None else f"{tag_version}.dev0"
137-
142+
138143
return version.format_next_version(guess_next_major)
139-
144+
140145
elif bump_type == "minor":
141146
# Minor bump: use simplified semver with MINOR retention
142147
from ._version_schemes import SEMVER_MINOR
143-
return version.format_next_version(guess_next_simple_semver, retain=SEMVER_MINOR)
144-
148+
149+
return version.format_next_version(
150+
guess_next_simple_semver, retain=SEMVER_MINOR
151+
)
152+
145153
else: # patch
146154
# Patch bump: use simplified semver with PATCH retention
147155
from ._version_schemes import SEMVER_PATCH
148-
return version.format_next_version(guess_next_simple_semver, retain=SEMVER_PATCH)
149156

157+
return version.format_next_version(
158+
guess_next_simple_semver, retain=SEMVER_PATCH
159+
)

vcs-versioning/testing_vcs/test_version_scheme_towncrier.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,9 @@ def test_determine_bump_type_patch_mixed() -> None:
243243
assert _determine_bump_type(fragments) == "patch"
244244

245245

246-
def test_version_from_fragments_exact(changelog_dir: Path, config: _config.Configuration) -> None:
246+
def test_version_from_fragments_exact(
247+
changelog_dir: Path, config: _config.Configuration
248+
) -> None:
247249
"""Test version scheme when exactly on a tag."""
248250
version = ScmVersion(
249251
tag=Version("1.2.3"),
@@ -256,7 +258,9 @@ def test_version_from_fragments_exact(changelog_dir: Path, config: _config.Confi
256258
assert result == "1.2.3"
257259

258260

259-
def test_version_from_fragments_no_fragments(changelog_dir: Path, config: _config.Configuration) -> None:
261+
def test_version_from_fragments_no_fragments(
262+
changelog_dir: Path, config: _config.Configuration
263+
) -> None:
260264
"""Test version scheme with no fragments falls back to guess-next-dev."""
261265
version = ScmVersion(
262266
tag=Version("1.2.3"),
@@ -270,7 +274,9 @@ def test_version_from_fragments_no_fragments(changelog_dir: Path, config: _confi
270274
assert result.startswith("1.2.4.dev5")
271275

272276

273-
def test_version_from_fragments_major_bump(changelog_dir: Path, config: _config.Configuration) -> None:
277+
def test_version_from_fragments_major_bump(
278+
changelog_dir: Path, config: _config.Configuration
279+
) -> None:
274280
"""Test version scheme with removal fragments (major bump)."""
275281
(changelog_dir / "1.removal.md").write_text("Remove old API")
276282

@@ -285,7 +291,9 @@ def test_version_from_fragments_major_bump(changelog_dir: Path, config: _config.
285291
assert result.startswith("2.0.0.dev5")
286292

287293

288-
def test_version_from_fragments_minor_bump(changelog_dir: Path, config: _config.Configuration) -> None:
294+
def test_version_from_fragments_minor_bump(
295+
changelog_dir: Path, config: _config.Configuration
296+
) -> None:
289297
"""Test version scheme with feature fragments (minor bump)."""
290298
(changelog_dir / "1.feature.md").write_text("Add new feature")
291299

@@ -300,7 +308,9 @@ def test_version_from_fragments_minor_bump(changelog_dir: Path, config: _config.
300308
assert result.startswith("1.3.0.dev5")
301309

302310

303-
def test_version_from_fragments_patch_bump(changelog_dir: Path, config: _config.Configuration) -> None:
311+
def test_version_from_fragments_patch_bump(
312+
changelog_dir: Path, config: _config.Configuration
313+
) -> None:
304314
"""Test version scheme with bugfix fragments (patch bump)."""
305315
(changelog_dir / "1.bugfix.md").write_text("Fix bug")
306316

@@ -315,7 +325,9 @@ def test_version_from_fragments_patch_bump(changelog_dir: Path, config: _config.
315325
assert result.startswith("1.2.4.dev5")
316326

317327

318-
def test_version_from_fragments_precedence(changelog_dir: Path, config: _config.Configuration) -> None:
328+
def test_version_from_fragments_precedence(
329+
changelog_dir: Path, config: _config.Configuration
330+
) -> None:
319331
"""Test that removal > feature > bugfix precedence works."""
320332
# Add all three types - removal should win
321333
(changelog_dir / "1.removal.md").write_text("Remove API")
@@ -334,7 +346,9 @@ def test_version_from_fragments_precedence(changelog_dir: Path, config: _config.
334346
assert result.startswith("2.0.0.dev5")
335347

336348

337-
def test_version_from_fragments_minor_over_patch(changelog_dir: Path, config: _config.Configuration) -> None:
349+
def test_version_from_fragments_minor_over_patch(
350+
changelog_dir: Path, config: _config.Configuration
351+
) -> None:
338352
"""Test that feature takes precedence over bugfix."""
339353
(changelog_dir / "1.feature.md").write_text("Add feature")
340354
(changelog_dir / "2.bugfix.md").write_text("Fix bug")
@@ -351,7 +365,9 @@ def test_version_from_fragments_minor_over_patch(changelog_dir: Path, config: _c
351365
assert result.startswith("1.3.0.dev5")
352366

353367

354-
def test_version_from_fragments_deprecation_is_minor(changelog_dir: Path, config: _config.Configuration) -> None:
368+
def test_version_from_fragments_deprecation_is_minor(
369+
changelog_dir: Path, config: _config.Configuration
370+
) -> None:
355371
"""Test that deprecation triggers a minor bump."""
356372
(changelog_dir / "1.deprecation.md").write_text("Deprecate method")
357373

@@ -366,7 +382,9 @@ def test_version_from_fragments_deprecation_is_minor(changelog_dir: Path, config
366382
assert result.startswith("1.3.0.dev5")
367383

368384

369-
def test_version_from_fragments_doc_is_patch(changelog_dir: Path, config: _config.Configuration) -> None:
385+
def test_version_from_fragments_doc_is_patch(
386+
changelog_dir: Path, config: _config.Configuration
387+
) -> None:
370388
"""Test that doc changes trigger a patch bump."""
371389
(changelog_dir / "1.doc.md").write_text("Update docs")
372390

@@ -381,7 +399,9 @@ def test_version_from_fragments_doc_is_patch(changelog_dir: Path, config: _confi
381399
assert result.startswith("1.2.4.dev5")
382400

383401

384-
def test_version_from_fragments_misc_is_patch(changelog_dir: Path, config: _config.Configuration) -> None:
402+
def test_version_from_fragments_misc_is_patch(
403+
changelog_dir: Path, config: _config.Configuration
404+
) -> None:
385405
"""Test that misc changes trigger a patch bump."""
386406
(changelog_dir / "1.misc.md").write_text("Refactor")
387407

@@ -396,7 +416,9 @@ def test_version_from_fragments_misc_is_patch(changelog_dir: Path, config: _conf
396416
assert result.startswith("1.2.4.dev5")
397417

398418

399-
def test_version_from_fragments_major_from_0_x(changelog_dir: Path, config: _config.Configuration) -> None:
419+
def test_version_from_fragments_major_from_0_x(
420+
changelog_dir: Path, config: _config.Configuration
421+
) -> None:
400422
"""Test major bump from 0.x version."""
401423
(changelog_dir / "1.removal.md").write_text("Remove API")
402424

@@ -411,7 +433,9 @@ def test_version_from_fragments_major_from_0_x(changelog_dir: Path, config: _con
411433
assert result.startswith("1.0.0.dev5")
412434

413435

414-
def test_version_from_fragments_minor_from_0_x(changelog_dir: Path, config: _config.Configuration) -> None:
436+
def test_version_from_fragments_minor_from_0_x(
437+
changelog_dir: Path, config: _config.Configuration
438+
) -> None:
415439
"""Test minor bump from 0.x version."""
416440
(changelog_dir / "1.feature.md").write_text("Add feature")
417441

@@ -426,7 +450,9 @@ def test_version_from_fragments_minor_from_0_x(changelog_dir: Path, config: _con
426450
assert result.startswith("0.6.0.dev5")
427451

428452

429-
def test_version_from_fragments_missing_changelog_dir(config: _config.Configuration) -> None:
453+
def test_version_from_fragments_missing_changelog_dir(
454+
config: _config.Configuration,
455+
) -> None:
430456
"""Test version scheme when changelog.d directory doesn't exist."""
431457
version = ScmVersion(
432458
tag=Version("1.2.3"),
@@ -440,7 +466,9 @@ def test_version_from_fragments_missing_changelog_dir(config: _config.Configurat
440466
assert result.startswith("1.2.4.dev5")
441467

442468

443-
def test_version_from_fragments_dirty(changelog_dir: Path, config: _config.Configuration) -> None:
469+
def test_version_from_fragments_dirty(
470+
changelog_dir: Path, config: _config.Configuration
471+
) -> None:
444472
"""Test version scheme with dirty working directory."""
445473
(changelog_dir / "1.feature.md").write_text("Add feature")
446474

0 commit comments

Comments
 (0)