@@ -87,34 +87,22 @@ class MyCase(TestCase):
87
87
88
88
class ComplianceTest :
89
89
"""
90
- Main Test class
90
+ Base class for tests. Inheriting classes should have a run() method and set
91
+ these class variables:
91
92
92
- """
93
-
94
- _name = ""
95
- _title = ""
96
- _doc = "https://docs.zephyrproject.org/latest/contribute/"
93
+ name:
94
+ Test name
97
95
98
- def __init__ (self , suite , commit_range ):
99
- self .case = None
100
- self .suite = suite
101
- self .commit_range = commit_range
102
- # get() defaults to None if not present
96
+ doc:
97
+ Link to documentation related to what's being tested
103
98
104
- def prepare ( self , where ) :
105
- """
106
- Prepare test case
107
- :return:
108
- """
109
- self .case = MyCase (self ._name )
99
+ path_hint :
100
+ The path the test runs itself in. This is just informative and used in
101
+ the message that gets printed when running the test.
102
+ """
103
+ def __init__ ( self ):
104
+ self .case = MyCase (self .name )
110
105
self .case .classname = "Guidelines"
111
- print ("Running {:16} tests in {} ..." .format (self ._name , where ))
112
-
113
- def run (self ):
114
- """
115
- Run testcase
116
- :return:
117
- """
118
106
119
107
def error (self , msg ):
120
108
"""
@@ -159,7 +147,7 @@ def add_failure(self, msg):
159
147
"""
160
148
if not self .case .result :
161
149
# First reported failure
162
- self .case .result = Failure (self ._name + " issues" , "failure" )
150
+ self .case .result = Failure (self .name + " issues" , "failure" )
163
151
self .case .result ._elem .text = msg .rstrip ()
164
152
else :
165
153
# If there are multiple Failures, concatenate their messages
@@ -201,19 +189,19 @@ class CheckPatch(ComplianceTest):
201
189
Runs checkpatch and reports found issues
202
190
203
191
"""
204
- _name = "checkpatch"
205
- _doc = "https://docs.zephyrproject.org/latest/contribute/#coding-style"
192
+ name = "checkpatch"
193
+ doc = "https://docs.zephyrproject.org/latest/contribute/#coding-style"
194
+ path_hint = GIT_TOP
206
195
207
196
def run (self ):
208
- self .prepare (GIT_TOP )
209
197
# Default to Zephyr's checkpatch if ZEPHYR_BASE is set
210
198
checkpatch = os .path .join (ZEPHYR_BASE or GIT_TOP , 'scripts' ,
211
199
'checkpatch.pl' )
212
200
if not os .path .exists (checkpatch ):
213
201
self .skip (checkpatch + " not found" )
214
202
215
203
# git diff's output doesn't depend on the current (sub)directory
216
- diff = subprocess .Popen (('git' , 'diff' , '%s' % ( self . commit_range ) ),
204
+ diff = subprocess .Popen (('git' , 'diff' , COMMIT_RANGE ),
217
205
stdout = subprocess .PIPE )
218
206
try :
219
207
subprocess .check_output ((checkpatch , '--mailback' , '--no-tree' , '-' ),
@@ -235,12 +223,11 @@ class KconfigCheck(ComplianceTest):
235
223
Checks is we are introducing any new warnings/errors with Kconfig,
236
224
for example using undefiend Kconfig variables.
237
225
"""
238
- _name = "Kconfig"
239
- _doc = "https://docs.zephyrproject.org/latest/guides/kconfig/index.html"
226
+ name = "Kconfig"
227
+ doc = "https://docs.zephyrproject.org/latest/guides/kconfig/index.html"
228
+ path_hint = ZEPHYR_BASE
240
229
241
230
def run (self ):
242
- self .prepare (ZEPHYR_BASE )
243
-
244
231
kconf = self .parse_kconfig ()
245
232
246
233
self .check_top_menu_not_too_long (kconf )
@@ -500,11 +487,11 @@ class DeviceTreeCheck(ComplianceTest):
500
487
"""
501
488
Runs the dtlib and edtlib test suites in scripts/dts/.
502
489
"""
503
- _name = "Device tree"
504
- _doc = "https://docs.zephyrproject.org/latest/guides/dts/index.html"
490
+ name = "Device tree"
491
+ doc = "https://docs.zephyrproject.org/latest/guides/dts/index.html"
492
+ path_hint = ZEPHYR_BASE
505
493
506
494
def run (self ):
507
- self .prepare (ZEPHYR_BASE )
508
495
if not ZEPHYR_BASE :
509
496
self .skip ("Not a Zephyr tree (ZEPHYR_BASE unset)" )
510
497
@@ -542,8 +529,9 @@ class Codeowners(ComplianceTest):
542
529
"""
543
530
Check if added files have an owner.
544
531
"""
545
- _name = "Codeowners"
546
- _doc = "https://help.github.com/articles/about-code-owners/"
532
+ name = "Codeowners"
533
+ doc = "https://help.github.com/articles/about-code-owners/"
534
+ path_hint = GIT_TOP
547
535
548
536
def ls_owned_files (self , codeowners ):
549
537
"""Returns an OrderedDict mapping git patterns from the CODEOWNERS file
@@ -610,7 +598,6 @@ def git_pattern_to_glob(self, git_pattern):
610
598
return ret
611
599
612
600
def run (self ):
613
- self .prepare (GIT_TOP )
614
601
# TODO: testing an old self.commit range that doesn't end
615
602
# with HEAD is most likely a mistake. Should warn, see
616
603
# https://github.com/zephyrproject-rtos/ci-tools/pull/24
@@ -619,9 +606,9 @@ def run(self):
619
606
self .skip ("CODEOWNERS not available in this repo" )
620
607
621
608
name_changes = git ("diff" , "--name-only" , "--diff-filter=ARCD" ,
622
- self . commit_range )
609
+ COMMIT_RANGE )
623
610
624
- owners_changes = git ("diff" , "--name-only" , self . commit_range ,
611
+ owners_changes = git ("diff" , "--name-only" , COMMIT_RANGE ,
625
612
"--" , codeowners )
626
613
627
614
if not name_changes and not owners_changes :
@@ -637,7 +624,7 @@ def run(self):
637
624
# however if one is missed then it will always be reported as an
638
625
# Addition instead.
639
626
new_files = git ("diff" , "--name-only" , "--diff-filter=ARC" ,
640
- self . commit_range ).splitlines ()
627
+ COMMIT_RANGE ).splitlines ()
641
628
logging .debug ("New files %s" , new_files )
642
629
643
630
# Convert to pathlib.Path string representation (e.g.,
@@ -674,14 +661,13 @@ class Documentation(ComplianceTest):
674
661
Checks if documentation build has generated any new warnings.
675
662
676
663
"""
677
- _name = "Documentation"
678
- _doc = "https://docs.zephyrproject.org/latest/guides/documentation/index.html"
664
+ name = "Documentation"
665
+ doc = "https://docs.zephyrproject.org/latest/guides/documentation/index.html"
666
+ path_hint = os .getcwd ()
679
667
680
668
DOCS_WARNING_FILE = "doc.warnings"
681
669
682
670
def run (self ):
683
- self .prepare (os .getcwd ())
684
-
685
671
if os .path .exists (self .DOCS_WARNING_FILE ) and os .path .getsize (self .DOCS_WARNING_FILE ) > 0 :
686
672
with open (self .DOCS_WARNING_FILE , "rb" ) as docs_warning :
687
673
self .add_failure (docs_warning .read ().decode ("utf-8" ))
@@ -692,15 +678,14 @@ class GitLint(ComplianceTest):
692
678
Runs gitlint on the commits and finds issues with style and syntax
693
679
694
680
"""
695
- _name = "Gitlint"
696
- _doc = "https://docs.zephyrproject.org/latest/contribute/#commit-guidelines"
681
+ name = "Gitlint"
682
+ doc = "https://docs.zephyrproject.org/latest/contribute/#commit-guidelines"
683
+ path_hint = GIT_TOP
697
684
698
685
def run (self ):
699
- self .prepare (GIT_TOP )
700
-
701
686
# By default gitlint looks for .gitlint configuration only in
702
687
# the current directory
703
- proc = subprocess .Popen ('gitlint --commits %s' % ( self . commit_range ) ,
688
+ proc = subprocess .Popen ('gitlint --commits ' + COMMIT_RANGE ,
704
689
stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
705
690
shell = True , cwd = GIT_TOP )
706
691
@@ -717,18 +702,17 @@ class PyLint(ComplianceTest):
717
702
Runs pylint on all .py files, with a limited set of checks enabled. The
718
703
configuration is in the pylintrc file.
719
704
"""
720
- _name = "pylint"
721
- _doc = "https://www.pylint.org/"
705
+ name = "pylint"
706
+ doc = "https://www.pylint.org/"
707
+ path_hint = GIT_TOP
722
708
723
709
def run (self ):
724
- self .prepare (GIT_TOP )
725
-
726
710
# Path to pylint configuration file
727
711
pylintrc = os .path .join (os .path .dirname (__file__ ), "pylintrc" )
728
712
729
713
# List of files added/modified by the commit(s).
730
714
files = git (
731
- "diff" , "--name-only" , "--diff-filter=d" , self . commit_range , "--" ,
715
+ "diff" , "--name-only" , "--diff-filter=d" , COMMIT_RANGE , "--" ,
732
716
# Skip to work around crash in pylint 2.2.2:
733
717
# https://github.com/PyCQA/pylint/issues/2906
734
718
":!boards/xtensa/intel_s1000_crb/support/create_board_img.py" ) \
@@ -780,21 +764,20 @@ class License(ComplianceTest):
780
764
Checks for licenses in new files added by the Pull request
781
765
782
766
"""
783
- _name = "License"
784
- _doc = "https://docs.zephyrproject.org/latest/contribute/#licensing"
767
+ name = "License"
768
+ doc = "https://docs.zephyrproject.org/latest/contribute/#licensing"
769
+ # copyfile() below likely requires that getcwd()==GIT_TOP
770
+ path_hint = os .getcwd ()
785
771
786
772
def run (self ):
787
- # copyfile() below likely requires that getcwd()==GIT_TOP
788
- self .prepare (os .getcwd ())
789
-
790
773
scancode = "/opt/scancode-toolkit/scancode"
791
774
if not os .path .exists (scancode ):
792
775
self .skip ("scancode-toolkit not installed" )
793
776
794
777
os .makedirs ("scancode-files" , exist_ok = True )
795
778
# git diff's output doesn't depend on the current (sub)directory
796
779
new_files = git ("diff" , "--name-only" , "--diff-filter=A" ,
797
- self . commit_range ).splitlines ()
780
+ COMMIT_RANGE ).splitlines ()
798
781
799
782
if not new_files :
800
783
return
@@ -881,15 +864,14 @@ class Identity(ComplianceTest):
881
864
"""
882
865
Checks if Emails of author and signed-off messages are consistent.
883
866
"""
884
- _name = "Identity/Emails"
885
- _doc = "https://docs.zephyrproject.org/latest/contribute/#commit-guidelines"
867
+ name = "Identity/Emails"
868
+ doc = "https://docs.zephyrproject.org/latest/contribute/#commit-guidelines"
869
+ # git rev-list and git log don't depend on the current (sub)directory
870
+ # unless explicited
871
+ path_hint = GIT_TOP
886
872
887
873
def run (self ):
888
- # git rev-list and git log don't depend on the current
889
- # (sub)directory unless explicited.
890
- self .prepare (GIT_TOP )
891
-
892
- for shaidx in get_shas (self .commit_range ):
874
+ for shaidx in get_shas (COMMIT_RANGE ):
893
875
commit = git ("log" , "--decorate=short" , "-n 1" , shaidx )
894
876
signed = []
895
877
author = ""
@@ -951,11 +933,11 @@ def set_pending():
951
933
# Sets 'pending' status for all tests for the commit given by --sha
952
934
953
935
for testcase in ComplianceTest .__subclasses__ ():
954
- print ("Creating pending status for " + testcase ._name )
936
+ print ("Creating pending status for " + testcase .name )
955
937
github_commit .create_status (
956
- 'pending' , testcase ._doc ,
938
+ 'pending' , testcase .doc ,
957
939
'Run in progress (build no. {})' .format (build_number ),
958
- testcase ._name )
940
+ testcase .name )
959
941
960
942
def report_test_results_to_github (suite ):
961
943
# Reports test results to Github.
@@ -964,7 +946,7 @@ def report_test_results_to_github(suite):
964
946
965
947
print ("reporting results to GitHub" )
966
948
967
- name2doc = {testcase ._name : testcase ._doc
949
+ name2doc = {testcase .name : testcase .doc
968
950
for testcase in ComplianceTest .__subclasses__ ()}
969
951
970
952
n_failures = 0
@@ -1170,20 +1152,21 @@ def _main(args):
1170
1152
# The "real" main(), which is wrapped to catch exceptions and report them
1171
1153
# to GitHub. Returns the number of test failures.
1172
1154
1155
+ # The commit range passed in --commit, e.g. "HEAD~3"
1156
+ global COMMIT_RANGE
1157
+ COMMIT_RANGE = args .commits
1158
+
1173
1159
init_logs (args .loglevel )
1174
1160
1175
1161
if args .list :
1176
1162
for testcase in ComplianceTest .__subclasses__ ():
1177
- print (testcase ._name )
1163
+ print (testcase .name )
1178
1164
return 0
1179
1165
1180
1166
if args .status :
1181
1167
set_pending ()
1182
1168
return 0
1183
1169
1184
- if not args .commits :
1185
- err ("No commit range given" )
1186
-
1187
1170
# Load saved test results from an earlier run, if requested
1188
1171
if args .previous_run :
1189
1172
if not os .path .exists (args .previous_run ):
@@ -1204,15 +1187,21 @@ def _main(args):
1204
1187
suite = TestSuite ("Compliance" )
1205
1188
1206
1189
for testcase in ComplianceTest .__subclasses__ ():
1207
- test = testcase (suite , args .commits )
1208
- if args .module :
1209
- if test ._name not in args .module :
1210
- continue
1211
- elif test ._name in args .exclude_module :
1212
- print ("Skipping " + test ._name )
1190
+ # "Modules" and "testcases" are the same thing. Better flags would have
1191
+ # been --tests and --exclude-tests or the like, but it's awkward to
1192
+ # change now.
1193
+
1194
+ if args .module and testcase .name not in args .module :
1195
+ continue
1196
+
1197
+ if testcase .name in args .exclude_module :
1198
+ print ("Skipping " + testcase .name )
1213
1199
continue
1214
1200
1201
+ test = testcase ()
1215
1202
try :
1203
+ print ("Running {:16} tests in {} ..."
1204
+ .format (test .name , test .path_hint ))
1216
1205
test .run ()
1217
1206
except EndTest :
1218
1207
pass
0 commit comments