Skip to content

Commit 19ba6af

Browse files
committed
Merge pull request #32 from codebykat/changeset-comments
Add line-level comments on changesets
2 parents 72fc224 + 29bb1a7 commit 19ba6af

9 files changed

Lines changed: 197 additions & 60 deletions

File tree

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ in context, below the line in question.
3030

3131
* Comments on changesets – useful when doing code reviews of incoming commits.
3232

33+
* Inline comments on changesets - comment on a specific line of the changeset.
34+
3335
* Comments on attachment pages – useful when reviewing patches.
3436

3537
* Wiki Markup – you can use the standard Trac wiki markup inside your
@@ -70,11 +72,11 @@ Roadmap
7072

7173
Nobody can predict the future, but here are some features on the roadmap:
7274

73-
* Line-level comments for changesets and diff attachments, too
75+
* Line-level comments for diff attachments, too
7476
* E-mail notifications
7577

7678
License
7779
-------
7880
Copyright (C) 2011-2012, Automattic Inc.
7981

80-
This plugin is distributed under the GPLv2 or later license.
82+
This plugin is distributed under the GPLv2 or later license.

code_comments/comment.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,17 @@ def __init__(self, req, env, data):
3838
self.req = req
3939
if self._empty('version'):
4040
self.version = VERSION
41+
if self._empty( 'path' ):
42+
self.path = ''
4143
self.html = format_to_html(self.req, self.env, self.text)
4244
email = self.email_map().get(self.author, 'baba@baba.net')
4345
self.email_md5 = md5_hexdigest(email)
4446
attachment_info = self.attachment_info()
45-
self.is_comment_to_attachment = attachment_info['is']
47+
self.is_comment_to_attachment = 'attachment' == self.type
4648
self.attachment_ticket = attachment_info['ticket']
4749
self.attachment_filename = attachment_info['filename']
48-
self.is_comment_to_changeset = self.revision and not self.path
49-
self.is_comment_to_file = self.revision and self.path
50+
self.is_comment_to_changeset = 'changeset' == self.type
51+
self.is_comment_to_file = 'browser' == self.type
5052

5153
def _empty(self, column_name):
5254
return not hasattr(self, column_name) or not getattr(self, column_name)
@@ -71,25 +73,31 @@ def href(self):
7173
href = self.req.href.changeset(self.revision, codecomment=self.id)
7274
elif self.is_comment_to_attachment:
7375
href = self.req.href('/attachment/ticket/%d/%s' % (self.attachment_ticket, self.attachment_filename), codecomment=self.id)
74-
if self.line:
76+
if self.line and not self.is_comment_to_changeset:
7577
href += '#L' + str(self.line)
7678
return href
7779

7880
def link_text(self):
79-
if self.revision and not self.path:
80-
return '[%s]' % self.revision
81-
if self.path.startswith('attachment:'):
81+
if self.is_comment_to_changeset:
82+
return self.changeset_link_text()
83+
if self.is_comment_to_attachment:
8284
return self.attachment_link_text()
8385

84-
# except the two specials cases of changesets (revision-only)
85-
# and arrachments (path-only), we must always have them both
86+
# except the two special cases of changesets (revision-only)
87+
# and attachments (path-only), we must always have them both
8688
assert self.path and self.revision
8789

8890
link_text = self.path + '@' + str(self.revision)
8991
if self.line:
9092
link_text += '#L' + str(self.line)
9193
return link_text
9294

95+
def changeset_link_text(self):
96+
if 0 != self.line:
97+
return 'Changeset @%d#L%d (in %s)' % ( self.revision, self.line, self.path )
98+
else:
99+
return 'Changeset @%s' % self.revision
100+
93101
def attachment_link_text(self):
94102
return '#%s: %s' % (self.attachment_ticket, self.attachment_filename)
95103

@@ -99,9 +107,8 @@ def trac_link(self):
99107
return 'source:' + self.link_text()
100108

