OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Lists branches with closed and abandoned issues.""" | |
7 | |
8 import optparse | |
9 import os | |
10 import sys | |
11 import urllib2 | |
12 | |
13 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
14 DEPOT_TOOLS_DIR = os.path.dirname(BASE_DIR) | |
15 sys.path.insert(0, DEPOT_TOOLS_DIR) | |
16 | |
17 import git_cl | |
18 | |
19 | |
20 def get_branches(): | |
21 """Get list of all local git branches.""" | |
22 branches = [l.split() for l in git_cl.RunGit( | |
23 ["for-each-ref", | |
24 "--format=%(refname:short) %(upstream:short)", | |
25 "refs/heads"]).splitlines()] | |
26 return [Branch(*b) for b in branches] | |
27 | |
28 def get_change_count(start, end): | |
29 return int(git_cl.RunGit(["rev-list", "%s..%s" % (start, end), "--count" ])) | |
30 | |
31 | |
32 class Branch(git_cl.Changelist): | |
33 def __init__(self, name, upstream=None): | |
34 git_cl.Changelist.__init__(self, branchref=name) | |
35 self._upstream = upstream | |
36 self._distance = None | |
37 self._issue_status = None | |
38 | |
39 def GetStatus(self): | |
40 if not self._issue_status: | |
41 if self.GetIssue(): | |
42 try: | |
43 issue_properties = self.RpcServer().get_issue_properties( | |
44 self.GetIssue(), None) | |
45 if issue_properties['closed']: | |
46 self._issue_status = 'closed' | |
47 else: | |
48 self._issue_status = 'pending' | |
49 except urllib2.HTTPError, e: | |
50 if e.code == 404: | |
51 self._issue_status = 'abandoned' | |
52 else: | |
53 self._issue_status = 'no-issue' | |
54 if (self._issue_status != 'pending' | |
55 and self._upstream | |
56 and not self.GetDistance()[0] | |
57 and not self._upstream.startswith("origin/")): | |
58 self._issue_status = 'empty' | |
59 return self._issue_status | |
60 | |
61 def GetDistance(self): | |
62 if self._upstream is None: | |
63 return None; | |
64 if not self._distance: | |
65 self._distance = [get_change_count(self._upstream, self.GetBranch()), | |
66 get_change_count(self.GetBranch(), self._upstream)] | |
67 return self._distance | |
68 | |
69 def GetDistanceInfo(self): | |
70 if not self._upstream: | |
71 return "<No upstream branch>" | |
72 formatted_dist = ", ".join(["%s %d" % (x,y) | |
73 for (x,y) in zip(["ahead","behind"], self.GetDistance()) if y]) | |
74 return "[%s%s]" % ( | |
75 self._upstream, ": " + formatted_dist if formatted_dist else "") | |
76 | |
77 def print_branches(title, fmt, branches): | |
78 if branches: | |
79 print title | |
80 for branch in branches: | |
81 print fmt.format(branch=branch.GetBranch(), | |
82 issue=branch.GetIssue(), | |
83 distance=branch.GetDistanceInfo()) | |
84 | |
85 def main(): | |
86 parser = optparse.OptionParser(usage=sys.modules['__main__'].__doc__) | |
87 options, args = parser.parse_args() | |
88 if args: | |
89 parser.error('Unsupported arg: %s' % args) | |
90 | |
91 branches = get_branches() | |
92 filtered = { 'closed' : [], | |
93 'empty' : [], | |
94 'pending' : [], | |
95 'abandoned' : [], | |
96 'no-issue' : []} | |
97 | |
98 for branch in branches: | |
99 filtered[branch.GetStatus()].append(branch) | |
100 | |
101 print_branches("# Branches with closed issues", | |
102 "git branch -D {branch} # Issue {issue} is closed.", | |
103 filtered['closed']) | |
104 print_branches("\n# Empty branches", | |
105 "git branch -D {branch} # Empty.", | |
106 filtered['empty']) | |
107 print_branches("\n# Pending Branches", | |
108 "# Branch {branch} - Issue {issue} - {distance}", | |
109 filtered['pending']); | |
110 print_branches("\n# Branches with abandoned issues", | |
111 "# Branch {branch} - was issue {issue} - {distance}", | |
112 filtered['abandoned']) | |
113 | |
114 print_branches("\n# Branches without associated issues", | |
115 "# Branch {branch} - {distance}", | |
116 filtered['no-issue']) | |
117 | |
118 return 0 | |
119 | |
120 | |
121 if __name__ == '__main__': | |
122 sys.exit(main()) | |
OLD | NEW |