Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(220)

Side by Side Diff: chromite/bin/cros_changelog

Issue 4175007: Tool for printing changelog descriptions. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """Helper script for printing differences between tags."""
8
9 import cgi
10 from datetime import datetime
11 import os
12 import re
13 import sys
14
15 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../lib'))
16 from cros_build_lib import RunCommand
17
18 DEFAULT_TRACKER = 'chromium-os'
19
20
21 def _GrabOutput(cmd):
22 """Returns output from specified command."""
23 return RunCommand(cmd, shell=True, print_cmd=False,
24 redirect_stdout=True).output
25
26
27 def _GrabTags():
28 """Returns list of tags from current git repository."""
diandersAtChromium 2010/10/28 20:36:15 It would be a lot easier to understand / make chan
David James 2010/10/28 20:52:52 Good idea. Could you add a TODO for this? This cod
29 cmd = ("git for-each-ref refs/tags | awk '{print $3}' | "
30 "sed 's,refs/tags/,,g' | sort -t. -k3,3rn -k4,4rn")
31 return _GrabOutput(cmd).split()
32
33
34 def _GrabDirs():
35 """Returns list of directories managed by repo."""
36 return _GrabOutput('repo forall -c "pwd"').split()
37
38
39 class Commit(object):
40 """Class for tracking git commits."""
41
42 def __init__(self, commit, projectname, commit_email, commit_date, subject,
43 body):
44 """Create commit logs."""
diandersAtChromium 2010/10/28 20:36:15 Seems like parameters should be documented here?
David James 2010/10/28 20:52:52 +1
45 self.commit = commit
46 self.projectname = projectname
47 self.commit_email = commit_email
48 fmt = '%a %b %d %H:%M:%S %Y'
49 self.commit_date = datetime.strptime(commit_date, fmt)
50 self.subject = subject
51 self.body = body
52 self.bug_ids = self._GetBugIDs()
53
54 def _GetBugIDs(self):
55 """Get bug ID from commit logs."""
diandersAtChromium 2010/10/28 20:36:15 Describe inputs and outputs for this function: inp
David James 2010/10/28 20:52:52 +1
56
diandersAtChromium 2010/10/28 20:36:15 Some comments about what this is doing would be ap
David James 2010/10/28 20:52:52 +1. We should also mention it's copied from bugdro
57 entries = []
58 for line in self.body.split('\n'):
59 match = re.match(r'^ *BUG *=(.*)', line)
60 if match:
61 for i in match.group(1).split(','):
62 entries.extend(filter(None, [x.strip() for x in i.split()]))
63
64 bug_ids = []
65 last_tracker = DEFAULT_TRACKER
66 regex = (r'http://code.google.com/p/(\S+)/issues/detail\?id=([0-9]+)'
67 r'|(\S+):([0-9]+)|(\b[0-9]+\b)')
68
69 for new_item in entries:
70 bug_numbers = re.findall(regex, new_item)
71 for bug_tuple in bug_numbers:
72 if bug_tuple[0] and bug_tuple[1]:
73 bug_ids.append('%s:%s' % (bug_tuple[0], bug_tuple[1]))
74 last_tracker = bug_tuple[0]
75 elif bug_tuple[2] and bug_tuple[3]:
76 bug_ids.append('%s:%s' % (bug_tuple[2], bug_tuple[3]))
77 last_tracker = bug_tuple[2]
78 elif bug_tuple[4]:
79 bug_ids.append('%s:%s' % (last_tracker, bug_tuple[4]))
80
81 bug_ids.sort(key=str.lower)
82 return bug_ids
83
84 def AsHTMLTableRow(self):
85 """Returns HTML for this change, for printing as part of a table.
86
87 Columns: Project, Date, Commit, Committer, Bugs, Subject.
88 """
89
90 bugs = []
91 bug_url_fmt = 'http://code.google.com/p/%s/issues/detail?id=%s'
92 link_fmt = '<a href="%s">%s</a>'
93 for bug in self.bug_ids:
94 tracker, bug_id = bug.split(':')
95
96 # Get bug URL. We use short URLs to make the URLs a bit more readable.
97 if tracker == 'chromium-os':
98 bug_url = 'http://crosbug.com/%s' % bug_id
99 elif tracker == 'chrome-os-partner':
100 bug_url = 'http://crosbug.com/p/%s' % bug_id
101 else:
102 bug_url = bug_url_fmt % (tracker, bug_id)
103
104 bugs.append(link_fmt % (bug_url, bug))
105
106 url_fmt = 'http://chromiumos-git/git/?p=%s.git;a=commitdiff;h=%s'
David McMahon 2010/10/28 02:30:44 Probably want to use gitrw.chromium.org:9222.
diandersAtChromium 2010/10/28 20:36:15 I'm not sure I understand this comment. I think t
David James 2010/10/28 20:52:52 Yeah. That was a misunderstanding. djmm and I disc
107 url = url_fmt % (self.projectname, self.commit)
108 commit_desc = link_fmt % (url, self.commit[:8])
109 bug_str = '<br>'.join(bugs)
110 if not bug_str:
111 if (self.projectname == 'kernel-next' or
112 self.commit_email == 'chrome-bot@chromium.org'):
113 bug_str = 'not needed'
114 else:
115 bug_str = '<font color="red">none</font>'
116
117 cols = [
118 cgi.escape(self.projectname),
119 str(self.commit_date),
120 commit_desc,
121 cgi.escape(self.commit_email),
122 bug_str,
123 cgi.escape(self.subject[:100]),
124 ]
125 return '<tr><td>%s</td></tr>' % ('</td><td>'.join(cols))
126
127 def __cmp__(self, other):
128 """Compare two Commit objects first by project name, then by date."""
129 return (cmp(self.projectname, other.projectname) or
130 cmp(self.commit_date, other.commit_date))
131
132
133 def _GrabChanges(path, tag1, tag2):
134 """Return list of commits to path between tag1 and tag2."""
diandersAtChromium 2010/10/28 20:36:15 Would be nice to see parameters / return values co
David James 2010/10/28 20:52:52 +1
135
136 cmd = 'cd %s && git config --get remote.cros.projectname' % path
137 projectname = _GrabOutput(cmd).strip()
138 log_fmt = '%x00%H\t%ce\t%cd\t%s\t%b'
139 cmd_fmt = 'cd %s && git log --format="%s" --date=local %s..%s'
140 cmd = cmd_fmt % (path, log_fmt, tag1, tag2)
141 output = _GrabOutput(cmd)
142 commits = []
143 for log_data in output.split('\0')[1:]:
144 commit, commit_email, commit_date, subject, body = log_data.split('\t', 4)
145 change = Commit(commit, projectname, commit_email, commit_date, subject,
146 body)
147 commits.append(change)
148 return commits
149
150
151 def main():
152 tags = _GrabTags()
153 tag1 = None
154 if len(sys.argv) == 3:
155 tag1 = sys.argv[1]
156 tag2 = sys.argv[2]
157 elif len(sys.argv) == 2:
158 tag2 = sys.argv[1]
159 else:
160 print >>sys.stderr, 'Usage: %s [tag1] tag2' % sys.argv[0]
161 print >>sys.stderr, 'If only one tag is specified, we view the differences'
162 print >>sys.stderr, 'between that tag and the previous tag. You can also'
163 print >>sys.stderr, 'specify cros/master to show differences with'
164 print >>sys.stderr, 'tip-of-tree.'
165 sys.exit(1)
166 if not tag2.startswith('cros/') and tag2 not in tags:
167 print >>sys.stderr, 'Unrecognized tag: %s' % tag2
168 sys.exit(1)
169 if not tag1:
diandersAtChromium 2010/10/28 20:36:15 Should be "if tag1 is None" unless you really want
David James 2010/10/28 20:52:52 Empty string is bad too, so let's leave this as-is
170 tag1 = tags[tags.index(tag2) + 1]
diandersAtChromium 2010/10/28 20:36:15 Potential out of bounds issue here if tag2 is the
David James 2010/10/28 20:52:52 +1, please fix
171 if not tag1.startswith('cros/') and tag1 not in tags:
172 print >>sys.stderr, 'Unrecognized tag: %s' % tag1
173 sys.exit(1)
174
175 print >>sys.stderr, 'Finding differences between %s and %s' % (tag1, tag2)
176 paths = _GrabDirs()
177 changes = []
178 for path in paths:
179 changes.extend(_GrabChanges(path, tag1, tag2))
180
181 title = 'Changelog for %s to %s' % (tag1, tag2)
182 print '<html>'
183 print '<head><title>%s</title></head>' % title
184 print '<h1>%s</h1>' % title
185 cols = ['Project', 'Date', 'Commit', 'Committer', 'Bugs', 'Subject']
186 print '<table border="1" cellpadding="4">'
187 print '<tr><th>%s</th>' % ('</th><th>'.join(cols))
188 for change in sorted(changes):
189 print change.AsHTMLTableRow()
190 print '</table>'
191 print '</html>'
192
193
194 if __name__ == '__main__':
195 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698