Skip to content

Commit 4778b24

Browse files
committed
Merge pull request godotengine#91597 from Repiteo/ci/pre-commit-handle-everything
CI: Overhaul static checks to use `pre-commit`
2 parents 15d2000 + df969ff commit 4778b24

File tree

10 files changed

+355
-273
lines changed

10 files changed

+355
-273
lines changed

.github/workflows/static_checks.yml

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,13 @@ jobs:
1919
- name: Install APT dependencies
2020
uses: awalsh128/cache-apt-pkgs-action@latest
2121
with:
22-
packages: dos2unix libxml2-utils moreutils
22+
packages: libxml2-utils
2323

2424
- name: Install Python dependencies and general setup
2525
run: |
26-
pip3 install pytest==7.1.2 mypy==0.971
26+
pip3 install pytest==7.1.2
2727
git config diff.wsErrorHighlight all
2828
29-
- name: Get changed files
30-
id: changed-files
31-
env:
32-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33-
run: |
34-
if [ "${{ github.event_name }}" == "pull_request" ]; then
35-
files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true)
36-
elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then
37-
files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true)
38-
fi
39-
echo "$files" >> changed.txt
40-
cat changed.txt
41-
files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "./{}"' | tr '\n' ' ')
42-
echo "CHANGED_FILES=$files" >> $GITHUB_ENV
43-
4429
# This needs to happen before Python and npm execution; it must happen before any extra files are written.
4530
- name: .gitignore checks (gitignore_check.sh)
4631
run: |
@@ -49,51 +34,12 @@ jobs:
4934
- name: Style checks via pre-commit
5035
uses: pre-commit/[email protected]
5136
with:
52-
extra_args: --verbose --files ${{ env.CHANGED_FILES }}
53-
54-
- name: File formatting checks (file_format.sh)
55-
run: |
56-
bash ./misc/scripts/file_format.sh changed.txt
57-
58-
- name: Header guards formatting checks (header_guards.sh)
59-
run: |
60-
bash ./misc/scripts/header_guards.sh changed.txt
61-
62-
- name: Python scripts static analysis (mypy_check.sh)
63-
run: |
64-
if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then
65-
bash ./misc/scripts/mypy_check.sh
66-
else
67-
echo "Skipping Python static analysis as no Python files were changed."
68-
fi
69-
70-
- name: Python builders checks via pytest (pytest_builders.sh)
71-
run: |
72-
bash ./misc/scripts/pytest_builders.sh
37+
extra_args: --verbose
7338

