Index: git_cl.py |
diff --git a/git_cl.py b/git_cl.py |
index c3b92903b7de07db6cedc99e15208d43f8c275d1..f1a450973db18f773e76f21c55c722b5edcb0a63 100755 |
--- a/git_cl.py |
+++ b/git_cl.py |
@@ -2518,6 +2518,9 @@ def GenerateGerritChangeId(message): |
def GerritUpload(options, args, cl, change): |
"""upload the current branch to gerrit.""" |
+ # TODO(tandrii): refactor this to be a method of _GerritChangelistImpl, |
+ # to avoid private members accessors below. |
+ |
# We assume the remote called "origin" is the one we want. |
# It is probably not worthwhile to support different workflows. |
gerrit_remote = 'origin' |
@@ -2526,52 +2529,122 @@ def GerritUpload(options, args, cl, change): |
branch = GetTargetRef(remote, remote_branch, options.target_branch, |
pending_prefix='') |
- change_desc = ChangeDescription( |
- options.message or CreateDescriptionFromLog(args)) |
- if not change_desc.description: |
- print "\nDescription is empty. Aborting..." |
- return 1 |
- |
if options.title: |
print "\nPatch titles (-t) are not supported in Gerrit. Aborting..." |
return 1 |
if options.squash: |
- # Try to get the message from a previous upload. |
- shadow_branch = 'refs/heads/git_cl_uploads/' + cl.GetBranch() |
- message = RunGitSilent(['show', '--format=%B', '-s', shadow_branch]) |
- if not message: |
+ if not cl.GetIssue(): |
+ # TODO(tandrii): deperecate this after 2016Q2. |
+ # Backwards compatibility with shadow branch, which used to contain |
+ # change-id for a given branch, using which we can fetch actual issue |
+ # number and set it as the property of the branch, which is the new way. |
+ message = RunGitSilent(['show', '--format=%B', '-s', |
+ 'refs/heads/git_cl_uploads/%s' % cl.GetBranch()]) |
+ if message: |
+ change_ids = git_footers.get_footer_change_id(message.strip()) |
+ if change_ids and len(change_ids) == 1: |
+ details = gerrit_util.GetChangeDetail( |
+ cl._codereview_impl._GetGerritHost(), change_ids[0]) |
+ if details: |
+ print('WARNING: found old upload in branch git_cl_uploads/%s ' |
+ 'corresponding to issue %s' % |
+ (cl.GetBranch(), details['_number'])) |
+ cl.SetIssue(details['_number']) |
+ if not cl.GetIssue(): |
+ DieWithError( |
+ '\n' # For readability of the blob below. |
+ 'Found old upload in branch git_cl_uploads/%s, ' |
+ 'but failed to find corresponding Gerrit issue.\n' |
+ 'If you know the issue number, set it manually first:\n' |
+ ' git cl issue 123456\n' |
+ 'If you intended to upload this CL as new issue, ' |
+ 'just delete or rename the old upload branch:\n' |
+ ' git rename-branch git_cl_uploads/%s old_upload-%s\n' |
+ 'After that, please run git cl upload again.' % |
+ tuple([cl.GetBranch()] * 3)) |
+ # End of backwards compatability. |
+ |
+ if cl.GetIssue(): |
+ # Try to get the message from a previous upload. |
+ message = cl.GetDescription() |
+ if not message: |
+ DieWithError( |
+ 'failed to fetch description from current Gerrit issue %d\n' |
+ '%s' % (cl.GetIssue(), cl.GetIssueURL())) |
+ change_id = cl._codereview_impl._GetChangeDetail([])['change_id'] |
+ while True: |
+ footer_change_ids = git_footers.get_footer_change_id(message) |
+ if footer_change_ids == [change_id]: |
+ break |
+ if not footer_change_ids: |
+ message = git_footers.add_footer_change_id(message, change_id) |
+ print('WARNING: appended missing Change-Id to issue description') |
+ continue |
+ # There is already a valid footer but with different or several ids. |
+ # Doing this automatically is non-trivial as we don't want to lose |
+ # existing other footers, yet we want to append just 1 desired |
+ # Change-Id. Thus, just create a new footer, but let user verify the new |
+ # description. |
+ message = '%s\n\nChange-Id: %s' % (message, change_id) |
+ print( |
+ 'WARNING: issue %s has Change-Id footer(s):\n' |
+ ' %s\n' |
+ 'but issue has Change-Id %s, according to Gerrit.\n' |
+ 'Please, check the proposed correction to the description, ' |
+ 'and edit it if necessary but keep the "Change-Id: %s" footer\n' |
+ % (cl.GetIssue(), '\n '.join(footer_change_ids), change_id, |
+ change_id)) |
+ ask_for_data('Press enter to edit now, Ctrl+C to abort') |
+ if not options.force: |
+ change_desc = ChangeDescription(message) |
+ change_desc.prompt() |
+ message = change_desc.description |
+ if not message: |
+ DieWithError("Description is empty. Aborting...") |
+ # Continue the while loop. |
+ # Sanity check of this code - we should end up with proper message footer. |
+ assert [change_id] == git_footers.get_footer_change_id(message) |
+ change_desc = ChangeDescription(message) |
+ else: |
+ change_desc = ChangeDescription( |
+ options.message or CreateDescriptionFromLog(args)) |
if not options.force: |
change_desc.prompt() |
if not change_desc.description: |
- print "Description is empty; aborting." |
- return 1 |
+ DieWithError("Description is empty. Aborting...") |
message = change_desc.description |
change_ids = git_footers.get_footer_change_id(message) |
if len(change_ids) > 1: |
- DieWithError('too many Change-Id footers in %s branch' % shadow_branch) |
+ DieWithError('too many Change-Id footers, at most 1 allowed.') |
if not change_ids: |
+ # Generate the Change-Id automatically. |
message = git_footers.add_footer_change_id( |
message, GenerateGerritChangeId(message)) |
change_desc.set_description(message) |
change_ids = git_footers.get_footer_change_id(message) |
assert len(change_ids) == 1 |
- |
change_id = change_ids[0] |
remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
if remote is '.': |
# If our upstream branch is local, we base our squashed commit on its |
# squashed version. |
- parent = ('refs/heads/git_cl_uploads/' + |
- scm.GIT.ShortBranchName(upstream_branch)) |
- |
- # Verify that the upstream branch has been uploaded too, otherwise Gerrit |
- # will create additional CLs when uploading. |
- if (RunGitSilent(['rev-parse', upstream_branch + ':']) != |
- RunGitSilent(['rev-parse', parent + ':'])): |
- print 'Upload upstream branch ' + upstream_branch + ' first.' |
- return 1 |
+ upstream_branch_name = scm.GIT.ShortBranchName(upstream_branch) |
+ # Check the squashed hash of the parent. |
+ parent = RunGit(['config', |
+ 'branch.%s.gerritsquashhash' % upstream_branch_name], |
+ error_ok=True).strip() |
+ # Verify that the upstream branch has been uploaded too, otherwise |
+ # Gerrit will create additional CLs when uploading. |
+ if not parent or (RunGitSilent(['rev-parse', upstream_branch + ':']) != |
+ RunGitSilent(['rev-parse', parent + ':'])): |
+ # TODO(tandrii): remove "old depot_tools" part on April 12, 2016. |
+ DieWithError( |
+ 'Upload upstream branch %s first.\n' |
+ 'Note: maybe you\'ve uploaded it with --no-squash or with an old\n' |
+ ' version of depot_tools. If so, then re-upload it with:\n' |
+ ' git cl upload --squash\n' % upstream_branch_name) |
else: |
parent = cl.GetCommonAncestorWithUpstream() |
@@ -2579,6 +2652,11 @@ def GerritUpload(options, args, cl, change): |
ref_to_push = RunGit(['commit-tree', tree, '-p', parent, |
'-m', message]).strip() |
else: |
+ change_desc = ChangeDescription( |
+ options.message or CreateDescriptionFromLog(args)) |
+ if not change_desc.description: |
+ DieWithError("Description is empty. Aborting...") |
+ |
if not git_footers.get_footer_change_id(change_desc.description): |
DownloadGerritHook(False) |
change_desc.set_description(AddChangeIdToCommitMessage(options, args)) |
@@ -2586,6 +2664,7 @@ def GerritUpload(options, args, cl, change): |
parent = '%s/%s' % (gerrit_remote, branch) |
change_id = git_footers.get_footer_change_id(change_desc.description)[0] |
+ assert change_desc |
commits = RunGitSilent(['rev-list', '%s..%s' % (parent, |
ref_to_push)]).splitlines() |
if len(commits) > 1: |
@@ -2632,8 +2711,8 @@ def GerritUpload(options, args, cl, change): |
('Created|Updated %d issues on Gerrit, but only 1 expected.\n' |
'Change-Id: %s') % (len(change_numbers), change_id)) |
cl.SetIssue(change_numbers[0]) |
- head = RunGit(['rev-parse', 'HEAD']).strip() |
- RunGit(['update-ref', '-m', 'Uploaded ' + head, shadow_branch, ref_to_push]) |
+ RunGit(['config', 'branch.%s.gerritsquashhash' % cl.GetBranch(), |
+ ref_to_push]) |
return 0 |
@@ -2924,6 +3003,9 @@ def CMDupload(parser, args): |
options.reviewers = cleanup_list(options.reviewers) |
options.cc = cleanup_list(options.cc) |
+ # For sanity of test expectations, do this otherwise lazy-loading *now*. |
+ settings.GetIsGerrit() |
+ |
cl = Changelist(auth_config=auth_config) |
if args: |
# TODO(ukai): is it ok for gerrit case? |