glusterfs

Форк
0
/
git-branch-diff.py 
285 строк · 12.1 Кб
1
#!/bin/python2
2

3
"""
4
  Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com>
5
  This file is part of GlusterFS.
6

7
  This file is licensed to you under your choice of the GNU Lesser
8
  General Public License, version 3 or any later version (LGPLv3 or
9
  later), or the GNU General Public License, version 2 (GPLv2), in all
10
  cases as published by the Free Software Foundation.
11
"""
12

13
"""
14
  ABOUT:
15
  This script helps in visualizing backported and missed commits between two
16
  different branches, tags or commit ranges. In the list of missed commits,
17
  it will help you identify patches which are posted for reviews on gerrit server.
18

19
  USAGE:
20
    $ ./extras/git-branch-diff.py --help
21
    usage: git-branch-diff.py [-h] [-s SOURCE] -t TARGET [-a AUTHOR] [-p PATH]
22
                              [-o OPTIONS]
23

24
    git wrapper to diff local or remote branches/tags/commit-ranges
25

26
    optional arguments:
27
      -h, --help            show this help message and exit
28
      -s SOURCE, --source SOURCE
29
                            source pattern, it could be a branch, tag or a commit
30
                            range
31
      -t TARGET, --target TARGET
32
                            target pattern, it could be a branch, tag or a commit
33
                            range
34
      -a AUTHOR, --author AUTHOR
35
                            default: git config name/email, to provide multiple
36
                            specify comma separated values
37
      -p PATH, --path PATH  show source and target diff w.r.t given path, to
38
                            provide multiple specify space in between them
39
      -o OPTIONS, --options OPTIONS
40
                            add other git options such as --after=<>, --before=<>
41
                            etc. experts use;
42

43
  SAMPLE EXECUTIONS:
44
  $ ./extras/git-branch-diff.py -t origin/release-3.8
45

46
  $ ./extras/git-branch-diff.py -s local_branch -t origin/release-3.7
47

48
  $ ./extras/git-branch-diff.py -s 4517bf8..e66add8 -t origin/release-3.7
49
  $ ./extras/git-branch-diff.py -s HEAD..c4efd39 -t origin/release-3.7
50

51
  $ ./extras/git-branch-diff.py -t v3.7.11 --author="author@redhat.com"
52
  $ ./extras/git-branch-diff.py -t v3.7.11 --author="authorX, authorY, authorZ"
53

54
  $ ./extras/git-branch-diff.py -t origin/release-3.8 --path="xlators/"
55
  $ ./extras/git-branch-diff.py -t origin/release-3.8 --path="./xlators ./rpc"
56

57
  $ ./extras/git-branch-diff.py -t origin/release-3.6 --author="*"
58
  $ ./extras/git-branch-diff.py -t origin/release-3.6 --author="All"
59
  $ ./extras/git-branch-diff.py -t origin/release-3.6 --author="Null"
60

61
  $ ./extras/git-branch-diff.py -t v3.7.11 --options="--after=2015-03-01 \
62
                                                      --before=2016-01-30"
63

64
  DECLARATION:
65
  While backporting commit to another branch only subject of the patch may
66
  remain unchanged, all others such as commit message,  commit Id, change Id,
67
  bug Id, may be changed. This script works by taking commit subject as the
68
  key value for comparing two git branches, which can be local or remote.
69

70
  Note: This script may ignore commits which have altered their commit subjects
71
  while backporting patches. Also this script doesn't have any intelligence to
72
  detect squashed commits.
73

74
  AUTHOR:
75
  Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
76
"""
77

78
from __future__ import print_function
79
import os
80
import sys
81
import argparse
82
import commands
83
import subprocess
84
import requests
85

86
class GitBranchDiff:
87
    def __init__ (self):
88
        " color symbols"
89
        self.tick  = u'\033[1;32m[ \u2714 ]\033[0m'
