Skip to content

Commit 2963535

Browse files
[py] Improve ruff linting DX and CI speed (#17588)
- Unify ruff_check.py + ruff_format.py into a single ruff.py that accepts check/format/both modes; eliminates duplicated dirs, excludes, and config references. Adds //py:ruff target for running both at once. - Fix --exit-non-zero-on-fix footgun: ruff_check now exits 0 when all issues are auto-fixed. CI verification mode uses --no-fix explicitly. - Add ruff check to scripts/format.sh (always, not just with --lint), resolving the ruff binary once via --run_under=echo to halve Bazel startup overhead. Auto-fixable lint issues are now committed by the CI bot alongside formatting fixes. - Update py:lint to use --no-fix (pure verification, no side effects). - Split ci-python.yml lint job into parallel lint-ruff / lint-mypy / lint-docs jobs so mypy does not block ruff feedback.
1 parent 50613c2 commit 2963535

7 files changed

Lines changed: 79 additions & 67 deletions

File tree

.github/workflows/ci-python.yml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,29 @@ jobs:
1616
run: |
1717
bazel build //py:selenium-wheel //py:selenium-sdist
1818
19-
lint:
20-
name: Lint
19+
lint-ruff:
20+
name: Lint (ruff)
2121
uses: ./.github/workflows/bazel.yml
2222
with:
23-
name: Lint
24-
run: ./go py:lint
23+
name: Lint (ruff)
24+
run: bazel run //py:ruff-check -- --no-fix
25+
26+
lint-mypy:
27+
name: Lint (mypy)
28+
uses: ./.github/workflows/bazel.yml
29+
with:
30+
name: Lint (mypy)
31+
run: bazel run //py:mypy
32+
33+
lint-docs:
34+
name: Lint (docs)
35+
uses: ./.github/workflows/bazel.yml
36+
with:
37+
name: Lint (docs)
38+
run: |
39+
bazel run //py:generate-api-listing
40+
bazel run //py:sphinx-autogen
41+
bazel build //py:docs
2542
2643
unit-tests:
2744
name: Unit Tests

py/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,11 @@ py_binary(
947947
],
948948
)
949949

