def test_update_reviewers(self): data = [ ('foo', [], 'foo'), ('foo\nR=xx', [], 'foo\nR=xx'), ('foo\nTBR=xx', [], 'foo\nTBR=xx'), ('foo', ['a@c'], 'foo\n\nR=a@c'), ('foo\nR=xx', ['a@c'], 'foo\n\nR=a@c, xx'), ('foo\nTBR=xx', ['a@c'], 'foo\n\nR=a@c\nTBR=xx'), ('foo\nTBR=xx\nR=yy', ['a@c'], 'foo\n\nR=a@c, yy\nTBR=xx'), ('foo\nBUG=', ['a@c'], 'foo\nBUG=\nR=a@c'), ('foo\nR=xx\nTBR=yy\nR=bar', ['a@c'], 'foo\n\nR=a@c, xx, bar\nTBR=yy'), ('foo', ['a@c', 'b@c'], 'foo\n\nR=a@c, b@c'), ('foo\nBar\n\nR=\nBUG=', ['c@c'], 'foo\nBar\n\nR=c@c\nBUG='), ('foo\nBar\n\nR=\nBUG=\nR=', ['c@c'], 'foo\nBar\n\nR=c@c\nBUG='), # Same as the line before, but full of whitespaces. ( 'foo\nBar\n\n R = \n BUG = \n R = ', ['c@c'], 'foo\nBar\n\nR=c@c\n BUG =', ), # Whitespaces aren't interpreted as new lines. ('foo BUG=allo R=joe ', ['c@c'], 'foo BUG=allo R=joe\n\nR=c@c'), ] expected = [i[2] for i in data] actual = [] for orig, reviewers, _expected in data: obj = git_cl.ChangeDescription(orig) obj.update_reviewers(reviewers) actual.append(obj.description) self.assertEqual(expected, actual)
def test_update_reviewers(self): data = [ ('foo', [], 'foo'), ('foo', ['a@c'], 'foo\n\nR=a@c'), ('foo\nBUG=', ['a@c'], 'foo\nBUG=\nR=a@c'), ('foo\nR=xx\nTBR=yy\nR=bar', ['a@c'], 'foo\nTBR=a@c'), ('foo', ['a@c', 'b@c'], 'foo\n\nR=a@c, b@c'), ] for orig, reviewers, expected in data: obj = git_cl.ChangeDescription(orig) obj.update_reviewers(reviewers) self.assertEqual(expected, obj.description)
def __init__(self, name, issue, patchset, description, files, local_root, rietveld_url, needs_upload): # Defer the description processing to git_cl.ChangeDescription. self._desc = git_cl.ChangeDescription(description) self.name = name self.issue = int(issue) self.patchset = int(patchset) self._files = files or [] self.patch = None self._local_root = local_root self.needs_upload = needs_upload self.rietveld = gclient_utils.UpgradeToHttps( rietveld_url or GetCodeReviewSetting('CODE_REVIEW_SERVER')) self._rpc_server = None
def _commit_patch(self, pending): """Commits the pending patch to the repository. Do the checkout and applies the patch. """ try: try: # Make sure to apply on HEAD. pending.revision = None pending.apply_patch(self.context, True) # Commit it. commit_desc = git_cl.ChangeDescription(pending.description) if (self.context.server_hooks_missing and self.context.rietveld.email != pending.owner): commit_desc.update_reviewers(pending.reviewers) commit_desc.append_footer('Author: ' + pending.owner) commit_desc.append_footer( 'Review URL: %s/%s' % (self.context.rietveld.url, pending.issue)) pending.revision = self.context.checkout.commit( commit_desc.description, pending.owner) if not pending.revision: raise base.DiscardPending(pending, 'Failed to commit patch.') # Note that the commit succeeded for commit throttling. self.recent_commit_timestamps.append(time.time()) self.recent_commit_timestamps = ( self.recent_commit_timestamps[-(self.MAX_COMMIT_BURST + 1):]) viewvc_url = self.context.checkout.get_settings('VIEW_VC') issue_desc = git_cl.ChangeDescription(pending.description) msg = 'Committed: %s' % pending.revision if viewvc_url: viewvc_url = '%s%s' % (viewvc_url.rstrip('/'), pending.revision) msg = 'Committed: %s' % viewvc_url issue_desc.append_footer(msg) # Update the CQ dashboard. self.context.status.send( pending, { 'verification': 'commit', 'payload': { 'revision': pending.revision, 'output': msg, 'url': viewvc_url } }) # Closes the issue on Rietveld. # TODO(csharp): Retry if exceptions are encountered. try: self.context.rietveld.close_issue(pending.issue) self.context.rietveld.update_description( pending.issue, issue_desc.description) self.context.rietveld.add_comment( pending.issue, 'Change committed as %s' % pending.revision) except (urllib2.HTTPError, urllib2.URLError) as e: # Ignore AppEngine flakiness. logging.warning('Unable to fully close the issue') # And finally remove the issue. If the close_issue() call above failed, # it is possible the dashboard will be confused but it is harmless. try: self.queue.get(pending.issue) except KeyError: logging.error('Internal inconsistency for %d', pending.issue) self.queue.remove(pending.issue) except (checkout.PatchApplicationFailed, patch.UnsupportedPatchFormat) as e: raise base.DiscardPending(pending, str(e)) except subprocess2.CalledProcessError as e: stdout = getattr(e, 'stdout', None) out = 'Failed to apply the patch.' if stdout: out += '\n%s' % stdout raise base.DiscardPending(pending, out) except base.DiscardPending as e: self._discard_pending(e.pending, e.status) except Exception as e: traceback.print_exc() # Swallow every exception in that code and move on. Make sure to send a # stack trace though. errors.send_stack(e)
def CMDcommit(change_info, args): """Commits the changelist to the repository.""" if not change_info.GetFiles(): print "Nothing to commit, changelist is empty." return 1 # OptionallyDoPresubmitChecks has a side-effect which eats these flags. bypassed = '--no_presubmit' in args or '--force' in args output = OptionallyDoPresubmitChecks(change_info, True, args) if not output.should_continue(): return 1 # We face a problem with svn here: Let's say change 'bleh' modifies # svn:ignore on dir1\. but another unrelated change 'pouet' modifies # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. # The only fix is to use --non-recursive but that has its issues too: # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise # you'll get "svn: Cannot non-recursively commit a directory deletion of a # directory with child nodes". Yay... commit_cmd = ["svn", "commit"] if change_info.issue: # Get the latest description from Rietveld. change_info.UpdateDescriptionFromIssue() change_info.update_reviewers(change_info.GetApprovingReviewers()) commit_desc = git_cl.ChangeDescription(change_info.description) if change_info.issue: server = change_info.rietveld if not server.startswith("http://") and not server.startswith("https://"): server = "http://" + server commit_desc.append_footer('Review URL: %s/%d' % (server, change_info.issue)) handle, commit_filename = tempfile.mkstemp(text=True) os.write(handle, commit_desc.description) os.close(handle) try: handle, targets_filename = tempfile.mkstemp(text=True) os.write(handle, "\n".join(change_info.GetFileNames())) os.close(handle) try: commit_cmd += ['--file=' + commit_filename] commit_cmd += ['--targets=' + targets_filename] # Change the current working directory before calling commit. output = '' try: output = RunShell(commit_cmd, True) except subprocess2.CalledProcessError, e: ErrorExit('Commit failed.\n%s' % e) finally: os.remove(commit_filename) finally: os.remove(targets_filename) if output.find("Committed revision") != -1: change_info.Delete() if change_info.issue: revision = re.compile(".*?\nCommitted revision (\d+)", re.DOTALL).match(output).group(1) viewvc_url = GetCodeReviewSetting('VIEW_VC') if viewvc_url and revision: change_info.append_footer('Committed: ' + viewvc_url + revision) elif revision: change_info.append_footer('Committed: ' + revision) change_info.CloseIssue() props = change_info.RpcServer().get_issue_properties( change_info.issue, False) patch_num = len(props['patchsets']) comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) comment += ' (presubmit successful).' if not bypassed else '.' change_info.AddComment(comment) return 0
def UpdateDescriptionFromIssue(self): """Updates self.description with the issue description from Rietveld.""" self._desc = git_cl.ChangeDescription(self.GetIssueDescription())
def force_description(self, new_description): self._desc = git_cl.ChangeDescription(new_description) self.needs_upload = True