Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: presubmit_support.py

Issue 6719004: refactor parsing of change descriptions, fix TBR= (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: remove TestableChangeDescription; the base class is already testable Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2010 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 """Enables directory-specific presubmit checks to run at upload and/or commit. 6 """Enables directory-specific presubmit checks to run at upload and/or commit.
7 """ 7 """
8 8
9 __version__ = '1.4' 9 __version__ = '1.4'
10 10
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 805
806 806
807 class GitChange(Change): 807 class GitChange(Change):
808 _AFFECTED_FILES = GitAffectedFile 808 _AFFECTED_FILES = GitAffectedFile
809 809
810 def __init__(self, *args, **kwargs): 810 def __init__(self, *args, **kwargs):
811 Change.__init__(self, *args, **kwargs) 811 Change.__init__(self, *args, **kwargs)
812 self.scm = 'git' 812 self.scm = 'git'
813 813
814 814
815 class ChangeDescription(object):
M-A Ruel 2011/03/22 17:24:16 It's a slightly odd location for this class but it
816 """Contains a parsed form of the change description."""
817 MAX_SUBJECT_LENGTH = 100
818
819 def __init__(self, subject=None, description=None, reviewers=None, tbr=False,
820 editor=None):
821 self.subject = (subject or '').strip()
822 self.description = (description or '').strip()
823 self.reviewers = reviewers or []
824 self.tbr = tbr
825 self.editor = editor or gclient_utils.UserEdit
826
827 if self.description:
828 if not self.description.startswith(self.subject):
829 self.description = self.subject + '\n\n' + self.description
830 elif self.subject:
831 self.description = self.subject
832 self.Parse(self.EditableDescription())
833
834 def EditableDescription(self):
835 text = self.description.strip()
836 if text:
837 text += '\n'
838
839 tbr_present = False
840 r_present = False
841 bug_present = False
842 test_present = False
843 for l in text.splitlines():
844 l = l.strip()
845 r_present = r_present or l.startswith('R=')
846 tbr_present = tbr_present or l.startswith('TBR=')
847
848 if text and not (r_present or tbr_present):
849 text += '\n'
850
851 if not tbr_present and not r_present:
852 if self.tbr:
853 text += 'TBR=' + ','.join(self.reviewers) + '\n'
854 else:
855 text += 'R=' + ','.join(self.reviewers) + '\n'
856 if not bug_present:
857 text += 'BUG=\n'
858 if not test_present:
859 text += 'TEST=\n'
860
861 return text
862
863 def UserEdit(self):
864 """Allows the user to update the description.
865
866 Uses the editor callback passed to the constructor."""
867 self.Parse(self.editor(self.EditableDescription()))
868
869 def Parse(self, text):
870 """Parse the text returned from UserEdit() and update our state."""
871 parsed_lines = []
872 reviewers_regexp = re.compile('\s*(TBR|R)=(.+)')
873 reviewers = []
874 subject = ''
875 tbr = False
876 for l in text.splitlines():
877 l = l.strip()
878
879 # Throw away empty BUG=, TEST=, and R= lines. We leave in TBR= lines
880 # to indicate that this change was meant to be "unreviewed".
881 if l in ('BUG=', 'TEST=', 'R='):
882 continue
883
884 if not subject:
885 subject = l
886 matched_reviewers = reviewers_regexp.match(l)
887 if matched_reviewers:
888 tbr = (matched_reviewers.group(1) == 'TBR')
889 reviewers.extend(matched_reviewers.group(2).split(','))
890 parsed_lines.append(l)
891
892 if len(subject) > self.MAX_SUBJECT_LENGTH:
893 subject = subject[:self.MAX_SUBJECT_LENGTH - 3] + '...'
894
895 self.description = '\n'.join(parsed_lines).strip()
896 self.subject = subject
897 self.reviewers = reviewers
898 self.tbr = tbr
899
900 def IsEmpty(self):
901 return not self.description
902
903
904
815 def ListRelevantPresubmitFiles(files, root): 905 def ListRelevantPresubmitFiles(files, root):
816 """Finds all presubmit files that apply to a given set of source files. 906 """Finds all presubmit files that apply to a given set of source files.
817 907
818 If inherit-review-settings-ok is present right under root, looks for 908 If inherit-review-settings-ok is present right under root, looks for
819 PRESUBMIT.py in directories enclosing root. 909 PRESUBMIT.py in directories enclosing root.
820 910
821 Args: 911 Args:
822 files: An iterable container containing file paths. 912 files: An iterable container containing file paths.
823 root: Path where to stop searching. 913 root: Path where to stop searching.
824 914
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
1186 options.verbose, 1276 options.verbose,
1187 sys.stdout, 1277 sys.stdout,
1188 sys.stdin, 1278 sys.stdin,
1189 options.default_presubmit, 1279 options.default_presubmit,
1190 options.may_prompt) 1280 options.may_prompt)
1191 return not results.should_continue() 1281 return not results.should_continue()
1192 1282
1193 1283
1194 if __name__ == '__main__': 1284 if __name__ == '__main__':
1195 sys.exit(Main(None)) 1285 sys.exit(Main(None))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698