blob: 87eaa4cc8bd526b67d8d30ac32e7549b94460477 [file] [log] [blame]
Björn Pedersenc357ceb2015-05-27 10:17:36 +02001#!/usr/bin/env python
Dave Borowitz1b46d672014-10-02 09:18:19 -07002# Copyright (C) 2014 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from __future__ import print_function
17
18import argparse
19import collections
20import os
21import subprocess
22import sys
23
24
25def get_config(name):
26 args = ['git', 'config', '--get', name]
27 p = subprocess.Popen(args, stdout=subprocess.PIPE)
28 out, _ = p.communicate()
29 ret = p.poll()
30 if ret not in (0, 1):
31 raise subprocess.CalledProcessError(ret, ' '.join(args), output=out)
32 return out.strip()
33
34
35def deref(name):
36 p = subprocess.Popen(
37 ['git', 'rev-parse', '--symbolic-full-name', name],
38 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
39 out, _ = p.communicate()
40 return out.strip()
41
42
43def main(argv):
44 p = argparse.ArgumentParser(description='Push changes to Gerrit for review')
45 p.add_argument('-r', '--remote', default='', metavar='REMOTE',
46 help='remote name or URL to push to')
47 p.add_argument('-b', '--branch', default='', metavar='BRANCH',
48 help='remote branch name, refs/for/BRANCH')
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020049 p.add_argument('args', nargs='*', metavar='REVIEWER_OR_HASHTAG',
50 help='reviewer names or aliases, or #hashtags')
Dave Borowitz1b46d672014-10-02 09:18:19 -070051 p.add_argument('-t', '--topic', default='', metavar='TOPIC',
52 help='topic for new changes')
53 p.add_argument('--dry-run', action='store_true',
54 help='dry run, print git command and exit')
55 args = p.parse_args()
56
57 if not args.remote or not args.branch:
58 hp = 'refs/heads/'
59 upstream = deref('HEAD')
60 while upstream.startswith(hp):
61 upstream = deref(upstream[len(hp):] + '@{u}')
62
63 rp = 'refs/remotes/'
64 if upstream.startswith(rp):
65 def_remote, def_branch = upstream[len(rp):].split('/', 1)
66 else:
67 def_remote, def_branch = 'origin', 'master'
68 args.remote = args.remote or def_remote
69 args.branch = args.branch or def_branch
70
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020071
Dave Borowitz1b46d672014-10-02 09:18:19 -070072 opts = collections.defaultdict(list)
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020073 is_hashtag = lambda x: x.startswith('#')
74 opts['r'].extend(
Dave Borowitze7d88cd2016-10-04 11:47:33 -040075 (get_config('reviewer.' + r) or r)
76 for r in args.args if not is_hashtag(r))
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020077 opts['t'].extend(t[1:] for t in args.args if is_hashtag(t))
Dave Borowitz1b46d672014-10-02 09:18:19 -070078 if args.topic:
79 opts['topic'].append(args.topic)
80 opts_str = ','.join('%s=%s' % (k, v) for k in opts for v in opts[k])
81 if opts_str:
82 opts_str = '%' + opts_str
83
84 git_args = ['git', 'push', args.remote,
85 'HEAD:refs/for/%s%s' % (args.branch, opts_str)]
86 if args.dry_run:
87 print(' '.join(git_args))
88 return 0
89 os.execvp('git', git_args)
90
91
92if __name__ == '__main__':
93 sys.exit(main(sys.argv))