-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathupdatefiles.py
121 lines (96 loc) · 4.4 KB
/
updatefiles.py
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
"""Update files with a new version number."""
import argparse
import logging
import re
from pathlib import Path
from .logging import setup_logging, NOTICE
VERSION_REGEX = re.compile(
r"""
^ # Start of line, followed by any whitespace
(?P<prefix> # Open `prefix` capture group
\s* # Any whitespace
(?P<vquote>['"]?) # `'`, `"`, or nothing (saved as `vquote` group)
(?:__)? # Optional literal `__`
version # Literal `version`
(?:__)? # Optional literal `__`
(?P=vquote) # `'`, `"`, or nothing (back-reference to `vquote`)
(?:\s*:\s*str\b)? # Optional literal `: str` (for python typing)
(?:
\s* # Any whitespace
[=:]? # `=`, `:`, or nothing
\s* # Any whitespace
)
(?P<quote>['"]?) # `'`, `"`, or nothing (saved as `quote` group)
) # Close `prefix` capture group
(?P<version>.*?) # Non-greedy match of all characters (the version)
(?P<suffix> # Open `suffix` capture group
(?P=quote) # `'`, `"`, or nothing (back-reference to `quote`)
,? # Optional comma
\s* # Any whitespace
(?:\#.*)? # Optional `#` followed by anyanything
) # Close `suffix` capture group
$ # End of line
""",
flags=re.VERBOSE | re.IGNORECASE | re.MULTILINE,
)
def update_file(version: str, version_file: Path):
"""Update a single file with the new version number."""
original_text = version_file.read_text(encoding="utf-8")
updated_text, update_count = VERSION_REGEX.subn(
r"\g<prefix>" + version + r"\g<suffix>", original_text
)
if update_count == 0:
raise ValueError(f"Version regex not found in {version_file}!")
if update_count > 1:
# Find the different lines
original_lines = original_text.splitlines()
updated_lines = updated_text.splitlines()
changed_pairs = [
(orig, updated)
for (orig, updated) in zip(original_lines, updated_lines)
if orig != updated
]
assert len(changed_pairs) == update_count
logging.getLogger(__name__).error(
"Multiple versions updated in %s", version_file
)
for orig, updated in changed_pairs:
logging.getLogger(__name__).debug("`%s` -> `%s`", orig, updated)
raise ValueError(f"Multiple versions changed in {version_file}")
logging.getLogger(__name__).log(NOTICE, "Version updated in %s", version_file)
version_file.write_text(updated_text, encoding="utf-8")
def update_files(repo_root: Path, version: str, files_str: str):
"""Update each of the files with the new version number."""
version_files = [repo_root / item for item in files_str.split(",")]
for version_file in version_files:
full_version_file = version_file.resolve()
logging.getLogger(__name__).info("Trying to update %s", full_version_file)
# Make sure it is a tracked file
if not full_version_file.is_relative_to(repo_root):
raise ValueError(f"Version file {version_file} is not within the git repo")
# Make sure it's not under the .git folder (probably already covered by
# the above) or the .github folder
if {".git", ".github"} & set(full_version_file.parts):
raise ValueError(
f"Version file {version_file} is within a protected folder"
)
# Finally, make sure it is actually a file
if not full_version_file.is_file():
raise ValueError(f"Version file {version_file} does not exist")
update_file(version, version_file)
def entrypoint():
"""Main entrypoint."""
parser = argparse.ArgumentParser()
parser.add_argument("repo_root", type=Path)
parser.add_argument("version", type=str)
parser.add_argument("files", type=str)
args = parser.parse_args()
setup_logging()
if not args.files:
logging.getLogger(__name__).debug("No version files need to be updated")
else:
try:
update_files(args.repo_root.resolve(), args.version, args.files)
except Exception:
logging.getLogger(__name__).exception("Error updating files")
raise