16 from collections.abc
import Callable, Iterable
17 from difflib
import unified_diff
18 from subprocess
import run
19 from typing
import Union
23 GITLAB_TOKEN = os.environ.get(
"GITLAB_TOKEN")
28 Convert a version in format "vXrY" or "X.Y" in the pair ("X.Y", "vXrY").
30 >>> normalize_version("v37r0")
32 >>> normalize_version("37.0.1")
36 numbers = re.findall(
r"\d+", version)
39 "".join(
"{}{}".
format(*pair)
for pair
in zip(
"vrpt", numbers)),
45 Helper to carry the allowed fields for formatting replacement strings.
47 >>> f = Fields("v37r1", datetime.date(2023, 9, 25))
49 Fields('37.1', datetime.date(2023, 9, 25))
51 {'cmake_version': '37.1', 'tag_version': 'v37r1', 'date': datetime.date(2023, 9, 25)}
54 def __init__(self, version: str, date: datetime.date):
57 cmake_version=cmake_version,
58 tag_version=tag_version,
64 f
"Fields({repr(self._data['cmake_version'])}, {repr(self._data['date'])})"
74 Helper to replace lines with patterns or applying functions.
76 >>> r = ReplacementRule(r"^version: ", "version: {cmake_version}")
77 >>> f = Fields("v1r1", datetime.date(2023, 9, 25))
78 >>> r("nothing to change\\n", f)
79 'nothing to change\\n'
80 >>> r("version: 1.0\\n", f)
86 pattern: Union[str, re.Pattern],
87 replace: Union[str, Callable[[str, Fields], str]],
89 self.
pattern = re.compile(pattern)
90 if isinstance(replace, str):
91 replace = f
"{replace.rstrip()}\n"
92 self.
replace =
lambda _line, fields: replace.format(**fields.data)
96 def __call__(self, line: str, fields: Fields) -> str:
98 return self.
replace(line, fields)
104 self, filename: str, rules: Iterable[Union[ReplacementRule, tuple[str, str]]]
108 r
if isinstance(r, ReplacementRule)
else ReplacementRule(*r)
for r
in rules
112 for rule
in self.
rules:
113 line = rule(line, fields)
116 def __call__(self, fields: Fields) -> tuple[str, list[str], list[str]]:
124 Special updater to fill draft changelog entry.
127 [
"git",
"describe",
"--tags",
"--abbrev=0"], capture_output=
True, text=
True
132 [
"git",
"log",
"--first-parent",
"--format=%s<=>%b|", f
"{latest_tag}.."],
137 changes_txt =
" ".join(changes_txt.strip().rstrip(
"|").splitlines())
140 changes_txt.replace(
"Closes #",
"gaudi/Gaudi#")
141 .replace(
"See merge request ",
"")
146 f
"- {msg.strip()} ({', '.join(refs.split())})\n"
148 else f
"- {msg.strip()}\n"
149 for change
in changes
150 for msg, refs
in ([change.split(
"<=>", 1)]
if "<=>" in change
else [])
153 contributors = sorted(
157 [
"git",
"log",
"--format=%an", f
"{latest_tag}...HEAD"],
160 ).stdout.splitlines()
164 filename =
"CHANGELOG.md"
165 with open(filename)
as f:
167 for idx, line
in enumerate(old):
168 if line.startswith(
"## ["):
174 "## [{tag_version}](https://gitlab.cern.ch/gaudi/Gaudi/-/releases/{tag_version}) - {date}\n".
format(
177 "\nA special thanks to all the people that contributed to this release:\n",
178 ",\n".join(contributors),
187 data.extend([
"\n",
"\n"])
188 data.extend(old[idx:])
190 return filename, old, data
195 from requests
import get
198 "https://gitlab.cern.ch/api/v4/users",
199 headers={
"PRIVATE-TOKEN": GITLAB_TOKEN},
200 params={
"search": name},
203 return f
'@{users[0]["username"]}'
208 @click.argument(
"version", type=str)
211 type=click.DateTime((
"%Y-%m-%d",)),
213 default=datetime.datetime.now(),
220 help=
"only show what would change, but do not modify the files",
224 Helper to easily update the project version number in all needed files.
226 fields =
Fields(version, date.date())
228 "Bumping version to {cmake_version} (tag: {tag_version})".
format(**fields.data)
234 [(
r"^project\(Gaudi VERSION",
"project(Gaudi VERSION {cmake_version}")],
239 (
r"^version: ",
"version: {tag_version}"),
240 (
r"^date-released: ",
"date-released: '{date}'"),
244 "docs/source/conf.py",
246 (
r"^version = ",
'version = "{cmake_version}"'),
247 (
r"^release = ",
'release = "{tag_version}"'),
252 filename, old, new = updater(fields)
256 sys.stdout.writelines(
260 fromfile=f
"a/{filename}",
261 tofile=f
"b/{filename}",
265 click.echo(f
"updated {filename}")
266 with open(filename,
"w")
as f:
270 if __name__ ==
"__main__":