101109
def attachment_info(self):
102-
info = {'is': False, 'ticket': None, 'filename': None}
103-
info['is'] = self.path.startswith('attachment:')
104-
if not info['is']:
110+
info = { 'ticket': None, 'filename': None }
111+
if not self.path.startswith( 'attachment' ):
105112
return info
106113
match = re.match(r'attachment:/ticket/(\d+)/(.*)', self.path)
107114
if not match:

code_comments/db.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from trac.db.api import DatabaseManager
55

66
# Database version identifier for upgrades.
7-
db_version = 1
7+
db_version = 2
88

99
# Database schema
1010
schema = {
@@ -17,6 +17,7 @@
1717
Column('line', type='int'),
1818
Column('author'),
1919
Column('time', type='int'),
20+
Column('type'),
2021
Index(['path']),
2122
Index(['author']),
2223
],
@@ -34,15 +35,48 @@ def create_tables(env, db):
3435
cursor.execute(stmt)
3536
cursor.execute("INSERT into system values ('code_comments_schema_version', %s)",
3637
str(db_version))
38+
3739
# Upgrades
3840
def upgrade_from_1_to_2(env, db):
39-
pass
41+
# Add the new column "type"
42+
@env.with_transaction()
43+
def add_type_column( db ):
44+
cursor = db.cursor()
45+
cursor.execute( 'ALTER TABLE code_comments ADD COLUMN type TEXT' )
46+
47+
# Convert all the current comments to the new schema
48+
@env.with_transaction()
49+
def convert_comments( db ):
50+
comments = {}
51+
cursor = db.cursor()
52+
cursor.execute( 'SELECT id, path FROM code_comments' )
53+
comments = cursor.fetchall()
54+
# options:
55+
# 1: comment on file (path != "" && path != "attachment")
56+
# 2: comment on changeset (path == "")
57+
# 3: comment on attachment (path == "attachment")
58+
for comment in comments:
59+
path = comment[1]
60+
is_comment_to_attachment = path.startswith( 'attachment' )
61+
is_comment_to_file = not is_comment_to_attachment and '' != path
62+
is_comment_to_changeset = '' == path
63+
cursor = db.cursor()
64+
update = 'UPDATE code_comments SET type={0} WHERE id={1}'
65+
sql = ''
66+
67+
if is_comment_to_changeset:
68+
sql = update.format( "'changeset'", str( comment[0] ) )
69+
elif is_comment_to_attachment:
70+
sql = update.format( "'attachment'", str(comment[0] ) )
71+
elif is_comment_to_file:
72+
sql = update.format( "'browser'", str(comment[0] ) )
73+
74+
cursor.execute( sql )
4075

4176
upgrade_map = {
4277
2: upgrade_from_1_to_2
4378
}
4479

45-
4680
class CodeCommentsSetup(Component):
4781
"""Component that deals with database setup and upgrades."""
4882

code_comments/htdocs/code-comments.css

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,30 @@ tr.with-comments {
6969
background-color: #FFFFE2;
7070
border-bottom: 1px solid #998;
7171
}
72-
tr.comments {
72+
tr.comments td {
7373
border-bottom: 1px solid #998;
7474
}
75-
table.code tr {
75+
/* fixes .with-comments bottom borders on changeset view */
76+
.diff table.inline tbody.mod tr.with-comments td.r,
77+
.diff table.inline tbody.add tr.with-comments td.r {
78+
border-bottom-width: 1px;
79+
}
80+
.diff table.inline tbody.mod tr.with-comments td.l,
81+
.diff table.inline tbody.rem tr.with-comments td.l {
82+
border-bottom-width: 1px;
83+
}
84+
85+
table.code tr,
86+
.trac-diff tbody tr {
7687
height: 17px;
7788
}
78-
table.code tr:hover td {
89+
90+
table.code tr:hover td,
91+
#content table.trac-diff tbody tr:hover td {
7992
background-color: #FFFFCA;
93+
}
94+
95+
a.bubble span.ui-icon {
96+
/* this centers the icon horizontally and vertically */
97+
margin: -2px auto 0;
8098
}

0 commit comments

Comments
 (0)