contrib: Add a simple tool for pushing to named reviewers

This is a sort of simplified version of git-review[1] for users like
myself who don't mind most git command line tools, and therefore don't
feel the need to switch to a full git-review workflow, but still don't
like the HEAD:refs/for/master%r=user@domain.com syntax for specifying
reviewers during a push.

Reviewer aliases can be specified in a git config file:

[reviewer]
  sop = sop@google.com

$ git push-reviewer --dry-run sop
git push origin HEAD:refs/for/master%r=sop@google.com

[1] http://www.mediawiki.org/wiki/Gerrit/git-review

Change-Id: Ib0c8d609ed9eab17b71ddb13da417a9bfd013611
This commit is contained in:
Dave Borowitz 2014-10-02 09:18:19 -07:00
parent c957df57a1
commit 1b46d67a93

88
contrib/git-push-review Executable file
View File

@ -0,0 +1,88 @@
#!/usr/bin/python
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import collections
import os
import subprocess
import sys
def get_config(name):
args = ['git', 'config', '--get', name]
p = subprocess.Popen(args, stdout=subprocess.PIPE)
out, _ = p.communicate()
ret = p.poll()
if ret not in (0, 1):
raise subprocess.CalledProcessError(ret, ' '.join(args), output=out)
return out.strip()
def deref(name):
p = subprocess.Popen(
['git', 'rev-parse', '--symbolic-full-name', name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, _ = p.communicate()
return out.strip()
def main(argv):
p = argparse.ArgumentParser(description='Push changes to Gerrit for review')
p.add_argument('-r', '--remote', default='', metavar='REMOTE',
help='remote name or URL to push to')
p.add_argument('-b', '--branch', default='', metavar='BRANCH',
help='remote branch name, refs/for/BRANCH')
p.add_argument('reviewers', nargs='*', metavar='REVIEWER',
help='reviewer names or aliases')
p.add_argument('-t', '--topic', default='', metavar='TOPIC',
help='topic for new changes')
p.add_argument('--dry-run', action='store_true',
help='dry run, print git command and exit')
args = p.parse_args()
if not args.remote or not args.branch:
hp = 'refs/heads/'
upstream = deref('HEAD')
while upstream.startswith(hp):
upstream = deref(upstream[len(hp):] + '@{u}')
rp = 'refs/remotes/'
if upstream.startswith(rp):
def_remote, def_branch = upstream[len(rp):].split('/', 1)
else:
def_remote, def_branch = 'origin', 'master'
args.remote = args.remote or def_remote
args.branch = args.branch or def_branch
opts = collections.defaultdict(list)
opts['r'].extend((get_config('reviewer.' + r) or r) for r in args.reviewers)
if args.topic:
opts['topic'].append(args.topic)
opts_str = ','.join('%s=%s' % (k, v) for k in opts for v in opts[k])
if opts_str:
opts_str = '%' + opts_str
git_args = ['git', 'push', args.remote,
'HEAD:refs/for/%s%s' % (args.branch, opts_str)]
if args.dry_run:
print(' '.join(git_args))
return 0
os.execvp('git', git_args)
if __name__ == '__main__':
sys.exit(main(sys.argv))