74-
- name: JavaScript style and documentation checks via ESLint and JSDoc
39+
- name: Python builders checks via pytest
7540
run: |
76-
if grep -q "\.js" changed.txt || [ -z "$(cat changed.txt)" ]; then
77-
cd platform/web
78-
npm ci
79-
npm run lint
80-
npm run docs -- -d dry-run
81-
else
82-
echo "Skipping JavaScript formatting as no Web/JS files were changed."
83-
fi
41+
pytest ./tests/python_build
8442
8543
- name: Class reference schema checks
8644
run: |
8745
xmllint --noout --schema doc/class.xsd doc/classes/*.xml modules/*/doc_classes/*.xml platform/*/doc_classes/*.xml
88-
89-
- name: Documentation checks
90-
run: |
91-
doc/tools/doc_status.py doc/classes modules/*/doc_classes platform/*/doc_classes
92-
93-
- name: Spell checks via codespell
94-
if: github.event_name == 'pull_request' && env.CHANGED_FILES != ''
95-
uses: codespell-project/actions-codespell@v2
96-
with:
97-
skip: "./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/project_converter_3_to_4.cpp,./misc/scripts/codespell.sh,./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json"
98-
ignore_words_list: "breaked,colour,curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,thirdparty,vai"
99-
path: ${{ env.CHANGED_FILES }}

.pre-commit-config.yaml

Lines changed: 139 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
exclude: |
2+
(?x)^(
3+
.*thirdparty/.*|
4+
.*-so_wrap\.(h|c)$
5+
)
6+
17
repos:
28
- repo: https://github.com/pre-commit/mirrors-clang-format
39
rev: v17.0.6
@@ -7,10 +13,8 @@ repos:
713
types_or: [text]
814
exclude: |
915
(?x)^(
10-
tests/python_build.*|
11-
.*thirdparty.*|
12-
.*platform/android/java/lib/src/com.*|
13-
.*-so_wrap.*
16+
tests/python_build/.*|
17+
platform/android/java/lib/src/com/.*
1418
)
1519
1620
- repo: https://github.com/psf/black-pre-commit-mirror
@@ -19,33 +23,155 @@ repos:
1923
- id: black
2024
files: (\.py$|SConstruct|SCsub)
2125
types_or: [text]
22-
exclude: .*thirdparty.*
2326
args:
2427
- --line-length=120
2528

29+
- repo: https://github.com/pre-commit/mirrors-mypy
30+
rev: v0.971
31+
hooks:
32+
- id: mypy
33+
files: \.py$
34+
types_or: [text]
35+
args: [--config-file=./misc/scripts/mypy.ini]
36+
37+
- repo: https://github.com/codespell-project/codespell
38+
rev: v2.2.6
39+
hooks:
40+
- id: codespell
41+
types_or: [text]
42+
exclude: |
43+
(?x)^(
44+
.*\.desktop$|
45+
.*\.gitignore$|
46+
.*\.po$|
47+
.*\.pot$|
48+
.*\.rc$|
49+
\.mailmap$|
50+
AUTHORS.md$|
51+
COPYRIGHT.txt$|
52+
DONORS.md$|
53+
core/input/gamecontrollerdb.txt$|
54+
core/string/locales.h$|
55+
editor/project_converter_3_to_4.cpp$|
56+
platform/android/java/lib/src/com/.*|
57+
platform/web/package-lock.json$
58+
)
59+
args:
60+
- --enable-colors
61+
- --write-changes
62+
- --check-hidden
63+
- --quiet-level
64+
- '3'
65+
- --ignore-words-list
66+
- aesthetic,aesthetics,breaked,cancelled,colour,curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,mis,nd,numer,ot,requestor,te,thirdparty,vai
67+
- --builtin
68+
- clear,rare,en-GB_to_en-US
69+
70+
### Requires Docker; look into alternative implementation.
71+
# - repo: https://github.com/comkieffer/pre-commit-xmllint.git
72+
# rev: 1.0.0
73+
# hooks:
74+
# - id: xmllint
75+
# language: docker
76+
# types_or: [text]
77+
# files: ^(doc/classes|.*/doc_classes)/.*\.xml$
78+
# args: [--schema, doc/class.xsd]
79+
80+
- repo: https://github.com/pre-commit/mirrors-eslint
81+
rev: v8.46.0
82+
hooks:
83+
- id: eslint
84+
name: eslint-engine
85+
files: ^(platform/web/js/engine/|js/jsdoc2rst/).*\.js$
86+
args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.engine.js]
87+
additional_dependencies: &eslint-deps
88+
89+
90+
91+
92+
- '@html-eslint/[email protected]'
93+
- '@html-eslint/[email protected]'
94+
- id: eslint
95+
name: eslint-libs
96+
files: ^(platform/web/js/libs/|modules/).*\.js$
97+
args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.libs.js]
98+
additional_dependencies: *eslint-deps
99+
- id: eslint
100+
name: eslint-sw
101+
files: ^misc/dist/html/service-worker\.js$
102+
args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.sw.js]
103+
additional_dependencies: *eslint-deps
104+
- id: eslint
105+
name: eslint-html
106+
files: ^misc/dist/html/.*\.html$
107+
types: [html]
108+
args: [--fix, --no-eslintrc, --config, platform/web/.eslintrc.html.js]
109+
additional_dependencies: *eslint-deps
110+
26111
- repo: local
27112
hooks:
28113
- id: make-rst
29114
name: make-rst
115+
language: python
30116
entry: python3 doc/tools/make_rst.py doc/classes modules platform --dry-run --color
31117
pass_filenames: false
118+
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
119+
120+
- id: doc-status
121+
name: doc-status
32122
language: python
33-
files: ^(doc|modules|platform).*xml$
123+
entry: python3 doc/tools/doc_status.py
124+
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
125+
126+
- id: jsdoc
127+
name: jsdoc
128+
language: node
129+
entry: jsdoc
130+
files: ^platform/web/js/engine/(engine|config|features)\.js$
131+
args: [--template, platform/web/js/jsdoc2rst/, --destination, '', -d, dry-run]
132+
additional_dependencies: ["[email protected]"]
34133

