Skip to content

Commit 709a89a

Browse files
author
Chris Elion
authored
script to check for old release links and references (#4153)
1 parent 5ab907c commit 709a89a

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,9 @@ repos:
116116
language: script
117117
entry: utils/validate_inits.py
118118
types: [python]
119+
- id: validate-release-links-py
120+
name: validate release links
121+
language: script
122+
entry: utils/validate_release_links.py
123+
119124

utils/validate_release_links.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#!/usr/bin/env python3
2+
3+
import ast
4+
import sys
5+
import os
6+
import re
7+
import subprocess
8+
from typing import List, Optional, Pattern
9+
10+
RELEASE_PATTERN = re.compile(r"release_[0-9]+(_docs)*")
11+
TRAINER_INIT_FILE = "ml-agents/mlagents/trainers/__init__.py"
12+
13+
# Filename -> regex list to allow specific lines.
14+
# To allow everything in the file, use None for the value
15+
ALLOW_LIST = {
16+
# Previous release table
17+
"README.md": re.compile(r"\*\*Release [0-9]+\*\*"),
18+
"docs/Versioning.md": None,
19+
"com.unity.ml-agents/CHANGELOG.md": None,
20+
"utils/make_readme_table.py": None,
21+
"utils/validate_doc_versions.py": None,
22+
}
23+
24+
25+
def test_pattern():
26+
# Just some sanity check that the regex works as expected.
27+
assert RELEASE_PATTERN.search(
28+
"https://github.com/Unity-Technologies/ml-agents/blob/release_3_docs/Food.md"
29+
)
30+
assert RELEASE_PATTERN.search(
31+
"https://github.com/Unity-Technologies/ml-agents/blob/release_3/Foo.md"
32+
)
33+
assert RELEASE_PATTERN.search(
34+
"git clone --branch release_3 https://github.com/Unity-Technologies/ml-agents.git"
35+
)
36+
assert RELEASE_PATTERN.search(
37+
"https://github.com/Unity-Technologies/ml-agents/blob/release_123_docs/Foo.md"
38+
)
39+
assert RELEASE_PATTERN.search(
40+
"https://github.com/Unity-Technologies/ml-agents/blob/release_123/Foo.md"
41+
)
42+
assert not RELEASE_PATTERN.search(
43+
"https://github.com/Unity-Technologies/ml-agents/blob/latest_release/docs/Foo.md"
44+
)
45+
print("tests OK!")
46+
47+
48+
def git_ls_files() -> List[str]:
49+
"""
50+
Run "git ls-files" and return a list with one entry per line.
51+
This returns the list of all files tracked by git.
52+
"""
53+
return subprocess.check_output(["git", "ls-files"], universal_newlines=True).split(
54+
"\n"
55+
)
56+
57+
58+
def get_release_tag() -> Optional[str]:
59+
"""
60+
Returns the release tag for the mlagents python package.
61+
This will be None on the master branch.
62+
:return:
63+
"""
64+
with open(TRAINER_INIT_FILE) as f:
65+
for line in f:
66+
if "__release_tag__" in line:
67+
lhs, equals_string, rhs = line.strip().partition(" = ")
68+
# Evaluate the right hand side of the expression
69+
return ast.literal_eval(rhs)
70+
# If we couldn't find the release tag, raise an exception
71+
# (since we can't return None here)
72+
raise RuntimeError("Can't determine release tag")
73+
74+
75+
def check_file(filename: str, global_allow_pattern: Pattern) -> List[str]:
76+
"""
77+
Validate a single file and return any offending lines.
78+
"""
79+
bad_lines = []
80+
with open(filename, "r") as f:
81+
for line in f:
82+
if not RELEASE_PATTERN.search(line):
83+
continue
84+
85+
if global_allow_pattern.search(line):
86+
continue
87+
88+
if filename in ALLOW_LIST:
89+
if ALLOW_LIST[filename] is None or ALLOW_LIST[filename].search(line):
90+
continue
91+
92+
bad_lines.append(f"{filename}: {line.strip()}")
93+
return bad_lines
94+
95+
96+
def check_all_files(allow_pattern: Pattern) -> List[str]:
97+
"""
98+
Validate all files tracked by git.
99+
:param allow_pattern:
100+
"""
101+
bad_lines = []
102+
file_types = {".py", ".md", ".cs"}
103+
for file_name in git_ls_files():
104+
if "localized" in file_name or os.path.splitext(file_name)[1] not in file_types:
105+
continue
106+
bad_lines += check_file(file_name, allow_pattern)
107+
return bad_lines
108+
109+
110+
def main():
111+
release_tag = get_release_tag()
112+
if not release_tag:
113+
print("Release tag is None, exiting")
114+
sys.exit(0)
115+
116+
print(f"Release tag: {release_tag}")
117+
allow_pattern = re.compile(f"{release_tag}(_docs)*")
118+
bad_lines = check_all_files(allow_pattern)
119+
if bad_lines:
120+
print(
121+
f"Found lines referring to previous release. Either update the files, or add an exclusion to {__file__}"
122+
)
123+
for line in bad_lines:
124+
print(line)
125+
126+
sys.exit(1 if bad_lines else 0)
127+
128+
129+
if __name__ == "__main__":
130+
if "--test" in sys.argv:
131+
test_pattern()
132+
main()

0 commit comments

Comments
 (0)