#!/usr/bin/env python # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Upload a cherry pick CL to rietveld.""" import argparse import md5 import subprocess2 import sys from git_cl import Changelist from git_common import config, run from third_party.upload import EncodeMultipartFormData, GitVCS from rietveld import Rietveld def cherry_pick(target_branch, commit): """Attempt to upload a cherry pick CL to rietveld. Args: target_branch: The branch to cherry pick onto. commit: The git hash of the commit to cherry pick. """ author = config('user.email') description = '%s\n\n(cherry picked from commit %s)\n' % ( run('show', '--pretty=%B', '--quiet', commit), commit) parent = run('show', '--pretty=%P', '--quiet', commit) print 'Found parent revision:', parent class Options(object): def __init__(self): self.emulate_svn_auto_props = False content_type, payload = EncodeMultipartFormData([ ('base', '%s@%s' % (Changelist().GetRemoteUrl(), target_branch)), ('cc', config('rietveld.cc')), ('content_upload', '1'), ('description', description), ('project', '%s@%s' % (config('rietveld.project'), target_branch)), ('subject', description.splitlines()[0]), ('user', author), ], [ ('data', 'data.diff', GitVCS(Options()).PostProcessDiff( run('diff', parent, commit))), ]) rietveld = Rietveld(config('rietveld.server'), author, None) # pylint: disable=W0212 output = rietveld._send( '/upload', payload=payload, content_type=content_type, ).splitlines() # If successful, output will look like: # Issue created. URL: https://codereview.chromium.org/1234567890 # 1 # 10001 some/path/first.file # 10002 some/path/second.file # 10003 some/path/third.file if output[0].startswith('Issue created. URL: '): print output[0] issue = output[0].rsplit('/', 1)[-1] patchset = output[1] files = output[2:] for f in files: file_id, filename = f.split() mode = 'M' try: content = run('show', '%s:%s' % (parent, filename)) except subprocess2.CalledProcessError: # File didn't exist in the parent revision. content = '' mode = 'A' content_type, payload = EncodeMultipartFormData([ ('checksum', md5.md5(content).hexdigest()), ('filename', filename), ('is_current', 'False'), ('status', mode), ], [ ('data', filename, content), ]) # pylint: disable=W0212 print ' Uploading base file for %s:' % filename, rietveld._send( '/%s/upload_content/%s/%s' % (issue, patchset, file_id), payload=payload, content_type=content_type, ) try: content = run('show', '%s:%s' % (commit, filename)) except subprocess2.CalledProcessError: # File no longer exists in the new commit. content = '' mode = 'D' content_type, payload = EncodeMultipartFormData([ ('checksum', md5.md5(content).hexdigest()), ('filename', filename), ('is_current', 'True'), ('status', mode), ], [ ('data', filename, content), ]) # pylint: disable=W0212 print ' Uploading %s:' % filename, rietveld._send( '/%s/upload_content/%s/%s' % (issue, patchset, file_id), payload=payload, content_type=content_type, ) # pylint: disable=W0212 print 'Finalizing upload:', rietveld._send('/%s/upload_complete/1' % issue) def main(): parser = argparse.ArgumentParser() parser.add_argument( '--branch', '-b', help='The upstream branch to cherry pick to.', metavar='<branch>', required=True, ) parser.add_argument( 'commit', help='SHA to cherry pick.', metavar='<commit>', ) args = parser.parse_args() cherry_pick(args.branch, args.commit) if __name__ == '__main__': sys.exit(main())