跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 31 章 贡献指南

/code/31-contributing/

03-checklist-gate/checklist_gate.py3186 字节
#!/usr/bin/env python3
"""Fail a self-check list when an unchecked item has no stated reason.

The Ascend PR template asks contributors to explain every skipped item. This
script turns that request into a gate that can run before the PR is opened.

Usage:
    python3 checklist_gate.py <checklist.md>
    python3 checklist_gate.py --template
    python3 checklist_gate.py --self-test
"""

from __future__ import annotations

import re
import sys
import tempfile
from pathlib import Path


TEMPLATE = """# 改动自检清单

> 未勾选的条目必须写原因或跟踪 issue。

- [ ] 已跑 `bash format.sh`
  - 原因: <填写;不适用时写不适用并给理由>
- [ ] 已跑改动路径对应的测试套件
  - 原因: <填写>
- [ ] 已附性能报告(若改动触及热点路径)
  - 原因: <填写>
- [ ] 已核对后端可移植性(是否需要 requires_cuda / requires_rocm / requires_metal)
  - 原因: <填写>
- [ ] 昇腾改动已按 PR 模板说明双后端情况
  - 原因: <填写>
"""

UNCHECKED = re.compile(r"^\s*-\s*\[\s\]\s*(?P<body>.*)$")
CHECKED = re.compile(r"^\s*-\s*\[[xX]\]\s*")
REASON_INLINE = re.compile(r"(?:—|--)\s*(原因|理由|Because|Reason)\s*[::]", re.IGNORECASE)
REASON_LINE = re.compile(r"^\s+(?:[-*]\s*)?(原因|理由|Because|Reason)\s*[::]", re.IGNORECASE)


def audit(text: str) -> list[tuple[int, str]]:
    """Return (line_number, text) for unchecked items with no reason."""
    lines = text.splitlines()
    unexplained: list[tuple[int, str]] = []
    for index, line in enumerate(lines):
        match = UNCHECKED.match(line)
        if match is None:
            continue
        body = match.group("body").strip()
        if REASON_INLINE.search(body):
            continue
        if index + 1 < len(lines) and REASON_LINE.match(lines[index + 1]):
            continue
        unexplained.append((index + 1, body))
    return unexplained


def self_test() -> int:
    failures: list[str] = []

    good = """
- [x] done
- [ ] skipped — 原因: no NPU on this machine
- [ ] other
  - 原因: tracked in #1234
"""
    if audit(good):
        failures.append("well-explained list should pass")

    bad = """
- [ ] skipped silently
"""
    if not audit(bad):
        failures.append("silently skipped item should fail")

    if audit(TEMPLATE):
        failures.append("the bundled template must itself pass")

    with tempfile.TemporaryDirectory() as tmp:
        path = Path(tmp) / "check.md"
        path.write_text(good, encoding="utf-8")
        if not path.is_file():
            failures.append("tempfile round-trip failed")

    if failures:
        for failure in failures:
            print(f"FAIL: {failure}", file=sys.stderr)
        return 1
    print("self-test passed")
    return 0


def main(argv: list[str]) -> int:
    if argv == ["--template"]:
        sys.stdout.write(TEMPLATE)
        return 0
    if argv == ["--self-test"]:
        return self_test()
    if len(argv) != 1:
        print(__doc__, file=sys.stderr)
        return 2

    path = Path(argv[0])
    if not path.is_file():
        print(f"not a file: {path}", file=sys.stderr)
        return 2
    unexplained = audit(path.read_text(encoding="utf-8"))
    if unexplained:
        for line_no, body in unexplained:
            print(f"unexplained: {line_no}: {body}")
        return 1
    print(f"ok: {path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))

← 浏览本章全部代码