refactor(CI/Codestyle): Move the SQL check to python (#21002)
This commit is contained in:
parent
cbdab03623
commit
d5fac96a20
2
.github/workflows/codestyle.yml
vendored
2
.github/workflows/codestyle.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: AzerothCore codestyle
|
||||
run: python ./apps/codestyle/codestyle.py
|
||||
run: python ./apps/codestyle/codestyle-cpp.py
|
||||
- name: C++ Advanced
|
||||
run: |
|
||||
sudo apt update -y
|
||||
|
||||
8
.github/workflows/sql-codestyle.yml
vendored
8
.github/workflows/sql-codestyle.yml
vendored
@ -13,5 +13,9 @@ jobs:
|
||||
if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check pending SQL
|
||||
run: source ./apps/ci/ci-pending.sh
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: AzerothCore codestyle
|
||||
run: python ./apps/codestyle/codestyle-sql.py
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Pending SQL check script:"
|
||||
echo
|
||||
|
||||
# We want to ensure the end of file has a semicolon and doesn't have extra
|
||||
# newlines
|
||||
find data/sql/updates/pending* -name "*.sql" -type f | while read -r file; do
|
||||
# The first sed script collapses all strings into an empty string. The
|
||||
# contents of strings aren't necessary for this check and its still valid
|
||||
# sql.
|
||||
#
|
||||
# The second rule removes sql comments.
|
||||
ERR_AT_EOF="$(sed -e "s/'.*'/''/g" -e 's/ --([^-])*$//' "$file" | tr -d '\n ' | tail -c 1)"
|
||||
if [[ "$ERR_AT_EOF" != ";" ]]; then
|
||||
echo "Missing Semicolon (;) or multiple newlines at the end of the file."
|
||||
exit 1
|
||||
else
|
||||
echo "> Semicolon check - OK"
|
||||
fi
|
||||
done
|
||||
|
||||
find data/sql/updates/pending* -name "*.sql" -type f | while read -r file; do
|
||||
if sed "s/'.*'\(.*\)/\1/g" "$file" | grep -q -i -E "broadcast_text"; then
|
||||
echo "> broadcast_text check - Failed"
|
||||
echo " - DON'T EDIT broadcast_text TABLE UNLESS YOU KNOW WHAT YOU ARE DOING!"
|
||||
echo " - This error can safely be ignored if the changes are approved to be sniffed."
|
||||
exit 1
|
||||
else
|
||||
echo "> broadcast_text check - OK"
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Everything looks good"
|
||||
141
apps/codestyle/codestyle-sql.py
Normal file
141
apps/codestyle/codestyle-sql.py
Normal file
@ -0,0 +1,141 @@
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import glob
|
||||
|
||||
# Get the pending directory of the project
|
||||
base_dir = os.getcwd()
|
||||
pattern = os.path.join(base_dir, 'data/sql/updates/pending_db_*')
|
||||
src_directory = glob.glob(pattern)
|
||||
|
||||
# Global variables
|
||||
error_handler = False
|
||||
results = {
|
||||
"Multiple blank lines check": "Passed",
|
||||
"Trailing whitespace check": "Passed",
|
||||
"SQL codestyle check": "Passed",
|
||||
}
|
||||
|
||||
# Collect all files in all directories
|
||||
def collect_files_from_directories(directories: list) -> list:
|
||||
all_files = []
|
||||
for directory in directories:
|
||||
for root, _, files in os.walk(directory):
|
||||
for file in files:
|
||||
if not file.endswith('.sh'): # Skip .sh files
|
||||
all_files.append(os.path.join(root, file))
|
||||
return all_files
|
||||
|
||||
# Main function to parse all the files of the project
|
||||
def parsing_file(files: list) -> None:
|
||||
print("Starting AzerothCore SQL Codestyle check...")
|
||||
print(" ")
|
||||
print("Please read the SQL Standards for AzerothCore:")
|
||||
print("https://www.azerothcore.org/wiki/sql-standards")
|
||||
print(" ")
|
||||
|
||||
# Iterate over all files
|
||||
for file_path in files:
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
multiple_blank_lines_check(file, file_path)
|
||||
trailing_whitespace_check(file, file_path)
|
||||
sql_check(file, file_path)
|
||||
except UnicodeDecodeError:
|
||||
print(f"\nCould not decode file {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Output the results
|
||||
print("")
|
||||
for check, result in results.items():
|
||||
print(f"{check} : {result}")
|
||||
if error_handler:
|
||||
print("\nPlease fix the codestyle issues above.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"\nEverything looks good")
|
||||
|
||||
# Codestyle patterns checking for multiple blank lines
|
||||
def multiple_blank_lines_check(file: io, file_path: str) -> None:
|
||||
global error_handler, results
|
||||
file.seek(0) # Reset file pointer to the beginning
|
||||
check_failed = False
|
||||
consecutive_blank_lines = 0
|
||||
# Parse all the file
|
||||
for line_number, line in enumerate(file, start = 1):
|
||||
if line.strip() == '':
|
||||
consecutive_blank_lines += 1
|
||||
if consecutive_blank_lines > 1:
|
||||
print(f"Multiple blank lines found in {file_path} at line {line_number - 1}")
|
||||
check_failed = True
|
||||
else:
|
||||
consecutive_blank_lines = 0
|
||||
# Additional check for the end of the file
|
||||
if consecutive_blank_lines >= 1:
|
||||
print(f"Multiple blank lines found at the end of: {file_path}")
|
||||
check_failed = True
|
||||
# Handle the script error and update the result output
|
||||
if check_failed:
|
||||
error_handler = True
|
||||
results["Multiple blank lines check"] = "Failed"
|
||||
|
||||
# Codestyle patterns checking for whitespace at the end of the lines
|
||||
def trailing_whitespace_check(file: io, file_path: str) -> None:
|
||||
global error_handler, results
|
||||
file.seek(0) # Reset file pointer to the beginning
|
||||
check_failed = False
|
||||
# Parse all the file
|
||||
for line_number, line in enumerate(file, start = 1):
|
||||
if line.endswith(' \n'):
|
||||
print(f"Trailing whitespace found: {file_path} at line {line_number}")
|
||||
check_failed = True
|
||||
if check_failed:
|
||||
error_handler = True
|
||||
results["Trailing whitespace check"] = "Failed"
|
||||
|
||||
# Codestyle patterns checking for various codestyle issues
|
||||
def sql_check(file: io, file_path: str) -> None:
|
||||
global error_handler, results
|
||||
file.seek(0) # Reset file pointer to the beginning
|
||||
check_failed = False
|
||||
|
||||
# Parse all the file
|
||||
for line_number, line in enumerate(file, start = 1):
|
||||
if [match for match in ['broadcast_text'] if match in line]:
|
||||
print(
|
||||
f"DON'T EDIT broadcast_text TABLE UNLESS YOU KNOW WHAT YOU ARE DOING!\nThis error can safely be ignored if the changes are approved to be sniffed: {file_path} at line {line_number}")
|
||||
check_failed = True
|
||||
if [match for match in [';;'] if match in line]:
|
||||
print(
|
||||
f"Double semicolon (;;) found in {file_path} at line {line_number}")
|
||||
check_failed = True
|
||||
if re.match(r"\t", line):
|
||||
print(
|
||||
f"Tab found! Replace it to 4 spaces: {file_path} at line {line_number}")
|
||||
check_failed = True
|
||||
|
||||
# Ignore comments (remove content after --)
|
||||
line_without_comment = re.sub(r'--.*', '', line).strip()
|
||||
# Check if the last non-empty line ends with a semicolon
|
||||
if not line_without_comment.endswith(';'):
|
||||
print(
|
||||
f"The last non-empty line does not end with a semicolon: {file_path}")
|
||||
check_failed = True
|
||||
|
||||
last_line = line[-1].strip()
|
||||
if last_line:
|
||||
print(
|
||||
f"The last line is not a newline. Please add a newline: {file_path}")
|
||||
check_failed = True
|
||||
|
||||
# Handle the script error and update the result output
|
||||
if check_failed:
|
||||
error_handler = True
|
||||
results["SQL codestyle check"] = "Failed"
|
||||
|
||||
# Collect all files from matching directories
|
||||
all_files = collect_files_from_directories(src_directory)
|
||||
|
||||
# Main function
|
||||
parsing_file(all_files)
|
||||
Loading…
x
Reference in New Issue
Block a user