#!/usr/bin/env 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('args', nargs='*', metavar='REVIEWER_OR_HASHTAG', help='reviewer names or aliases, or #hashtags') p.add_argument('-t', '--topic', default='', metavar='TOPIC', help='topic for new changes') p.add_argument('-e', '--edit', action='store_true', help='upload as change edit') p.add_argument('-w', '--wip', action='store_true', help='upload as WIP') p.add_argument('-y', '--ready', action='store_true', help='set ready') 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) is_hashtag = lambda x: x.startswith('#') opts['r'].extend( (get_config('reviewer.' + r) or r) for r in args.args if not is_hashtag(r)) opts['t'].extend(t[1:] for t in args.args if is_hashtag(t)) if args.topic: opts['topic'].append(args.topic) if args.edit: opts['edit'].append(True) if args.wip: opts['wip'].append(True) if args.ready: opts['ready'].append(True) opts_strs = [] for k in opts: for v in opts[k]: if v == True: opts_strs.append(k) elif v != False: opts_strs.append('%s=%s' % (k, v)) opts_str = ','.join(opts_strs) 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))