| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Generic presubmit checks that can be reused by other presubmit checks.""" | 6 """Generic presubmit checks that can be reused by other presubmit checks.""" |
| 7 | 7 |
| 8 | 8 |
| 9 ### Description checks |
| 10 |
| 9 def CheckChangeHasTestField(input_api, output_api): | 11 def CheckChangeHasTestField(input_api, output_api): |
| 10 """Requires that the changelist have a TEST= field.""" | 12 """Requires that the changelist have a TEST= field.""" |
| 11 if input_api.change.TEST: | 13 if input_api.change.TEST: |
| 12 return [] | 14 return [] |
| 13 else: | 15 else: |
| 14 return [output_api.PresubmitNotifyResult( | 16 return [output_api.PresubmitNotifyResult( |
| 15 "Changelist should have a TEST= field. TEST=none is allowed.")] | 17 "Changelist should have a TEST= field. TEST=none is allowed.")] |
| 16 | 18 |
| 17 | 19 |
| 18 def CheckChangeHasBugField(input_api, output_api): | 20 def CheckChangeHasBugField(input_api, output_api): |
| (...skipping 25 matching lines...) Expand all Loading... |
| 44 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to the CL description. | 46 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to the CL description. |
| 45 """ | 47 """ |
| 46 keyword = 'DO NOT ' + 'SUBMIT' | 48 keyword = 'DO NOT ' + 'SUBMIT' |
| 47 if keyword in input_api.change.DescriptionText(): | 49 if keyword in input_api.change.DescriptionText(): |
| 48 return [output_api.PresubmitError( | 50 return [output_api.PresubmitError( |
| 49 keyword + " is present in the changelist description.")] | 51 keyword + " is present in the changelist description.")] |
| 50 else: | 52 else: |
| 51 return [] | 53 return [] |
| 52 | 54 |
| 53 | 55 |
| 56 ### Content checks |
| 57 |
| 54 def CheckDoNotSubmitInFiles(input_api, output_api): | 58 def CheckDoNotSubmitInFiles(input_api, output_api): |
| 55 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to any files.""" | 59 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to any files.""" |
| 56 keyword = 'DO NOT ' + 'SUBMIT' | 60 keyword = 'DO NOT ' + 'SUBMIT' |
| 57 for f, line_num, line in input_api.RightHandSideLines(): | 61 # We want to check every text files, not just source files. |
| 62 for f, line_num, line in input_api.RightHandSideLines(lambda x: x): |
| 58 if keyword in line: | 63 if keyword in line: |
| 59 text = 'Found ' + keyword + ' in %s, line %s' % (f.LocalPath(), line_num) | 64 text = 'Found ' + keyword + ' in %s, line %s' % (f.LocalPath(), line_num) |
| 60 return [output_api.PresubmitError(text)] | 65 return [output_api.PresubmitError(text)] |
| 61 return [] | 66 return [] |
| 62 | 67 |
| 63 | 68 |
| 64 def CheckDoNotSubmit(input_api, output_api): | 69 def CheckChangeHasNoCR(input_api, output_api, source_file_filter=None): |
| 65 return ( | |
| 66 CheckDoNotSubmitInDescription(input_api, output_api) + | |
| 67 CheckDoNotSubmitInFiles(input_api, output_api) | |
| 68 ) | |
| 69 | |
| 70 | |
| 71 def CheckChangeHasNoCR(input_api, output_api): | |
| 72 """Checks that there are no \r, \r\n (CR or CRLF) characters in any of the | 70 """Checks that there are no \r, \r\n (CR or CRLF) characters in any of the |
| 73 text files to be submitted. | 71 source files to be submitted. |
| 74 """ | 72 """ |
| 75 outputs = [] | 73 outputs = [] |
| 76 for f in input_api.AffectedTextFiles(): | 74 for f in input_api.AffectedSourceFiles(source_file_filter): |
| 77 if '\r' in input_api.ReadFile(f, 'rb'): | 75 if '\r' in input_api.ReadFile(f, 'rb'): |
| 78 outputs.append(output_api.PresubmitPromptWarning( | 76 outputs.append(output_api.PresubmitPromptWarning( |
| 79 "Found a CR character in %s" % f.LocalPath())) | 77 "Found a CR character in %s" % f.LocalPath())) |
| 80 return outputs | 78 return outputs |
| 81 | 79 |
| 82 | 80 |
| 83 def CheckChangeHasNoTabs(input_api, output_api): | 81 def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None): |
| 84 """Checks that there are no tab characters in any of the text files to be | 82 """Checks that there are no tab characters in any of the text files to be |
| 85 submitted. | 83 submitted. |
| 86 """ | 84 """ |
| 87 for f, line_num, line in input_api.RightHandSideLines(): | 85 for f, line_num, line in input_api.RightHandSideLines(source_file_filter): |
| 88 if '\t' in line: | 86 if '\t' in line: |
| 89 return [output_api.PresubmitPromptWarning( | 87 return [output_api.PresubmitPromptWarning( |
| 90 "Found a tab character in %s, line %s" % | 88 "Found a tab character in %s, line %s" % |
| 91 (f.LocalPath(), line_num))] | 89 (f.LocalPath(), line_num))] |
| 92 return [] | 90 return [] |
| 93 | 91 |
| 94 | 92 |
| 95 def CheckLongLines(input_api, output_api, maxlen=80): | 93 def CheckLongLines(input_api, output_api, maxlen=80, source_file_filter=None): |
| 96 """Checks that there aren't any lines longer than maxlen characters in any of | 94 """Checks that there aren't any lines longer than maxlen characters in any of |
| 97 the text files to be submitted. | 95 the text files to be submitted. |
| 98 """ | 96 """ |
| 99 bad = [] | 97 bad = [] |
| 100 for f, line_num, line in input_api.RightHandSideLines(): | 98 for f, line_num, line in input_api.RightHandSideLines(source_file_filter): |
| 101 # Allow lines with http://, https:// and #define/#pragma/#include/#if/#endif | 99 # Allow lines with http://, https:// and #define/#pragma/#include/#if/#endif |
| 102 # to exceed the maxlen rule. | 100 # to exceed the maxlen rule. |
| 103 if (len(line) > maxlen and | 101 if (len(line) > maxlen and |
| 104 not 'http://' in line and | 102 not 'http://' in line and |
| 105 not 'https://' in line and | 103 not 'https://' in line and |
| 106 not line.startswith('#define') and | 104 not line.startswith('#define') and |
| 107 not line.startswith('#include') and | 105 not line.startswith('#include') and |
| 108 not line.startswith('#pragma') and | 106 not line.startswith('#pragma') and |
| 109 not line.startswith('#if') and | 107 not line.startswith('#if') and |
| 110 not line.startswith('#endif')): | 108 not line.startswith('#endif')): |
| 111 bad.append( | 109 bad.append( |
| 112 '%s, line %s, %s chars' % | 110 '%s, line %s, %s chars' % |
| 113 (f.LocalPath(), line_num, len(line))) | 111 (f.LocalPath(), line_num, len(line))) |
| 114 if len(bad) == 5: # Just show the first 5 errors. | 112 if len(bad) == 5: # Just show the first 5 errors. |
| 115 break | 113 break |
| 116 | 114 |
| 117 if bad: | 115 if bad: |
| 118 msg = "Found lines longer than %s characters (first 5 shown)." % maxlen | 116 msg = "Found lines longer than %s characters (first 5 shown)." % maxlen |
| 119 return [output_api.PresubmitPromptWarning(msg, items=bad)] | 117 return [output_api.PresubmitPromptWarning(msg, items=bad)] |
| 120 else: | 118 else: |
| 121 return [] | 119 return [] |
| 122 | 120 |
| 123 | 121 |
| 122 ### Other checks |
| 123 |
| 124 def CheckDoNotSubmit(input_api, output_api): |
| 125 return ( |
| 126 CheckDoNotSubmitInDescription(input_api, output_api) + |
| 127 CheckDoNotSubmitInFiles(input_api, output_api) |
| 128 ) |
| 129 |
| 130 |
| 124 def CheckTreeIsOpen(input_api, output_api, url, closed): | 131 def CheckTreeIsOpen(input_api, output_api, url, closed): |
| 125 """Checks that an url's content doesn't match a regexp that would mean that | 132 """Checks that an url's content doesn't match a regexp that would mean that |
| 126 the tree is closed.""" | 133 the tree is closed.""" |
| 127 assert(input_api.is_committing) | 134 assert(input_api.is_committing) |
| 128 try: | 135 try: |
| 129 connection = input_api.urllib2.urlopen(url) | 136 connection = input_api.urllib2.urlopen(url) |
| 130 status = connection.read() | 137 status = connection.read() |
| 131 connection.close() | 138 connection.close() |
| 132 if input_api.re.match(closed, status): | 139 if input_api.re.match(closed, status): |
| 133 long_text = status + '\n' + url | 140 long_text = status + '\n' + url |
| 134 return [output_api.PresubmitPromptWarning("The tree is closed.", | 141 return [output_api.PresubmitPromptWarning("The tree is closed.", |
| 135 long_text=long_text)] | 142 long_text=long_text)] |
| 136 except IOError: | 143 except IOError: |
| 137 pass | 144 pass |
| 138 return [] | 145 return [] |
| 139 | 146 |
| 140 | 147 |
| 141 def _RunPythonUnitTests_LoadTests(input_api, module_name): | 148 def _RunPythonUnitTests_LoadTests(input_api, module_name): |
| 142 """Meant to be stubbed out during unit testing.""" | 149 """Meant to be stubbed out during unit testing.""" |
| 143 module = __import__(module_name) | 150 module = __import__(module_name) |
| 144 for part in module_name.split('.')[1:]: | 151 for part in module_name.split('.')[1:]: |
| 145 module = getattr(module, part) | 152 module = getattr(module, part) |
| 146 return input_api.unittest.TestLoader().loadTestsFromModule(module)._tests | 153 return input_api.unittest.TestLoader().loadTestsFromModule(module)._tests |
| 147 | 154 |
| 155 |
| 148 def RunPythonUnitTests(input_api, output_api, unit_tests): | 156 def RunPythonUnitTests(input_api, output_api, unit_tests): |
| 149 """Imports the unit_tests modules and run them.""" | 157 """Imports the unit_tests modules and run them.""" |
| 150 # We don't want to hinder users from uploading incomplete patches. | 158 # We don't want to hinder users from uploading incomplete patches. |
| 151 if input_api.is_committing: | 159 if input_api.is_committing: |
| 152 message_type = output_api.PresubmitError | 160 message_type = output_api.PresubmitError |
| 153 else: | 161 else: |
| 154 message_type = output_api.PresubmitNotifyResult | 162 message_type = output_api.PresubmitNotifyResult |
| 155 tests_suite = [] | 163 tests_suite = [] |
| 156 outputs = [] | 164 outputs = [] |
| 157 for unit_test in unit_tests: | 165 for unit_test in unit_tests: |
| 158 try: | 166 try: |
| 159 tests_suite.extend(_RunPythonUnitTests_LoadTests(input_api, unit_test)) | 167 tests_suite.extend(_RunPythonUnitTests_LoadTests(input_api, unit_test)) |
| 160 except ImportError: | 168 except ImportError: |
| 161 outputs.append(message_type("Failed to load %s" % unit_test, | 169 outputs.append(message_type("Failed to load %s" % unit_test, |
| 162 long_text=input_api.traceback.format_exc())) | 170 long_text=input_api.traceback.format_exc())) |
| 163 | 171 |
| 164 results = input_api.unittest.TextTestRunner(verbosity=0).run( | 172 results = input_api.unittest.TextTestRunner(verbosity=0).run( |
| 165 input_api.unittest.TestSuite(tests_suite)) | 173 input_api.unittest.TestSuite(tests_suite)) |
| 166 if not results.wasSuccessful(): | 174 if not results.wasSuccessful(): |
| 167 outputs.append(message_type("%d unit tests failed." % | 175 outputs.append(message_type("%d unit tests failed." % |
| 168 (len(results.failures) + len(results.errors)))) | 176 (len(results.failures) + len(results.errors)))) |
| 169 return outputs | 177 return outputs |
| OLD | NEW |