Skip to content

Commit fe9f325

Browse files
authored
CI: Add keyword checks (#21451)
1 parent 13d3fe6 commit fe9f325

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

.github/workflows/keywords.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Keywords
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- 'master'
8+
9+
jobs:
10+
check-keywords:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v6
14+
- run: |
15+
./scripts/check-keywords.py \
16+
--download_from_url \
17+
--parser_url https://github.com/pingcap/tidb/raw/refs/heads/${GITHUB_BASE_REF}/pkg/parser/parser.y

keywords.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ TiDB 从 v7.5.3 和 v7.6.0 开始提供 [`INFORMATION_SCHEMA.KEYWORDS`](/informa
778778
- VARCHARACTER (R)
779779
- VARIABLES
780780
- VARYING (R)
781-
- VECTOR
781+
- VECTOR
782782
- VIEW
783783
- VIRTUAL (R)
784784
- VISIBLE

scripts/check-keywords.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/python3
2+
import argparse
3+
import requests
4+
import re
5+
import sys
6+
from pathlib import Path
7+
8+
aparser = argparse.ArgumentParser()
9+
aparser.add_argument(
10+
"--parser_file", default="../tidb/pkg/parser/parser.y", help="Path to parser.y"
11+
)
12+
aparser.add_argument(
13+
"--parser_url",
14+
default="https://github.com/pingcap/tidb/raw/refs/heads/master/pkg/parser/parser.y",
15+
help="URL to parser.y",
16+
)
17+
aparser.add_argument("--download_from_url", action="store_true")
18+
args = aparser.parse_args()
19+
20+
if args.download_from_url:
21+
try:
22+
print(f"Fetching {args.parser_url}")
23+
r = requests.get(args.parser_url, timeout=30)
24+
r.raise_for_status()
25+
lines = r.text.splitlines()
26+
except requests.RequestException as e:
27+
sys.exit(f"Failed to download parser file: {e}")
28+
else:
29+
parser = Path(args.parser_file)
30+
if not parser.exists():
31+
sys.exit(f"{parser} doesn't exist")
32+
lines = parser.read_text(encoding="utf-8").splitlines()
33+
34+
kwdocs = Path("keywords.md")
35+
if not kwdocs.exists():
36+
sys.exit(f"{kwdocs} doesn't exist")
37+
38+
keywords = kwdocs.read_text()
39+
40+
errors = 0
41+
section = "Unknown"
42+
for line in lines:
43+
if line == "":
44+
section = "NotKeywordToken"
45+
46+
elif line.find("The following tokens belong to ReservedKeyword") >= 0:
47+
section = "ReservedKeyword"
48+
49+
elif line.find("The following tokens belong to UnReservedKeyword") >= 0:
50+
section = "UnReservedKeyword"
51+
52+
elif line.find("The following tokens belong to TiDBKeyword") >= 0:
53+
section = "TiDBKeyword"
54+
55+
elif line.find("The following tokens belong to NotKeywordToken") >= 0:
56+
section = "NotKeywordToken"
57+
58+
if section == "ReservedKeyword":
59+
if m := re.match(r'^\t\w+\s+"(\w+)"$', line):
60+
kw = m.groups()[0]
61+
if not (
62+
kwm := re.search(f"^- {kw} \\((R|R-Window)\\)$", keywords, re.MULTILINE)
63+
):
64+
if kwm := re.search(f"^- {kw}$", keywords, re.MULTILINE):
65+
print(f"Reserved keyword not labeled as reserved: {kw}")
66+
else:
67+
print(f"Missing docs for reserved keyword: {kw}")
68+
errors += 1
69+
70+
if section in ["UnReservedKeyword", "TiDBKeyword"]:
71+
if m := re.match(r'^\t\w+\s+"(\w+)"$', line):
72+
kw = m.groups()[0]
73+
if not (kwm := re.search(f"^- {kw}$", keywords, re.MULTILINE)):
74+
if kwm := re.search(
75+
f"^- {kw} \\((R|R-Window)\\)$", keywords, re.MULTILINE
76+
):
77+
print(
78+
f"Non-reserved keyword from {section} labeled as reserved: {kw}"
79+
)
80+
else:
81+
print(f"Missing docs for non-reserved keyword from {section}: {kw}")
82+
errors += 1
83+
84+
sys.exit(errors)

0 commit comments

Comments
 (0)