blob: 82e5a4372b0af0b666db43f08ae940d8b4a68e21 [file] [log] [blame]
#!/usr/bin/env python3
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import argparse
import csv
import pickle
import re
import sys
from collections import defaultdict
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent
sys.path.append(str(REPO_ROOT / "tests" / "scripts"))
sys.path.append(str(REPO_ROOT / "tests" / "scripts" / "github"))
sys.path.append(str(REPO_ROOT / "tests" / "scripts" / "jenkins"))
# Tag dictionary used to create a mapping relation to categorize PRs owning same tag.
TAG_DICT = {
"metaschedule": "MetaSchedule",
"cuda": "cuda & cutlass & tensorrt",
"cutlass": "cuda & cutlass & tensorrt",
"tensorrt": "cuda & cutlass & tensorrt",
"hexagon": "Hexagon",
"metal": "Metal",
"vulkan": "Vulkan",
"clml": "OpenCL & CLML",
"opencl": "OpenCL & CLML",
"openclml": "OpenCL & CLML",
"adreno": "Adreno",
"acl": "ArmComputeLibrary",
"rocm": "ROCm",
"crt": "CRT",
"web": "web",
"wasm": "web",
"runtime": "Runtime",
"aot": "AOT",
"arith": "Arith",
"byoc": "BYOC",
"community": "Community",
"tensorir": "TIR",
"tir": "TIR",
"tensorflow": "Frontend",
"tflite": "Frontend",
"pytorch": "Frontend",
"torch": "Frontend",
"keras": "Frontend",
"frontend": "Frontend",
"onnx": "Frontend",
"roofline": "Misc",
"rpc": "Misc",
"tophub": "Misc",
"ux": "Misc",
"APP": "Misc",
"docker": "Docker",
"doc": "Docs",
"docs": "Docs",
"llvm": "LLVM",
"sve": "LLVM",
"ci": "CI",
"test": "CI",
"tests": "CI",
"testing": "CI",
"unittest": "CI",
"bugfix": "BugFix",
"fix": "BugFix",
"bug": "BugFix",
"hotfix": "BugFix",
"qnn": "Relay",
"quantization": "Relay",
"relax": "Relax",
"unity": "Relax",
"transform": "Relax",
"kvcache": "Relax",
"s_tir": "S-TIR",
"disco": "Disco",
"tvmscript": "TVMScript",
"tvmscripts": "TVMScript",
"tvmc": "TVMC",
"topi": "TOPI",
}
def strip_header(title: str, header: str) -> str:
pos = title.lower().find(header.lower())
if pos == -1:
return title
return title[0:pos] + title[pos + len(header) :].strip()
def sprint(*args):
print(*args, file=sys.stderr)
def create_pr_dict(cache: Path):
with open(cache, "rb") as f:
data = pickle.load(f)
sprint(data[1])
pr_dict = {}
for item in data:
prs = item["associatedPullRequests"]["nodes"]
if len(prs) != 1:
continue
pr = prs[0]
pr_dict[pr["number"]] = pr
return pr_dict
def categorize_csv_file(csv_path: str):
headings = defaultdict(lambda: defaultdict(list))
sprint("Opening CSV")
with open(csv_path) as f:
input_file = csv.DictReader(f)
i = 0
blank_cate_set = {"Misc"}
for row in input_file:
# print(row)
tags = row["pr_title_tags"].split("/")
tags = ["misc"] if len(tags) == 0 else tags
categories = map(lambda t: TAG_DICT.get(t.lower(), "Misc"), tags)
categories = list(categories)
categories = list(set(categories) - blank_cate_set)
category = "Misc" if len(categories) == 0 else categories[0]
subject = row["subject"].strip()
pr_number = row["url"].split("/")[-1]
if category == "" or subject == "":
sprint(f"Skipping {i}th pr with number: {pr_number}, row: {row}")
continue
headings[category][subject].append(pr_number)
i += 1
# if i > 30:
# break
return headings
if __name__ == "__main__":
help = "List out commits with attached PRs since a certain commit"
parser = argparse.ArgumentParser(description=help)
parser.add_argument(
"--notes", required=True, help="csv or markdown file of categorized PRs in order"
)
parser.add_argument(
"--is-pr-with-link",
required=False,
help="exported pr number with hyper-link for forum format",
)
parser.add_argument(
"--convert-with-link",
required=False,
help="make PR number in markdown file owning hyper-link",
)
args = parser.parse_args()
user = "apache"
repo = "tvm"
if args.convert_with_link:
with open(args.notes) as f:
lines = f.readlines()
formated = []
for line in lines:
match = re.search(r"#\d+", line)
if match:
pr_num_str = match.group()
pr_num_int = pr_num_str.replace("#", "")
pr_number_str = f"[#{pr_num_int}](https://github.com/apache/tvm/pull/{pr_num_int})"
line = line.replace(pr_num_str, pr_number_str)
formated.append(line)
result = "".join(formated)
print(result)
exit(0)
# 1. Create PR dict from cache file
cache = Path("out.pkl")
if not cache.exists():
sprint("run gather_prs.py first to generate out.pkl")
exit(1)
pr_dict = create_pr_dict(cache)
# 2. Categorize csv file as dict by category and subject (sub-category)
headings = categorize_csv_file(args.notes)
# 3. Summarize and sort all categories
def sorter(x):
if x == "Misc":
return 10
return 0
keys = list(headings.keys())
keys = list(sorted(keys))
keys = list(sorted(keys, key=sorter))
# 4. Generate markdown by loop categorized csv file dict
def pr_title(number, heading):
# print(f"number:{number}, heading:{heading}, len(pr_dict):{len(pr_dict)}")
try:
title = pr_dict[int(number)]["title"]
title = strip_header(title, heading)
except Exception:
sprint("The out.pkl file is not match with csv file.")
exit(1)
return title
output = ""
for key in keys:
value = headings[key]
if key == "DO NOT INCLUDE":
continue
value = dict(value)
output += f"### {key}\n"
misc = []
misc += value.get("n/a", [])
misc += value.get("Misc", [])
for pr_number in misc:
if args.is_pr_with_link:
pr_number_str = f"[#{pr_number}](https://github.com/apache/tvm/pull/{pr_number})"
else:
pr_number_str = f"#{pr_number}"
pr_str = f" * {pr_number_str} - {pr_title(pr_number, '[' + key + ']')}\n"
output += pr_str
for subheading, pr_numbers in value.items():
if subheading == "DO NOT INCLUDE":
continue
if subheading == "n/a" or subheading == "Misc":
continue
else:
output += f" * {subheading} - " + ", ".join([f"#{n}" for n in pr_numbers]) + "\n"
# print(value)
output += "\n"
# 5. Print markdown-format output
print(output)