-
-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathcheck_changelog_and_version.py
More file actions
executable file
·135 lines (106 loc) · 4.42 KB
/
check_changelog_and_version.py
File metadata and controls
executable file
·135 lines (106 loc) · 4.42 KB
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
#!/usr/bin/env python
"""Tests for flake8-async package metadata."""
from __future__ import annotations
import re
import sys
from pathlib import Path
from typing import TYPE_CHECKING, NamedTuple, TypeVar
from typing_extensions import Self
if TYPE_CHECKING:
from collections.abc import Iterable
ROOT_PATH = Path(__file__).parent.parent
CHANGELOG = ROOT_PATH / "docs" / "changelog.rst"
USAGE = ROOT_PATH / "docs" / "usage.rst"
INIT_FILE = ROOT_PATH / "flake8_async" / "__init__.py"
ALLOW_FUTURE = "--allow-future-in-changelog" in sys.argv
T = TypeVar("T", bound="Version")
class Version(NamedTuple):
year: int
month: int
patch: int
@classmethod
def from_string(cls, string: str) -> Self:
return cls(*map(int, string.split(".")))
def __str__(self) -> str:
return ".".join(map(str, self))
for line in INIT_FILE.read_text().splitlines():
if m := re.match(r'__version__ = "(\d*\.\d*\.\d*)"', line):
VERSION = Version.from_string(m.groups()[0])
break
else:
raise RuntimeError("No version detected.")
def get_releases() -> Iterable[Version]:
valid_pattern = re.compile(r"^(\d\d\.\d?\d\.\d?\d)$")
header_pattern = re.compile(r"^=+$")
last_line_was_date = False
last_line: str | None = None
with open(CHANGELOG, encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
version_match = valid_pattern.match(line)
if last_line_was_date:
assert header_pattern.match(line)
last_line_was_date = False
elif version_match:
yield Version.from_string(version_match.group(1))
last_line_was_date = True
# only allow `Future\n=====` when run in pre-commit
elif header_pattern.match(line):
assert ALLOW_FUTURE, "FUTURE header with no --allow-future-in-changelog. "
assert last_line is not None
assert last_line.lower().strip() == "future"
last_line = line
def test_last_release_against_changelog() -> None:
"""Ensure we have the latest version covered in 'changelog.rst'.
If changelog version is greater, the __init__ gets bumped in update_version().
"""
latest_release = next(iter(get_releases()))
assert latest_release >= VERSION, f"{latest_release}, {VERSION}"
def test_version_increments_are_correct() -> None:
versions = list(get_releases())
for prev, current in zip(versions[1:], versions):
assert prev < current # remember that `versions` is newest-first
msg = f"{current=} does not follow {prev=}"
# for CalVer, we either increment the patch version by one, or
# increment the time-based parts and set the patch version to one.
if current.patch == 1:
assert prev[:2] < current[:2], msg
else:
assert current == prev._replace(patch=prev.patch + 1), msg
def ensure_tagged() -> None:
from git.repo import Repo
last_version = next(iter(get_releases()))
repo = Repo(ROOT_PATH)
if str(last_version) not in iter(map(str, repo.tags)):
# create_tag is partially unknown in pyright, which kinda looks like
# https://github.com/gitpython-developers/GitPython/issues/1473
# which should be resolved?
repo.create_tag(str(last_version)) # type: ignore
repo.remotes.origin.push(str(last_version))
def update_version() -> None:
# If we've added a new version to the changelog, update __version__ to match
last_version = next(iter(get_releases()))
if last_version != VERSION:
INIT_FILE = ROOT_PATH / "flake8_async" / "__init__.py"
subs = (f'__version__ = "{VERSION}"', f'__version__ = "{last_version}"')
INIT_FILE.write_text(INIT_FILE.read_text().replace(*subs))
print("updated VERSION in __init__.py")
# Similarly, update the pre-commit config example in the README
current = USAGE.read_text()
wanted = re.sub(
pattern=r"^ rev: (\d+\.\d+\.\d+)$",
repl=f" rev: {last_version}",
string=current,
flags=re.MULTILINE,
)
if last_version != VERSION:
assert current != wanted, "version changed but regex didn't substitute"
if current != wanted:
USAGE.write_text(wanted)
print("updated rev in pre-commit example")
if __name__ == "__main__":
test_last_release_against_changelog()
test_version_increments_are_correct()
update_version()
if "--ensure-tag" in sys.argv:
ensure_tagged()