Skip to content

script to check for old release links and references #4153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,9 @@ repos:
language: script
entry: utils/validate_inits.py
types: [python]
- id: validate-release-links-py
name: validate release links
language: script
entry: utils/validate_release_links.py


132 changes: 132 additions & 0 deletions utils/validate_release_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env python3

import ast
import sys
import os
import re
import subprocess
from typing import List, Optional, Pattern

RELEASE_PATTERN = re.compile(r"release_[0-9]+(_docs)*")
TRAINER_INIT_FILE = "ml-agents/mlagents/trainers/__init__.py"

# Filename -> regex list to allow specific lines.
# To allow everything in the file, use None for the value
ALLOW_LIST = {
# Previous release table
"README.md": re.compile(r"\*\*Release [0-9]+\*\*"),
"docs/Versioning.md": None,
"com.unity.ml-agents/CHANGELOG.md": None,
"utils/make_readme_table.py": None,
"utils/validate_doc_versions.py": None,
}


def test_pattern():
# Just some sanity check that the regex works as expected.
assert RELEASE_PATTERN.search(
"https://github.com/Unity-Technologies/ml-agents/blob/release_3_docs/Food.md"
)
assert RELEASE_PATTERN.search(
"https://github.com/Unity-Technologies/ml-agents/blob/release_3/Foo.md"
)
assert RELEASE_PATTERN.search(
"git clone --branch release_3 https://github.com/Unity-Technologies/ml-agents.git"
)
assert RELEASE_PATTERN.search(
"https://github.com/Unity-Technologies/ml-agents/blob/release_123_docs/Foo.md"
)
assert RELEASE_PATTERN.search(
"https://github.com/Unity-Technologies/ml-agents/blob/release_123/Foo.md"
)
assert not RELEASE_PATTERN.search(
"https://github.com/Unity-Technologies/ml-agents/blob/latest_release/docs/Foo.md"
)
print("tests OK!")


def git_ls_files() -> List[str]:
"""
Run "git ls-files" and return a list with one entry per line.
This returns the list of all files tracked by git.
"""
return subprocess.check_output(["git", "ls-files"], universal_newlines=True).split(
"\n"
)


def get_release_tag() -> Optional[str]:
"""
Returns the release tag for the mlagents python package.
This will be None on the master branch.
:return:
"""
with open(TRAINER_INIT_FILE) as f:
for line in f:
if "__release_tag__" in line:
lhs, equals_string, rhs = line.strip().partition(" = ")
# Evaluate the right hand side of the expression
return ast.literal_eval(rhs)
# If we couldn't find the release tag, raise an exception
# (since we can't return None here)
raise RuntimeError("Can't determine release tag")


def check_file(filename: str, global_allow_pattern: Pattern) -> List[str]:
"""
Validate a single file and return any offending lines.
"""
bad_lines = []
with open(filename, "r") as f:
for line in f:
if not RELEASE_PATTERN.search(line):
continue

if global_allow_pattern.search(line):
continue

if filename in ALLOW_LIST:
if ALLOW_LIST[filename] is None or ALLOW_LIST[filename].search(line):
continue

bad_lines.append(f"{filename}: {line.strip()}")
return bad_lines


def check_all_files(allow_pattern: Pattern) -> List[str]:
"""
Validate all files tracked by git.
:param allow_pattern:
"""
bad_lines = []
file_types = {".py", ".md", ".cs"}
for file_name in git_ls_files():
if "localized" in file_name or os.path.splitext(file_name)[1] not in file_types:
continue
bad_lines += check_file(file_name, allow_pattern)
return bad_lines


def main():
release_tag = get_release_tag()
if not release_tag:
print("Release tag is None, exiting")
sys.exit(0)

print(f"Release tag: {release_tag}")
allow_pattern = re.compile(f"{release_tag}(_docs)*")
bad_lines = check_all_files(allow_pattern)
if bad_lines:
print(
f"Found lines referring to previous release. Either update the files, or add an exclusion to {__file__}"
)
for line in bad_lines:
print(line)

sys.exit(1 if bad_lines else 0)


if __name__ == "__main__":
if "--test" in sys.argv:
test_pattern()
main()