90
        self.cross = u'\033[1;31m[ \u2716 ]\033[0m'
91
        self.green_set = u'\033[1;34m'
92
        self.yello_set = u'\033[4;33m'
93
        self.color_unset = '\033[0m'
94

95
        self.parse_cmd_args()
96

97
        " replace default values with actual values from command args"
98
        self.g_author = self.argsdict['author']
99
        self.s_pattern  = self.argsdict['source']
100
        self.t_pattern  = self.argsdict['target']
101
        self.r_path     = self.argsdict['path']
102
        self.options    = ' '.join(self.argsdict['options'])
103

104
        self.gerrit_server = "http://review.gluster.org"
105

106
    def check_dir_exist (self, os_path):
107
        " checks whether given path exist"
108
        path_list = os_path.split()
109
        for path in path_list:
110
            if not os.path.exists(path):
111
                raise argparse.ArgumentTypeError("'%s' path %s is not valid"
112
                                                 %(os_path, path))
113
        return os_path
114

115
    def check_pattern_exist (self):
116
        " defend to check given branch[s] exit"
117
        status_sbr, op = commands.getstatusoutput('git log ' +
118
                                                  self.s_pattern)
119
        status_tbr, op = commands.getstatusoutput('git log ' +
120
                                                  self.t_pattern)
121
        if status_sbr != 0:
122
            print("Error: --source=" + self.s_pattern + " doesn't exit\n")
123
            self.parser.print_help()
124
            exit(status_sbr)
125
        elif status_tbr != 0:
126
            print("Error: --target=" + self.t_pattern + " doesn't exit\n")
127
            self.parser.print_help()
128
            exit(status_tbr)
129

130
    def check_author_exist (self):
131
        " defend to check given author exist, format in case of multiple"
132
        contrib_list = ['', '*', 'all', 'All', 'ALL', 'null', 'Null', 'NULL']
133
        if self.g_author in contrib_list:
134
            self.g_author = ""
135
        else:
136
            ide_list = self.g_author.split(',')
137
            for ide in ide_list:
138
                cmd4 = 'git log ' + self.s_pattern + ' --author=' + ide
139
                c_list = subprocess.check_output(cmd4, shell = True)
140
                if len(c_list) is 0:
141
                    print("Error: --author=%s doesn't exit" %self.g_author)
142
                    print("see '%s --help'" %__file__)
143
                    exit(1)
144
            if len(ide_list) > 1:
145
                self.g_author = "\|".join(ide_list)
146

147
    def connected_to_gerrit (self):
148
        "check if gerrit server is reachable"
149
        try:
150
            r = requests.get(self.gerrit_server, timeout=3)
151
            return True
152
        except requests.Timeout as err:
153
            " request timed out"
154
            print("Warning: failed to get list of open review commits on " \
155
                            "gerrit.\n" \
156
                  "hint: Request timed out! gerrit server could possibly " \
157
                  "slow ...\n")
158
            return False
159
        except requests.RequestException as err:
160
            " handle other errors"
161
            print("Warning: failed to get list of open review commits on " \
162
                            "gerrit\n" \
163
                  "hint: check with internet connection ...\n")
164
            return False
165

166
    def parse_cmd_args (self):
167
        " command line parser"
168
        author = subprocess.check_output('git config user.email',
169
                                                  shell = True).rstrip('\n')
170
        source = "remotes/origin/master"
171
        options  = [' --pretty=format:"%h %s" ']
172
        path = subprocess.check_output('git rev-parse --show-toplevel',
173
                                            shell = True).rstrip('\n')
174
        self.parser = argparse.ArgumentParser(description = 'git wrapper to '
175
                                              'diff local or remote branches/'
176
                                              'tags/commit-ranges')
177
        self.parser.add_argument('-s',
178
                                 '--source',
179
                                 help = 'source pattern, it could be a branch,'
180
                                        ' tag or a commit range',
181
                                 default = source,
182
                                 dest = 'source')
