From 3b246ee36fc0a657791a1f3edd30f9da7910516c Mon Sep 17 00:00:00 2001 From: lingye <2389156934@qq.com> Date: Thu, 19 Feb 2026 20:38:58 +0800 Subject: [PATCH 1/2] test: add invalid spacing title trigger file --- invalid-space-case.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 invalid-space-case.txt diff --git a/invalid-space-case.txt b/invalid-space-case.txt new file mode 100644 index 0000000..6f9eb03 --- /dev/null +++ b/invalid-space-case.txt @@ -0,0 +1 @@ +Invalid spacing PR title test branch change. From 27139c3e2d79a481218b357acf04afdaafaa6ba2 Mon Sep 17 00:00:00 2001 From: lingye <2389156934@qq.com> Date: Thu, 19 Feb 2026 20:44:27 +0800 Subject: [PATCH 2/2] ci: add GitHub error annotations for PR title check --- .github/workflows/pr-title-check.yml | 39 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 68ede53..97426f6 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -18,6 +18,12 @@ jobs: import re import sys + def fail(message: str, detail: str | None = None) -> None: + print(f"::error title=PR 标题校验失败::{message}") + if detail: + print(detail) + sys.exit(1) + title = (os.getenv("PR_TITLE") or "").strip() allowed_types = { "build", "chore", "ci", "docs", "feat", "fix", @@ -26,32 +32,33 @@ jobs: match = re.match(r"^([a-z]+)(?:\(([^)]+)\))?:(\s+)(.+)$", title) if not match: - print("PR 标题格式错误,应为: type(scope): subject 或 type: subject") - print("例如: feat(api): add login endpoint") - print(f"当前标题: {title}") - sys.exit(1) + fail( + "PR 标题格式错误,应为: type(scope): subject 或 type: subject", + f"例如: feat(api): add login endpoint\n当前标题: {title}", + ) pr_type, scope, spaces_after_colon, subject = match.groups() if pr_type not in allowed_types: - print(f'不支持的 type: "{pr_type}"') - print("允许的 type: " + ", ".join(sorted(allowed_types))) - sys.exit(1) + fail( + f'不支持的 type: "{pr_type}"', + "允许的 type: " + ", ".join(sorted(allowed_types)), + ) if spaces_after_colon != " ": - print("格式错误: 冒号后必须有且仅有 1 个空格。") - print("正确示例: feat(api): add login endpoint") - print(f"当前标题: {title}") - sys.exit(1) + fail( + "格式错误: 冒号后必须有且仅有 1 个空格。", + f"正确示例: feat(api): add login endpoint\n当前标题: {title}", + ) if scope and not re.fullmatch(r"[A-Za-z0-9._/-]+", scope): - print(f'scope 不合法: "{scope}"') - print("scope 仅允许英文、数字、点(.)、下划线(_) 、斜杠(/) 、中划线(-)") - sys.exit(1) + fail( + f'scope 不合法: "{scope}"', + "scope 仅允许英文、数字、点(.)、下划线(_) 、斜杠(/) 、中划线(-)", + ) if not subject.strip(): - print("subject 不能为空") - sys.exit(1) + fail("subject 不能为空") print(f"PR title OK -> type={pr_type}, scope={scope or '-'}, subject={subject}") PY