35134
- id: copyright-headers
36135
name: copyright-headers
37136
language: python
38-
files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java)$
39137
entry: python3 misc/scripts/copyright_headers.py
138+
files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java)$
40139
exclude: |
41140
(?x)^(
42-
.*thirdparty.*|
43-
.*-so_wrap.*|
44141
core/math/bvh_.*\.inc$|
45-
platform/android/java/lib/src/com.*|
46-
platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.*|
47-
platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper.*|
48-
platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.*
142+
platform/android/java/lib/src/com/.*|
143+
platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java$|
144+
platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java$|
145+
platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java$
146+
)
147+
148+
- id: header-guards
149+
name: header-guards
150+
language: python
151+
entry: python3 misc/scripts/header_guards.py
152+
files: \.(h|hpp)$
153+
exclude: |
154+
(?x)^(
155+
.*/thread\.h$|
156+
.*/platform_config\.h$|
157+
.*/platform_gl\.$h
158+
)
159+
160+
- id: file-format
161+
name: file-format
162+
language: python
163+
entry: python3 misc/scripts/file_format.py
164+
types_or: [text]
165+
exclude: |
166+
(?x)^(
167+
.*\.test\.txt$|
168+
.*\.svg$|
169+
.*\.patch$|
170+
.*\.out$|
171+
modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd$|
172+
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
173+
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
174+
platform/android/java/lib/src/com/google/.*
49175
)
50176
51177
- id: dotnet-format

misc/scripts/codespell.sh

Lines changed: 0 additions & 8 deletions
This file was deleted.

misc/scripts/dotnet_format.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
import os
66
import sys
77

8-
# Create dummy generated files.
8+
if len(sys.argv) < 2:
9+
print("Invalid usage of dotnet_format.py, it should be called with a path to one or multiple files.")
10+
sys.exit(1)
11+
12+
# Create dummy generated files, if needed.
913
for path in [
1014
"modules/mono/SdkPackageVersions.props",
1115
]:
16+
if os.path.exists(path):
17+
continue
1218
os.makedirs(os.path.dirname(path), exist_ok=True)
1319
with open(path, "w", encoding="utf-8", newline="\n") as f:
1420
f.write("<Project />")
@@ -17,14 +23,12 @@
1723
os.environ["GodotSkipGenerated"] = "true"
1824

1925
# Match all the input files to their respective C# project.
20-
input_files = [os.path.normpath(x) for x in sys.argv]
2126
projects = {
22-
path: [f for f in sys.argv if os.path.commonpath([f, path]) == path]
27+
path: " ".join([f for f in sys.argv[1:] if os.path.commonpath([f, path]) == path])
2328
for path in [os.path.dirname(f) for f in glob.glob("**/*.csproj", recursive=True)]
2429
}
2530

2631
# Run dotnet format on all projects with more than 0 modified files.
2732
for path, files in projects.items():
28-
if len(files) > 0:
29-
command = f"dotnet format {path} --include {' '.join(files)}"
30-
os.system(command)
33+
if files:
34+
os.system(f"dotnet format {path} --include {files}")

misc/scripts/file_format.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
6+
if len(sys.argv) < 2:
7+
print("Invalid usage of file_format.py, it should be called with a path to one or multiple files.")
8+
sys.exit(1)
9+
10+
BOM = b"\xef\xbb\xbf"
11+
12+
changed = []
13+
invalid = []
14+
15+
for file in sys.argv[1:]:
16+
try:
17+
with open(file, "rt", encoding="utf-8") as f:
18+
original = f.read()
19+
except UnicodeDecodeError:
20+
invalid.append(file)
21+
continue
22+
23+
if original == "":
24+
continue
25+
26+
EOL = "\r\n" if file.endswith((".csproj", ".sln", ".bat")) or file.startswith("misc/msvs") else "\n"
27+
WANTS_BOM = file.endswith((".csproj", ".sln"))
28+
29+
revamp = EOL.join([line.rstrip("\n\r\t ") for line in original.splitlines(True)]).rstrip(EOL) + EOL
30+
31+
new_raw = revamp.encode(encoding="utf-8")
32+
if not WANTS_BOM and new_raw.startswith(BOM):
33+
new_raw = new_raw[len(BOM) :]
34+
elif WANTS_BOM and not new_raw.startswith(BOM):
35+
new_raw = BOM + new_raw
36+
37+
with open(file, "rb") as f:
38+
old_raw = f.read()
39+
40+
if old_raw != new_raw:
41+
changed.append(file)
42+
with open(file, "wb") as f:
43+
f.write(new_raw)
44+
45+
if changed:
46+
for file in changed:
47+
print(f"FIXED: {file}")
48+
if invalid:
49+
for file in invalid:
50+
print(f"REQUIRES MANUAL CHANGES: {file}")
51+
sys.exit(1)

0 commit comments

Comments
 (0)