diff --git a/advisors/tc_review b/advisors/tc_review index 6c9bc6cabf511851a819c9e7c5178cb476b00347..19a9dfd5a7e7b8492e3c8d3a5bd34b71bda5e79c 100755 --- a/advisors/tc_review +++ b/advisors/tc_review @@ -15,6 +15,7 @@ Review tool for openEuler submission """ import os import re +import sys import argparse import subprocess @@ -22,7 +23,7 @@ import gitee BASIC_CHK = """ **以下为 openEuler-Advisor 的 tc_review 生成审视要求清单** -**[Y]** 审视者确认符合要求 | **[N]** 审视者认为不符合要求 | **[?]** 审视者无法确认是否符合要求 | **[ ]** 审视过程中 +**[Y]** 审视者确认符合要求 | **[N]** 审视者认为不符合要求 | **[NA]** 审视者认为与本PR无关 | **[?]** 审视者无法确认是否符合要求 | **[ ]** 审视过程中 |审视情况|审视要求|审视要求说明| |:--:|:--|:--| |[ ]|PR的标题是否清晰易懂?|提交标题应该一句话说明本提交实现的内容。| @@ -33,12 +34,27 @@ BASIC_CHK = """ """ OWNER_CHK = "|[ ]|如果新增维护者,有没有对他/她能力的客观说明?|PR提交者需要提出相应的举证说明维护者候选人的技术能力与社区活跃程度。|\n" -OWNER_CHK_1 = "|[ ]|{sig} 中的其他维护者是否同意增加/删除维护者?|需要 {owners} 中至少两人代表确认是否同意接纳或者移除维护者。|\n" +OWNER_CHK_1 = "|[ ]|{sig} 中的其他维护者是否同意增加/删除维护者?|需要 {owners} 中至少两人代表在此 PR 的 review 中留下 "\ + "\"/lgtm\" 表示确认同意接纳或者移除维护者。|\n" + +INFO_CHK = "|[ ]|{sig} 是否同意更新 SIG 信息?| {owners} 中是否有代表通过在此 PR 的 review 中留下 \"/lgtm\" 表示同意。|\n" REPO_CHK = "|[ ]|是否所有变更的代码仓都被恰当的 SIG 管理?|代码仓应当由有能力且有意愿的SIG管理,同一类的软件尽量归属同一个SIG。|\n" -REPO_CHK_1 = "|[ ]|{sig}的维护者是否同意变更|需要 {owners} 中至少一人在此确认。|\n" +REPO_CHK_1 = "|[ ]|{sig}的维护者是否同意变更|需要 {owners} 中至少一人在PR的review中留下 \"/lgtm\" 表示确认。|\n" + +DEL_CHK = "|[ ]|是否确认删除 {repo} ?|为了保证兼容性,技术委员会建议将 {repo} 移动到 sig-recycle 管理一段时间,给用户切换时间。|\n" + +UPSTREAM_CHK = "|[ ]|是否正确提供代码仓上游信息?|使用软件社区的正式官方网址,或者无单独正式官网的情况下,提供主流代码托管商上面"\ + "对应的项目网址(如github)。不可使用maven等托管库作为官方网址。|\n" +NAME_CHK = "|[ ]|代码仓名称是否规范?|代码仓名称必须和上游官网/社区保持一致,不可随意命名。不允许以软件包中的子模块作为代码仓名。"\ + "当软件是某个语言的开发库时,可以使用前缀予以规范化管理(如 python-,perl-等)。|\n" +EOS_CHK = "|[ ]|新引入代码仓的上游是否仍处于生命周期内?|已经衰退的软件,生命周期结束,社区停运,或超过5年没有任何更新的软件,"\ + "原则上不引入openEuler。如果提交者认为非常有必要,可以考虑在 openeuler 中 fork 以后独立维护。|\n" +LICENSE_CHK = "|[ ]|新引入的代码仓的 License 授权是否都与 openEuler 兼容?|openEuler只能接纳可以被允许集成的软件。|\n" +COPYRIGHT_CHK = "|[ ]|新引入的代码仓的是否有 Copyright 信息?|我们期望软件有明确的 Copyright 信息。|\n" -LICENSE_CHK = "|[ ]|新引入的代码仓的 license 授权是否都与 openEuler 兼容?|openEuler只能接纳可以被允许集成的软件|\n" +ENCRYPTION_CHK = "|[ ]|新引入代码仓是否不涉及从美国代码托管网站引入加解密算法的实现?| "\ + "openEuler作为开源项目整体已经备案,无论是否涉及都不需要额外处理。|\n" SANITY_CHK_CMD = "python3 zh/technical-committee/governance/sanity_check.py ." @@ -52,7 +68,7 @@ def check_repository_changes(): return True return False -def check_repository_mgmt_changes(): +def check_repository_mgmt_changes(sigs): """ Return additional checking item if management of repository has been changed """ @@ -60,7 +76,7 @@ def check_repository_mgmt_changes(): need_additional_review = False ret_code, lst_files = subprocess.getstatusoutput(SANITY_CHK_CMD) if ret_code != 0: - return "|[ ]|PR必须通过CI检查|sanity_check.py 在这个 PR 中发现错误。|" + return False, "|[ ]|PR必须通过CI检查|sanity_check.py 在这个 PR 中发现错误。|\n" for item in lst_files.splitlines(): if item.startswith("SUGGESTION: This PR needs to be reviewed"): need_additional_review = True @@ -70,34 +86,68 @@ def check_repository_mgmt_changes(): if result: sig = result.group(1) owners = result.group(2) - review_body += REPO_CHK_1.format(sig=sig, owners=owners) - return review_body + if sig not in sigs: + review_body += REPO_CHK_1.format(sig=sig, owners=owners) + else: + result = re.match("WARNING! deleting (.*)", item) + if result: + review_body += DEL_CHK.format(repo=result.group(1)) + return need_additional_review, review_body + def check_maintainer_changes(): """ return all SIGs with changed maintainer """ sigs = {} - lst_files = subprocess.getoutput("git diff --name-only remotes/origin/master..") - for item in lst_files.splitlines(): - if item.startswith("sig") and item.endswith("OWNERS"): + lst_files = subprocess.getoutput("git diff --name-status remotes/origin/master..") + for line in lst_files.splitlines(): + status, item = line.split() + if status != "M": + continue + if item.startswith("sig/") and item.endswith("/OWNERS"): sig = item.split("/")[1] owners = [] - with open(item, "r") as owner_file: - for line in owner_file: - if line.strip().startswith("-"): - owner = line.replace("- ", "@").strip() - owners.append(owner) + owner_file = subprocess.getoutput("git show remotes/origin/master:" + item) + for f_line in owner_file.splitlines(): + if f_line.strip().startswith("-"): + owner = f_line.replace("- ", "@").strip() + owners.append(owner) sigs[sig] = " ".join(owners) return sigs +def check_sig_information_changes(): + """ + return all SIGs with changed information + """ + sigs = {} + lst_files = subprocess.getoutput("git diff --name-status remotes/origin/master..") + for line in lst_files.splitlines(): + status, item = line.split() + if status != "M": + continue + if item == "sig/sigs.yaml": + continue + if item.startswith("sig/") and not item.endswith("/OWNERS"): + sig = item.split("/")[1] + owners = [] + owner_fn = item.split("/")[:2] + owner_fn.append("OWNERS") + cmd_line = "git show remotes/origin/master:" + "/".join(owner_fn) + owner_file = subprocess.getoutput(cmd_line) + for f_line in owner_file.splitlines(): + if f_line.strip().startswith("-"): + owner = f_line.replace("- ", "@").strip() + owners.append(owner) + sigs[sig] = " ".join(owners) + return sigs def review(pull_request): """ Return check list of this PR """ - if pull_request["mergeable"] == False: + if not pull_request["mergeable"]: return "PR中存在冲突,无法自动合并。需要先解决冲突,才可以开展评审。" review_body = BASIC_CHK @@ -107,12 +157,25 @@ def review(pull_request): review_body += OWNER_CHK for sig in sigs: review_body += OWNER_CHK_1.format(sig=sig, owners=sigs[sig]) - additional = check_repository_mgmt_changes() + + info_sigs = check_sig_information_changes() + for sig in info_sigs: + if sig in sigs: + continue + review_body += INFO_CHK.format(sig=sig, owners=info_sigs[sig]) + + additional, add_review = check_repository_mgmt_changes(info_sigs) if additional: review_body += REPO_CHK - review_body += additional + review_body += add_review + if check_repository_changes(): + review_body += UPSTREAM_CHK + review_body += NAME_CHK + review_body += EOS_CHK review_body += LICENSE_CHK + review_body += COPYRIGHT_CHK + review_body += ENCRYPTION_CHK return review_body def main(): @@ -138,6 +201,9 @@ def main(): print("Failed to checkout master branch") sys.exit(1) + subprocess.call(["git", "branch", "-D", "pr_{n}".format(n=args.pull)]) + # It's OK to ignore the result + ret_code = subprocess.call(["git", "pull"]) if ret_code != 0: print("Failed to update to latest commit in master branch") @@ -155,6 +221,7 @@ def main(): pull_request = user_gitee.get_pr("community", args.pull, "openeuler") review_comment = review(pull_request) + #print(review_comment) user_gitee.create_pr_comment("community", args.pull, review_comment, "openeuler")