blob: 5a7f664bf36e9a0a428d00b9359ad45850c3e355 [file] [log] [blame]
David Ostrovsky2b5fe092021-03-03 11:52:30 +01001#!/usr/bin/env python3
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')
Dave Borowitz4f69f032018-04-12 04:01:53 -040053 p.add_argument('-e', '--edit', action='store_true',
54 help='upload as change edit')
55 p.add_argument('-w', '--wip', action='store_true', help='upload as WIP')
56 p.add_argument('-y', '--ready', action='store_true', help='set ready')
Dave Borowitz1b46d672014-10-02 09:18:19 -070057 p.add_argument('--dry-run', action='store_true',
58 help='dry run, print git command and exit')
59 args = p.parse_args()
60
61 if not args.remote or not args.branch:
62 hp = 'refs/heads/'
63 upstream = deref('HEAD')
64 while upstream.startswith(hp):
65 upstream = deref(upstream[len(hp):] + '@{u}')
66
67 rp = 'refs/remotes/'
68 if upstream.startswith(rp):
69 def_remote, def_branch = upstream[len(rp):].split('/', 1)
70 else:
71 def_remote, def_branch = 'origin', 'master'
72 args.remote = args.remote or def_remote
73 args.branch = args.branch or def_branch
74
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020075
Dave Borowitz1b46d672014-10-02 09:18:19 -070076 opts = collections.defaultdict(list)
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020077 is_hashtag = lambda x: x.startswith('#')
78 opts['r'].extend(
Dave Borowitze7d88cd2016-10-04 11:47:33 -040079 (get_config('reviewer.' + r) or r)
80 for r in args.args if not is_hashtag(r))
Dave Borowitz053b7a6e2016-09-22 09:20:13 +020081 opts['t'].extend(t[1:] for t in args.args if is_hashtag(t))
Dave Borowitz1b46d672014-10-02 09:18:19 -070082 if args.topic:
83 opts['topic'].append(args.topic)
Dave Borowitz4f69f032018-04-12 04:01:53 -040084 if args.edit:
85 opts['edit'].append(True)
86 if args.wip:
87 opts['wip'].append(True)
88 if args.ready:
89 opts['ready'].append(True)
90
91 opts_strs = []
92 for k in opts:
93 for v in opts[k]:
94 if v == True:
95 opts_strs.append(k)
96 elif v != False:
97 opts_strs.append('%s=%s' % (k, v))
98
99 opts_str = ','.join(opts_strs)
Dave Borowitz1b46d672014-10-02 09:18:19 -0700100 if opts_str:
101 opts_str = '%' + opts_str
102
103 git_args = ['git', 'push', args.remote,
104 'HEAD:refs/for/%s%s' % (args.branch, opts_str)]
105 if args.dry_run:
106 print(' '.join(git_args))
107 return 0
108 os.execvp('git', git_args)
109
110
111if __name__ == '__main__':
112 sys.exit(main(sys.argv))