Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # coding=utf8 | 1 # coding=utf8 |
| 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 """Commit queue manager class. | 5 """Commit queue manager class. |
| 6 | 6 |
| 7 Security implications: | 7 Security implications: |
| 8 | 8 |
| 9 The following hypothesis are made: | 9 The following hypothesis are made: |
| 10 - Commit queue: | 10 - Commit queue: |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 breakpad.SendStack(e, | 37 breakpad.SendStack(e, |
| 38 ''.join(traceback.format_tb(sys.exc_info()[2])), | 38 ''.join(traceback.format_tb(sys.exc_info()[2])), |
| 39 maxlen=2000) | 39 maxlen=2000) |
| 40 | 40 |
| 41 | 41 |
| 42 class PendingCommit(base.Verified): | 42 class PendingCommit(base.Verified): |
| 43 """Represents a pending commit that is being processed.""" | 43 """Represents a pending commit that is being processed.""" |
| 44 persistent = base.Verified.persistent + [ | 44 persistent = base.Verified.persistent + [ |
| 45 # Important since they tell if we need to revalidate and send try jobs | 45 # Important since they tell if we need to revalidate and send try jobs |
| 46 # again or not if any of these value changes. | 46 # again or not if any of these value changes. |
| 47 'issue', 'patchset', 'rietveld_server', 'processed', 'description', | 47 'issue', 'patchset', 'rietveld_server', 'description', |
| 48 'files', | 48 'files', |
| 49 # Only a cache, these values can be regenerated. | 49 # Only a cache, these values can be regenerated. |
| 50 'owner', 'reviewers', 'base_url', | 50 'owner', 'reviewers', 'base_url', |
| 51 # Only used after a patch was committed. Keeping here for completeness. | 51 # Only used after a patch was committed. Keeping here for completeness. |
| 52 'revision', | 52 'revision', |
| 53 ] | 53 ] |
| 54 | 54 |
| 55 def __init__(self, issue, owner, reviewers, patchset, base_url, description, | 55 def __init__(self, issue, owner, reviewers, patchset, base_url, description, |
| 56 messages, rietveld_server): | 56 messages, rietveld_server): |
| 57 super(PendingCommit, self).__init__() | 57 super(PendingCommit, self).__init__() |
| 58 self.issue = issue | 58 self.issue = issue |
| 59 self.owner = owner | 59 self.owner = owner |
| 60 self.reviewers = reviewers | 60 self.reviewers = reviewers |
| 61 self.patchset = patchset | 61 self.patchset = patchset |
| 62 self.base_url = base_url | 62 self.base_url = base_url |
| 63 self.rietveld_server = rietveld_server | 63 self.rietveld_server = rietveld_server |
| 64 self.description = description | 64 self.description = description |
| 65 self.messages = messages | 65 self.messages = messages |
| 66 self.revision = None | 66 self.revision = None |
| 67 self.processed = False | |
| 68 self.files = [] | 67 self.files = [] |
| 69 | 68 |
| 70 def patch_url(self): | 69 def patch_url(self): |
| 71 return ('%s/download/issue%d_%d.diff' % | 70 return ('%s/download/issue%d_%d.diff' % |
| 72 (self.rietveld_server, self.issue, self.patchset)) | 71 (self.rietveld_server, self.issue, self.patchset)) |
| 73 | 72 |
| 74 def pending_name(self): | 73 def pending_name(self): |
| 75 """The name that should be used for try jobs. | 74 """The name that should be used for try jobs. |
| 76 | 75 |
| 77 It makes it possible to regenerate the try_jobs array if ever needed.""" | 76 It makes it possible to regenerate the try_jobs array if ever needed.""" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 patchset with commit+ flag set. | 132 patchset with commit+ flag set. |
| 134 """ | 133 """ |
| 135 return json.loads(self.rietveld.get( | 134 return json.loads(self.rietveld.get( |
| 136 '/search?format=json&commit=True&closed=False&keys_only=True') | 135 '/search?format=json&commit=True&closed=False&keys_only=True') |
| 137 )['results'] | 136 )['results'] |
| 138 | 137 |
| 139 def process_new_pending_commit(self): | 138 def process_new_pending_commit(self): |
| 140 """Starts verification on newly found pending commits.""" | 139 """Starts verification on newly found pending commits.""" |
| 141 for pending in self.queue.pending_commits[:]: | 140 for pending in self.queue.pending_commits[:]: |
| 142 try: | 141 try: |
| 143 if pending.verifications or pending.processed: | 142 if len(pending.verifications) == len(self.verifiers) or pending.done(): |
|
Dirk Pranke
2011/01/04 22:10:42
Should this check maybe be part of pending.done()
M-A Ruel
2011/01/11 21:07:40
That's a good question.
Since pending doesn't kno
| |
| 144 continue | 143 continue |
| 145 logging.info('Processing issue %s' % pending.issue) | 144 logging.info('Processing issue %s' % pending.issue) |
| 146 pending.processed = True | |
| 147 | 145 |
| 148 if not self._validity_checks(pending): | 146 if not self._validity_checks(pending): |
| 149 # Silently ignore. | 147 # Silently ignore. |
| 150 continue | 148 continue |
| 151 | 149 |
| 152 # The patch is fine to try. | 150 # The patch is fine to try. |
| 153 revision = self.checkout.prepare() | 151 revision = self.checkout.prepare() |
| 154 self._apply_patch(pending, revision) | 152 self._apply_patch(pending, revision) |
| 155 previous_cwd = os.getcwd() | 153 previous_cwd = os.getcwd() |
| 156 try: | 154 try: |
| 157 os.chdir(self.checkout.project_path) | 155 os.chdir(self.checkout.project_path) |
| 158 for verifier in self.verifiers: | 156 for verifier in self.verifiers: |
| 159 verifier.verify(pending, revision) | 157 verifier.verify(pending, revision) |
| 158 if pending.done(): | |
| 159 break | |
| 160 finally: | 160 finally: |
| 161 os.chdir(previous_cwd) | 161 os.chdir(previous_cwd) |
| 162 except base.DiscardPending, e: | 162 except base.DiscardPending, e: |
| 163 self._discard_pending(e.pending, e.message) | 163 self._discard_pending(e.pending, e.message) |
| 164 except Exception, e: | 164 except Exception, e: |
| 165 # Swallow every exception in that code and move on. Make sure to send a | 165 # Swallow every exception in that code and move on. Make sure to send a |
| 166 # stack trace though. | 166 # stack trace though. |
| 167 send_stack(e) | 167 send_stack(e) |
| 168 | 168 |
| 169 def update_status(self): | 169 def update_status(self): |
| 170 """Updates the status for each pending commit verifier.""" | 170 """Updates the status for each pending commit verifier.""" |
| 171 for verifier in self.verifiers: | 171 for verifier in self.verifiers: |
| 172 try: | 172 try: |
| 173 verifier.update_status(self.queue.pending_commits) | 173 verifier.update_status(self.queue.pending_commits) |
| 174 except base.DiscardPending, e: | 174 except base.DiscardPending, e: |
| 175 # It's not efficient since it takes a full loop for each pending commit | 175 # It's not efficient since it takes a full loop for each pending commit |
| 176 # to discard. | 176 # to discard. |
| 177 self._discard_pending(e.pending, e.message) | 177 self._discard_pending(e.pending, e.message) |
| 178 except Exception, e: | 178 except Exception, e: |
| 179 # Swallow every exception in that code and move on. Make sure to send a | 179 # Swallow every exception in that code and move on. Make sure to send a |
| 180 # stack trace though. | 180 # stack trace though. |
| 181 send_stack(e) | 181 send_stack(e) |
| 182 | 182 |
| 183 def scan_results(self): | 183 def scan_results(self): |
| 184 """Scans pending commits that can be committed or discarded.""" | 184 """Scans pending commits that can be committed or discarded.""" |
| 185 for pending in self.queue.pending_commits[:]: | 185 for pending in self.queue.pending_commits[:]: |
| 186 if pending.failed(): | 186 if pending.ignored(): |
| 187 self._discard_pending(pending, None) | |
| 188 elif pending.failed(): | |
| 187 self._discard_pending(pending, 'Patch verification failed') | 189 self._discard_pending(pending, 'Patch verification failed') |
| 188 elif pending.succeeded(): | 190 elif pending.succeeded(): |
| 189 # The item is removed right away. | 191 # The item is removed right away. |
| 190 self.queue.pending_commits.remove(pending) | 192 self.queue.pending_commits.remove(pending) |
| 191 try: | 193 try: |
| 192 self._last_minute_checks(pending) | 194 self._last_minute_checks(pending) |
| 193 commit_message = '%s\n\nReview URL: %s/%s' % ( | 195 commit_message = '%s\n\nReview URL: %s/%s' % ( |
| 194 pending.description, | 196 pending.description, |
| 195 pending.rietveld_server, | 197 pending.rietveld_server, |
| 196 pending.issue) | 198 pending.issue) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 'Patch failed to apply against %s.' % revision) | 275 'Patch failed to apply against %s.' % revision) |
| 274 | 276 |
| 275 def load(self, filename): | 277 def load(self, filename): |
| 276 """Loads the commit queue state from a JSON file.""" | 278 """Loads the commit queue state from a JSON file.""" |
| 277 self.queue = model.load_from_json_file(filename) | 279 self.queue = model.load_from_json_file(filename) |
| 278 self.queue.pending_commits = self.queue.pending_commits or [] | 280 self.queue.pending_commits = self.queue.pending_commits or [] |
| 279 | 281 |
| 280 def save(self, filename): | 282 def save(self, filename): |
| 281 """Save the commit queue state in a simple JSON file.""" | 283 """Save the commit queue state in a simple JSON file.""" |
| 282 model.save_to_json_file(filename, self.queue) | 284 model.save_to_json_file(filename, self.queue) |
| OLD | NEW |