77import sys
88from fnmatch import fnmatch
99
10- import isort
1110import pytest
1211
1312from . import base , env , utils
1413
15- CI = ("black" , "eslint" , "flake8" , "isort" , "prettier" , "pylint" )
14+ CI = ("black" , "eslint" , "flake8" , "isort" , "prettier" , "pylint" , "ruff" , "ruff-format" )
1615
1716
1817def load_ci_arguments (args ):
@@ -31,6 +30,13 @@ class CIEnvironment(env.Environment):
3130
3231 def _ci_black (self , options , args , paths , ignores ):
3332 """Run black"""
33+ try :
34+ # pylint: disable=C0415,W0611
35+ import black
36+ except ImportError :
37+ utils .error ("black is not installed" )
38+ return 1
39+
3440 cmd = [sys .executable , "-m" , "black" ]
3541
3642 # Replace pattern matching with regex
@@ -75,6 +81,13 @@ def _ci_eslint(self, options, args, paths, ignores):
7581
7682 def _ci_flake8 (self , options , left , paths , ignores ):
7783 """Run flake8 tests"""
84+ try :
85+ # pylint: disable=C0415,E0401,W0611
86+ import flake8
87+ except ImportError :
88+ utils .error ("flake8 is not installed" )
89+ return 1
90+
7891 cmd = [sys .executable , "-m" , "flake8" ]
7992 if ignores :
8093 cmd .append ("--extend-exclude=" + "," .join (ignores ))
@@ -88,6 +101,12 @@ def _ci_flake8(self, options, left, paths, ignores):
88101
89102 def _ci_isort (self , options , args , paths , ignores ):
90103 """Run isort"""
104+ try :
105+ # pylint: disable=C0415,E0401,W0611
106+ import isort
107+ except ImportError :
108+ utils .error ("isort is not installed" )
109+ return 1
91110
92111 cmd = [sys .executable , "-m" , "isort" ]
93112 if not options .fix :
@@ -151,6 +170,13 @@ def _ci_prettier(self, options, args, paths, ignores):
151170
152171 def _ci_pylint (self , options , args , paths , ignores ):
153172 """Run pylint tests for Odoo"""
173+ try :
174+ # pylint: disable=C0415,E0401,W0611
175+ import pylint
176+ except ImportError :
177+ utils .error ("pylint is not installed" )
178+ return 1
179+
154180 files = set ()
155181
156182 extensions = self .get (
@@ -182,6 +208,50 @@ def _ci_pylint(self, options, args, paths, ignores):
182208
183209 return utils .call (* cmd , * args , * files , pipe = False )
184210
211+ def _ci_ruff (self , options , args , paths , ignores ):
212+ try :
213+ # pylint: disable=C0415,E0401,W0611
214+ import ruff
215+ except ImportError :
216+ utils .error ("ruff is not installed" )
217+ return 1
218+
219+ cmd = [
220+ sys .executable ,
221+ "-m" ,
222+ "ruff" ,
223+ "check" ,
224+ "--fix" if options .fix else "--no-fix" ,
225+ "--force-exclude" ,
226+ ]
227+ for pattern in ignores :
228+ cmd += ["--exclude" , pattern ]
229+
230+ return utils .call (* cmd , * args , * paths , pipe = False )
231+
232+ def _ci_ruff_format (self , options , args , paths , ignores ):
233+ try :
234+ # pylint: disable=C0415,E0401,W0611
235+ import ruff
236+ except ImportError :
237+ utils .error ("ruff is not installed" )
238+ return 1
239+
240+ cmd = [
241+ sys .executable ,
242+ "-m" ,
243+ "ruff" ,
244+ "format" ,
245+ "--force-exclude" ,
246+ ]
247+ if not options .fix :
248+ cmd .append ("--check" )
249+
250+ for pattern in ignores :
251+ cmd += ["--exclude" , pattern ]
252+
253+ return utils .call (* cmd , * args , * paths , pipe = False )
254+
185255 def _ci_paths (self ):
186256 return self .get ("odoo" , "addons_path" , default = []) + self .get (
187257 base .SECTION , "ci_path" , default = []
@@ -193,15 +263,17 @@ def ci(self, ci, args=None):
193263
194264 # Always include this script in the tests
195265 ignores = self .get (base .SECTION , "blacklist" , default = [])
196- func = getattr (self , f"_ci_{ ci } " , None )
266+ func = getattr (self , f"_ci_{ ci . replace ( '-' , '_' ) } " , None )
197267 if ci in CI and callable (func ):
268+ # pylint: disable=E1102
198269 return func (args , left , self ._ci_paths (), ignores )
199270
200271 utils .error (f"Unknown CI { ci } " )
201272 return 1
202273
203274 def _install_patches_for_pytest (self ):
204275 """Apply patches for pytest"""
276+ # pylint: disable=C0415
205277 from odoo .tests .common import BaseCase
206278
207279 if hasattr (BaseCase , "run" ):
@@ -227,7 +299,8 @@ def test(self, args=None):
227299 if not self ._init_odoo ():
228300 return False
229301
230- # pylint: disable=C0415,E0401
302+ # pylint: disable=C0415,E0401,W0611
303+ # ruff: noqa: F401
231304 import odoo
232305 from odoo .cli .server import report_configuration
233306 from odoo .tools import config
0 commit comments