950+
alias(
951+
name = "ruff",
952+
actual = "//py/private:ruff",
953+
)
954+
950955
alias(
951956
name = "ruff-check",
952957
actual = "//py/private:ruff_check",

py/private/BUILD.bazel

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,39 @@ py_binary(
2222
visibility = ["//visibility:public"],
2323
)
2424

25+
py_binary(
26+
name = "ruff",
27+
srcs = ["ruff.py"],
28+
data = [
29+
"//py:pyproject.toml",
30+
"@multitool//tools/ruff",
31+
],
32+
visibility = ["//visibility:public"],
33+
deps = ["@rules_python//python/runfiles"],
34+
)
35+
2536
py_binary(
2637
name = "ruff_check",
27-
srcs = ["ruff_check.py"],
38+
srcs = ["ruff.py"],
39+
args = ["check"],
2840
data = [
2941
"//py:pyproject.toml",
3042
"@multitool//tools/ruff",
3143
],
44+
main = "ruff.py",
3245
visibility = ["//visibility:public"],
3346
deps = ["@rules_python//python/runfiles"],
3447
)
3548

3649
py_binary(
3750
name = "ruff_format",
38-
srcs = ["ruff_format.py"],
51+
srcs = ["ruff.py"],
52+
args = ["format"],
3953
data = [
4054
"//py:pyproject.toml",
4155
"@multitool//tools/ruff",
4256
],
57+
main = "ruff.py",
4358
visibility = ["//visibility:public"],
4459
deps = ["@rules_python//python/runfiles"],
4560
)
Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
"""Run ruff format on Python files across the project.
18+
"""Run ruff check and/or format on Python files across the project.
19+
20+
Mode is the first positional argument; remaining args are forwarded to ruff:
21+
check -- ruff check --fix --show-fixes (pass --no-fix for CI verify mode)
22+
format -- ruff format
23+
both -- check then format (default when no mode given)
1924
2025
Usage:
26+
bazel run //py:ruff-check -- [ruff check args]
2127
bazel run //py:ruff-format -- [ruff format args]
28+
bazel run //py:ruff -- [ruff check+format args]
2229
"""
2330

2431
import os
@@ -31,8 +38,12 @@
3138
EXCLUDES = ["**/node_modules/**", "**/.bundle/**", "**/bidi/**", "**/devtools/**"]
3239

3340

41+
def run_check(ruff, exclude_args, dirs, extra_args):
42+
cmd = [ruff, "check", "--fix", "--show-fixes", "--config=py/pyproject.toml"]
43+
return subprocess.run(cmd + exclude_args + dirs + extra_args).returncode
44+
45+
3446
def run_format(ruff, exclude_args, dirs, extra_args):
35-
"""Run ruff format."""
3647
cmd = [ruff, "format", "--config=py/pyproject.toml"]
3748
return subprocess.run(cmd + exclude_args + dirs + extra_args).returncode
3849

@@ -47,4 +58,17 @@ def run_format(ruff, exclude_args, dirs, extra_args):
4758
for pattern in EXCLUDES:
4859
exclude_args.extend(["--exclude", pattern])
4960

50-
sys.exit(run_format(ruff, exclude_args, ALL_DIRS, sys.argv[1:]))
61+
mode = "both"
62+
extra_args = sys.argv[1:]
63+
if extra_args and extra_args[0] in ("check", "format", "both"):
64+
mode = extra_args[0]
65+
extra_args = extra_args[1:]
66+
67+
if mode == "check":
68+
sys.exit(run_check(ruff, exclude_args, ALL_DIRS, extra_args))
69+
elif mode == "format":
70+
sys.exit(run_format(ruff, exclude_args, ALL_DIRS, extra_args))
71+
else:
72+
rc_check = run_check(ruff, exclude_args, ALL_DIRS, extra_args)
73+
rc_format = run_format(ruff, exclude_args, ALL_DIRS, extra_args)
74+
sys.exit(max(rc_check, rc_format))

py/private/ruff_check.py

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

rake_tasks/python.rake

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ task :format do
170170
Bazel.execute('run', [], '//py:ruff-format')
171171
end
172172

173-
desc 'Run Python linters (ruff check, mypy, docs)'
173+
desc 'Run Python linters (ruff check --no-fix, mypy, docs)'
174174
task :lint do
175-
puts ' Running ruff check...'
176-
Bazel.execute('run', [], '//py:ruff-check')
175+
puts ' Running ruff check (verify)...'
176+
Bazel.execute('run', [], '//py:ruff-check', '--', '--no-fix')
177177
puts ' Running mypy...'
178178
Bazel.execute('run', [], '//py:mypy')
179179
Rake::Task['py:docs_generate'].invoke

scripts/format.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,13 @@ fi
119119

120120
if changed_matches '^py/'; then
121121
section "Python"
122-
if [[ "$run_lint" == "true" ]]; then
123-
echo " ruff check" >&2
124-
bazel run //py:ruff-check
125-
fi
122+
RUFF="$(bazel run --run_under=echo @multitool//tools/ruff)"
123+
RUFF_COMMON=(--config=py/pyproject.toml --exclude '**/node_modules/**' --exclude '**/.bundle/**' --exclude '**/bidi/**' --exclude '**/devtools/**' py scripts common dotnet java javascript rb)
124+
echo " ruff check" >&2
125+
# Apply auto-fixable lint issues; don't fail on unfixable violations (caught by py:lint)
126+
"$RUFF" check --fix --show-fixes "${RUFF_COMMON[@]}" || true
126127
echo " ruff format" >&2
127-
bazel run //py:ruff-format
128+
"$RUFF" format "${RUFF_COMMON[@]}"
128129
fi
129130

130131
if changed_matches '^dotnet/'; then

0 commit comments

Comments
 (0)