183
        self.parser.add_argument('-t',
184
                                 '--target',
185
                                 help = 'target pattern, it could be a branch,'
186
                                        ' tag or a commit range',
187
                                 required = True,
188
                                 dest = 'target')
189
        self.parser.add_argument('-a',
190
                                 '--author',
191
                                 help = 'default: git config name/email, '
192
                                        'to provide multiple specify comma'
193
                                        ' separated values',
194
                                 default = author,
195
                                 dest = 'author')
196
        self.parser.add_argument('-p',
197
                                 '--path',
198
                                 type = self.check_dir_exist,
199
                                 help = 'show source and target diff w.r.t '
200
                                        'given path, to provide multiple '
201
                                        'specify space in between them',
202
                                 default = path,
203
                                 dest = 'path')
204
        self.parser.add_argument('-o',
205
                                 '--options',
206
                                 help = 'add other git options such as '
207
                                        '--after=<>, --before=<> etc. '
208
                                        'experts use;',
209
                                 default = options,
210
                                 dest = 'options',
211
                                 action='append')
212
        self.argsdict = vars(self.parser.parse_args())
213

214
    def print_output (self):
215
        " display the result list"
216
        print("\n------------------------------------------------------------\n")
217
        print(self.tick + " Successfully Backported changes:")
218
        print('      {' + 'from: ' + self.s_pattern + \
219
              '  to: '+ self.t_pattern + '}\n')
220
        for key, value in self.s_dict.items():
221
            if value in self.t_dict.itervalues():
222
                print("[%s%s%s] %s" %(self.yello_set,
223
                                      key,
224
                                      self.color_unset,
225
                                      value))
226
        print("\n------------------------------------------------------------\n")
227
        print(self.cross + " Missing patches in " + self.t_pattern + ':\n')
228
        if self.connected_to_gerrit():
229
            cmd3 = "git review -r origin -l"
230
            review_list = subprocess.check_output(cmd3, shell = True).split('\n')
231
        else:
232
            review_list = []
233

234
        for key, value in self.s_dict.items():
235
            if value not in self.t_dict.itervalues():
236
                if any(value in s for s in review_list):
237
                    print("[%s%s%s] %s %s(under review)%s" %(self.yello_set,
238
                                                            key,
239
                                                            self.color_unset,
240
                                                            value,
241
                                                            self.green_set,
242
                                                            self.color_unset))
243
                else:
244
                    print("[%s%s%s] %s" %(self.yello_set,
245
                                          key,
246
                                          self.color_unset,
247
                                          value))
248
        print("\n------------------------------------------------------------\n")
249

250
    def main (self):
251
        self.check_pattern_exist()
252
        self.check_author_exist()
253

254
        " actual git commands"
255
        cmd1 = 'git log' + self.options + ' ' + self.s_pattern + \
256
               ' --author=\'' + self.g_author + '\' ' + self.r_path
257

258
        " could be backported by anybody so --author doesn't apply here"
259
        cmd2 = 'git log' + self.options + ' ' + self.t_pattern + \
260
               ' ' + self.r_path
261

262
        s_list = subprocess.check_output(cmd1, shell = True).split('\n')
263
        t_list = subprocess.check_output(cmd2, shell = True)
264

265
        if len(t_list) is 0:
266
            print("No commits in the target: %s" %self.t_pattern)
267
            print("see '%s --help'" %__file__)
268
            exit()
269
        else:
270
            t_list = t_list.split('\n')
271

272
        self.s_dict = dict()
273
        self.t_dict = dict()
274

275
        for item in s_list:
276
            self.s_dict.update(dict([item.split(' ', 1)]))
277
        for item in t_list:
278
            self.t_dict.update(dict([item.split(' ', 1)]))
279

280
        self.print_output()
281

282

283
if __name__ == '__main__':
284
    run = GitBranchDiff()
285
    run.main()
286

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.