Merge lp:~cjwatson/launchpad/git-mp-commits into lp:launchpad
- git-mp-commits
- Merge into devel
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 18046 |
Proposed branch: | lp:~cjwatson/launchpad/git-mp-commits |
Merge into: | lp:launchpad |
Prerequisite: | lp:~cjwatson/launchpad/git-commits-link-mps |
Diff against target: |
524 lines (+213/-73) 11 files modified
lib/lp/code/browser/branchmergeproposal.py (+16/-4) lib/lp/code/browser/tests/test_branchmergeproposal.py (+42/-7) lib/lp/code/interfaces/branchmergeproposal.py (+4/-1) lib/lp/code/model/branchmergeproposal.py (+54/-40) lib/lp/code/stories/branches/xx-code-review-comments.txt (+50/-0) lib/lp/code/templates/branchmergeproposal-index.pt (+8/-0) lib/lp/code/templates/branchmergeproposal-resubmit.pt (+21/-11) lib/lp/code/templates/codereviewcomment-reply.pt (+2/-2) lib/lp/code/templates/codereviewnewrevisions-footer.pt (+13/-5) lib/lp/code/templates/codereviewnewrevisions-header.pt (+1/-1) lib/lp/code/templates/git-macros.pt (+2/-2) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/git-mp-commits |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+294671@code.launchpad.net |
Commit message
Show unmerged and conversation-
Description of the change
Show unmerged and conversation-
The only significant oddity here is that we're using Git's idea of commit dates rather than when the commit was pushed. This will make sense from an author's point of view, but it will potentially mean that a reviewer sees commits pop up before their review comment. It arguably makes about as much sense as the approach we take with Bazaar, but it's certainly different. However, we can't emulate the Bazaar approach unless we start doing a full branch scanner and creating Revision rows for Git, which we wanted to avoid unless we had no choice, so let's go with this approach.
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/browser/branchmergeproposal.py' | |||
2 | --- lib/lp/code/browser/branchmergeproposal.py 2016-05-07 00:40:18 +0000 | |||
3 | +++ lib/lp/code/browser/branchmergeproposal.py 2016-05-18 22:37:48 +0000 | |||
4 | @@ -534,9 +534,15 @@ | |||
5 | 534 | particular time. | 534 | particular time. |
6 | 535 | """ | 535 | """ |
7 | 536 | 536 | ||
9 | 537 | def __init__(self, revisions, date, branch, diff): | 537 | def __init__(self, revisions, date, source, diff): |
10 | 538 | self.revisions = revisions | 538 | self.revisions = revisions |
12 | 539 | self.branch = branch | 539 | self.source = source |
13 | 540 | if IBranch.providedBy(source): | ||
14 | 541 | self.branch = source | ||
15 | 542 | self.git_ref = None | ||
16 | 543 | else: | ||
17 | 544 | self.branch = None | ||
18 | 545 | self.git_ref = source | ||
19 | 540 | self.has_body = False | 546 | self.has_body = False |
20 | 541 | self.has_footer = True | 547 | self.has_footer = True |
21 | 542 | # The date attribute is used to sort the comments in the conversation. | 548 | # The date attribute is used to sort the comments in the conversation. |
22 | @@ -613,7 +619,9 @@ | |||
23 | 613 | if IBranch.providedBy(source): | 619 | if IBranch.providedBy(source): |
24 | 614 | source = DecoratedBranch(source) | 620 | source = DecoratedBranch(source) |
25 | 615 | comments = [] | 621 | comments = [] |
27 | 616 | if getFeatureFlag('code.incremental_diffs.enabled'): | 622 | if (getFeatureFlag('code.incremental_diffs.enabled') and |
28 | 623 | merge_proposal.source_branch is not None): | ||
29 | 624 | # XXX cjwatson 2016-05-09: Implement for Git. | ||
30 | 617 | ranges = [ | 625 | ranges = [ |
31 | 618 | (revisions[0].revision.getLefthandParent(), | 626 | (revisions[0].revision.getLefthandParent(), |
32 | 619 | revisions[-1].revision) | 627 | revisions[-1].revision) |
33 | @@ -622,8 +630,12 @@ | |||
34 | 622 | else: | 630 | else: |
35 | 623 | diffs = [None] * len(groups) | 631 | diffs = [None] * len(groups) |
36 | 624 | for revisions, diff in zip(groups, diffs): | 632 | for revisions, diff in zip(groups, diffs): |
37 | 633 | if merge_proposal.source_branch is not None: | ||
38 | 634 | last_date_created = revisions[-1].revision.date_created | ||
39 | 635 | else: | ||
40 | 636 | last_date_created = revisions[-1]["author_date"] | ||
41 | 625 | newrevs = CodeReviewNewRevisions( | 637 | newrevs = CodeReviewNewRevisions( |
43 | 626 | revisions, revisions[-1].revision.date_created, source, diff) | 638 | revisions, last_date_created, source, diff) |
44 | 627 | comments.append(newrevs) | 639 | comments.append(newrevs) |
45 | 628 | while merge_proposal is not None: | 640 | while merge_proposal is not None: |
46 | 629 | from_superseded = merge_proposal != self.context | 641 | from_superseded = merge_proposal != self.context |
47 | 630 | 642 | ||
48 | === modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py' | |||
49 | --- lib/lp/code/browser/tests/test_branchmergeproposal.py 2016-05-18 12:15:05 +0000 | |||
50 | +++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2016-05-18 22:37:48 +0000 | |||
51 | @@ -11,6 +11,7 @@ | |||
52 | 11 | timedelta, | 11 | timedelta, |
53 | 12 | ) | 12 | ) |
54 | 13 | from difflib import unified_diff | 13 | from difflib import unified_diff |
55 | 14 | import hashlib | ||
56 | 14 | import re | 15 | import re |
57 | 15 | 16 | ||
58 | 16 | from lazr.lifecycle.event import ObjectModifiedEvent | 17 | from lazr.lifecycle.event import ObjectModifiedEvent |
59 | @@ -1031,9 +1032,12 @@ | |||
60 | 1031 | 1032 | ||
61 | 1032 | 1033 | ||
62 | 1033 | class TestBranchMergeProposalRequestReviewViewGit( | 1034 | class TestBranchMergeProposalRequestReviewViewGit( |
64 | 1034 | TestBranchMergeProposalRequestReviewViewMixin, BrowserTestCase): | 1035 | TestBranchMergeProposalRequestReviewViewMixin, GitHostingClientMixin, |
65 | 1036 | BrowserTestCase): | ||
66 | 1035 | """Test `BranchMergeProposalRequestReviewView` for Git.""" | 1037 | """Test `BranchMergeProposalRequestReviewView` for Git.""" |
67 | 1036 | 1038 | ||
68 | 1039 | layer = LaunchpadFunctionalLayer | ||
69 | 1040 | |||
70 | 1037 | def makeBranchMergeProposal(self): | 1041 | def makeBranchMergeProposal(self): |
71 | 1038 | return self.factory.makeBranchMergeProposalForGit() | 1042 | return self.factory.makeBranchMergeProposalForGit() |
72 | 1039 | 1043 | ||
73 | @@ -1261,10 +1265,10 @@ | |||
74 | 1261 | self.assertEqual('flibble', bmp.superseded_by.description) | 1265 | self.assertEqual('flibble', bmp.superseded_by.description) |
75 | 1262 | 1266 | ||
76 | 1263 | 1267 | ||
78 | 1264 | class TestResubmitBrowserGit(BrowserTestCase): | 1268 | class TestResubmitBrowserGit(GitHostingClientMixin, BrowserTestCase): |
79 | 1265 | """Browser tests for resubmitting branch merge proposals for Git.""" | 1269 | """Browser tests for resubmitting branch merge proposals for Git.""" |
80 | 1266 | 1270 | ||
82 | 1267 | layer = DatabaseFunctionalLayer | 1271 | layer = LaunchpadFunctionalLayer |
83 | 1268 | 1272 | ||
84 | 1269 | def test_resubmit_text(self): | 1273 | def test_resubmit_text(self): |
85 | 1270 | """The text of the resubmit page is as expected.""" | 1274 | """The text of the resubmit page is as expected.""" |
86 | @@ -1441,7 +1445,7 @@ | |||
87 | 1441 | [diff], | 1445 | [diff], |
88 | 1442 | [comment.diff for comment in comments]) | 1446 | [comment.diff for comment in comments]) |
89 | 1443 | 1447 | ||
91 | 1444 | def test_CodeReviewNewRevisions_implements_ICodeReviewNewRevisions(self): | 1448 | def test_CodeReviewNewRevisions_implements_interface_bzr(self): |
92 | 1445 | # The browser helper class implements its interface. | 1449 | # The browser helper class implements its interface. |
93 | 1446 | review_date = datetime(2009, 9, 10, tzinfo=pytz.UTC) | 1450 | review_date = datetime(2009, 9, 10, tzinfo=pytz.UTC) |
94 | 1447 | revision_date = review_date + timedelta(days=1) | 1451 | revision_date = review_date + timedelta(days=1) |
95 | @@ -1454,6 +1458,36 @@ | |||
96 | 1454 | 1458 | ||
97 | 1455 | self.assertTrue(verifyObject(ICodeReviewNewRevisions, new_revisions)) | 1459 | self.assertTrue(verifyObject(ICodeReviewNewRevisions, new_revisions)) |
98 | 1456 | 1460 | ||
99 | 1461 | def test_CodeReviewNewRevisions_implements_interface_git(self): | ||
100 | 1462 | # The browser helper class implements its interface. | ||
101 | 1463 | review_date = datetime(2009, 9, 10, tzinfo=pytz.UTC) | ||
102 | 1464 | author = self.factory.makePerson() | ||
103 | 1465 | with person_logged_in(author): | ||
104 | 1466 | author_email = author.preferredemail.email | ||
105 | 1467 | epoch = datetime.fromtimestamp(0, tz=pytz.UTC) | ||
106 | 1468 | review_date = self.factory.getUniqueDate() | ||
107 | 1469 | commit_date = self.factory.getUniqueDate() | ||
108 | 1470 | bmp = self.factory.makeBranchMergeProposalForGit( | ||
109 | 1471 | date_created=review_date) | ||
110 | 1472 | hosting_client = FakeMethod() | ||
111 | 1473 | hosting_client.getLog = FakeMethod(result=[ | ||
112 | 1474 | { | ||
113 | 1475 | u'sha1': unicode(hashlib.sha1(b'0').hexdigest()), | ||
114 | 1476 | u'message': u'0', | ||
115 | 1477 | u'author': { | ||
116 | 1478 | u'name': author.display_name, | ||
117 | 1479 | u'email': author_email, | ||
118 | 1480 | u'time': int((commit_date - epoch).total_seconds()), | ||
119 | 1481 | }, | ||
120 | 1482 | } | ||
121 | 1483 | ]) | ||
122 | 1484 | self.useFixture(ZopeUtilityFixture(hosting_client, IGitHostingClient)) | ||
123 | 1485 | |||
124 | 1486 | view = create_initialized_view(bmp, '+index') | ||
125 | 1487 | new_commits = view.conversation.comments[0] | ||
126 | 1488 | |||
127 | 1489 | self.assertTrue(verifyObject(ICodeReviewNewRevisions, new_commits)) | ||
128 | 1490 | |||
129 | 1457 | def test_include_superseded_comments(self): | 1491 | def test_include_superseded_comments(self): |
130 | 1458 | for x, time in zip(range(3), time_counter()): | 1492 | for x, time in zip(range(3), time_counter()): |
131 | 1459 | if x != 0: | 1493 | if x != 0: |
132 | @@ -1527,9 +1561,10 @@ | |||
133 | 1527 | self.assertThat(browser.contents, HTMLContains(expected_meta)) | 1561 | self.assertThat(browser.contents, HTMLContains(expected_meta)) |
134 | 1528 | 1562 | ||
135 | 1529 | 1563 | ||
137 | 1530 | class TestBranchMergeProposalBrowserView(BrowserTestCase): | 1564 | class TestBranchMergeProposalBrowserView( |
138 | 1565 | GitHostingClientMixin, BrowserTestCase): | ||
139 | 1531 | 1566 | ||
141 | 1532 | layer = DatabaseFunctionalLayer | 1567 | layer = LaunchpadFunctionalLayer |
142 | 1533 | 1568 | ||
143 | 1534 | def test_prerequisite_bzr(self): | 1569 | def test_prerequisite_bzr(self): |
144 | 1535 | # A prerequisite branch is rendered in the Bazaar case. | 1570 | # A prerequisite branch is rendered in the Bazaar case. |
145 | @@ -1727,7 +1762,7 @@ | |||
146 | 1727 | self.assertEqual('Eric on 2008-09-10', view.status_title) | 1762 | self.assertEqual('Eric on 2008-09-10', view.status_title) |
147 | 1728 | 1763 | ||
148 | 1729 | 1764 | ||
150 | 1730 | class TestBranchMergeProposal(BrowserTestCase): | 1765 | class TestBranchMergeProposal(GitHostingClientMixin, BrowserTestCase): |
151 | 1731 | 1766 | ||
152 | 1732 | layer = LaunchpadFunctionalLayer | 1767 | layer = LaunchpadFunctionalLayer |
153 | 1733 | 1768 | ||
154 | 1734 | 1769 | ||
155 | === modified file 'lib/lp/code/interfaces/branchmergeproposal.py' | |||
156 | --- lib/lp/code/interfaces/branchmergeproposal.py 2015-10-19 10:56:16 +0000 | |||
157 | +++ lib/lp/code/interfaces/branchmergeproposal.py 2016-05-18 22:37:48 +0000 | |||
158 | @@ -1,4 +1,4 @@ | |||
160 | 1 | # Copyright 2009-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
161 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
162 | 3 | 3 | ||
163 | 4 | """The interface for branch merge proposals.""" | 4 | """The interface for branch merge proposals.""" |
164 | @@ -429,6 +429,9 @@ | |||
165 | 429 | source branch that are not in the revision history of the target | 429 | source branch that are not in the revision history of the target |
166 | 430 | branch. These are the revisions that have been committed to the | 430 | branch. These are the revisions that have been committed to the |
167 | 431 | source branch since it branched off the target branch. | 431 | source branch since it branched off the target branch. |
168 | 432 | |||
169 | 433 | For Bazaar, this returns a sequence of `BranchRevision` objects. | ||
170 | 434 | For Git, this returns a sequence of commit information dicts. | ||
171 | 432 | """ | 435 | """ |
172 | 433 | 436 | ||
173 | 434 | def getUsersVoteReference(user): | 437 | def getUsersVoteReference(user): |
174 | 435 | 438 | ||
175 | === modified file 'lib/lp/code/model/branchmergeproposal.py' | |||
176 | --- lib/lp/code/model/branchmergeproposal.py 2015-10-13 17:24:59 +0000 | |||
177 | +++ lib/lp/code/model/branchmergeproposal.py 2016-05-18 22:37:48 +0000 | |||
178 | @@ -1,7 +1,7 @@ | |||
180 | 1 | # Copyright 2009-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
181 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
182 | 3 | 3 | ||
184 | 4 | """Database class for branch merge prosals.""" | 4 | """Database class for branch merge proposals.""" |
185 | 5 | 5 | ||
186 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
187 | 7 | __all__ = [ | 7 | __all__ = [ |
188 | @@ -36,10 +36,7 @@ | |||
189 | 36 | Int, | 36 | Int, |
190 | 37 | Reference, | 37 | Reference, |
191 | 38 | ) | 38 | ) |
196 | 39 | from storm.store import ( | 39 | from storm.store import Store |
193 | 40 | EmptyResultSet, | ||
194 | 41 | Store, | ||
195 | 42 | ) | ||
197 | 43 | from zope.component import getUtility | 40 | from zope.component import getUtility |
198 | 44 | from zope.event import notify | 41 | from zope.event import notify |
199 | 45 | from zope.interface import implementer | 42 | from zope.interface import implementer |
200 | @@ -70,8 +67,8 @@ | |||
201 | 70 | IBranchMergeProposal, | 67 | IBranchMergeProposal, |
202 | 71 | IBranchMergeProposalGetter, | 68 | IBranchMergeProposalGetter, |
203 | 72 | ) | 69 | ) |
204 | 73 | from lp.code.interfaces.branchrevision import IBranchRevision | ||
205 | 74 | from lp.code.interfaces.branchtarget import IHasBranchTarget | 70 | from lp.code.interfaces.branchtarget import IHasBranchTarget |
206 | 71 | from lp.code.interfaces.codereviewcomment import ICodeReviewComment | ||
207 | 75 | from lp.code.interfaces.codereviewinlinecomment import ( | 72 | from lp.code.interfaces.codereviewinlinecomment import ( |
208 | 76 | ICodeReviewInlineCommentSet, | 73 | ICodeReviewInlineCommentSet, |
209 | 77 | ) | 74 | ) |
210 | @@ -785,26 +782,38 @@ | |||
211 | 785 | 782 | ||
212 | 786 | def getUnlandedSourceBranchRevisions(self): | 783 | def getUnlandedSourceBranchRevisions(self): |
213 | 787 | """See `IBranchMergeProposal`.""" | 784 | """See `IBranchMergeProposal`.""" |
234 | 788 | if self.source_branch is None: | 785 | if self.source_branch is not None: |
235 | 789 | # XXX cjwatson 2015-04-16: Implement for Git somehow, perhaps by | 786 | store = Store.of(self) |
236 | 790 | # calling turnip via memcached. | 787 | source = SQL(""" |
237 | 791 | return [] | 788 | source AS ( |
238 | 792 | store = Store.of(self) | 789 | SELECT |
239 | 793 | source = SQL("""source AS (SELECT BranchRevision.branch, | 790 | BranchRevision.branch, BranchRevision.revision, |
240 | 794 | BranchRevision.revision, Branchrevision.sequence FROM | 791 | Branchrevision.sequence |
241 | 795 | BranchRevision WHERE BranchRevision.branch = %s and | 792 | FROM BranchRevision |
242 | 796 | BranchRevision.sequence IS NOT NULL ORDER BY BranchRevision.branch | 793 | WHERE |
243 | 797 | DESC, BranchRevision.sequence DESC | 794 | BranchRevision.branch = %s |
244 | 798 | LIMIT 10)""" % self.source_branch.id) | 795 | AND BranchRevision.sequence IS NOT NULL |
245 | 799 | where = SQL("""BranchRevision.revision NOT IN (SELECT revision from | 796 | ORDER BY |
246 | 800 | BranchRevision AS target where target.branch = %s and | 797 | BranchRevision.branch DESC, |
247 | 801 | BranchRevision.revision = target.revision)""" % | 798 | BranchRevision.sequence DESC |
248 | 802 | self.target_branch.id) | 799 | LIMIT 10)""" % self.source_branch.id) |
249 | 803 | using = SQL("""source as BranchRevision""") | 800 | where = SQL(""" |
250 | 804 | revisions = store.with_(source).using(using).find( | 801 | BranchRevision.revision NOT IN ( |
251 | 805 | BranchRevision, where) | 802 | SELECT revision |
252 | 806 | return list(revisions.order_by( | 803 | FROM BranchRevision AS target |
253 | 807 | Desc(BranchRevision.sequence)).config(limit=10)) | 804 | WHERE |
254 | 805 | target.branch = %s | ||
255 | 806 | AND BranchRevision.revision = target.revision)""" % | ||
256 | 807 | self.target_branch.id) | ||
257 | 808 | using = SQL("""source AS BranchRevision""") | ||
258 | 809 | revisions = store.with_(source).using(using).find( | ||
259 | 810 | BranchRevision, where) | ||
260 | 811 | return list(revisions.order_by( | ||
261 | 812 | Desc(BranchRevision.sequence)).config(limit=10)) | ||
262 | 813 | else: | ||
263 | 814 | return self.source_git_ref.getCommits( | ||
264 | 815 | self.source_git_commit_sha1, limit=10, | ||
265 | 816 | stop=self.target_git_commit_sha1) | ||
266 | 808 | 817 | ||
267 | 809 | def createComment(self, owner, subject, content=None, vote=None, | 818 | def createComment(self, owner, subject, content=None, vote=None, |
268 | 810 | review_type=None, parent=None, _date_created=DEFAULT, | 819 | review_type=None, parent=None, _date_created=DEFAULT, |
269 | @@ -1031,34 +1040,39 @@ | |||
270 | 1031 | return None | 1040 | return None |
271 | 1032 | 1041 | ||
272 | 1033 | def _getNewerRevisions(self): | 1042 | def _getNewerRevisions(self): |
273 | 1034 | if self.source_branch is None: | ||
274 | 1035 | # XXX cjwatson 2015-04-16: Implement for Git. | ||
275 | 1036 | return EmptyResultSet() | ||
276 | 1037 | start_date = self.date_review_requested | 1043 | start_date = self.date_review_requested |
277 | 1038 | if start_date is None: | 1044 | if start_date is None: |
278 | 1039 | start_date = self.date_created | 1045 | start_date = self.date_created |
281 | 1040 | return self.source_branch.getMainlineBranchRevisions( | 1046 | if self.source_branch is not None: |
282 | 1041 | start_date, self.revision_end_date, oldest_first=True) | 1047 | revisions = self.source_branch.getMainlineBranchRevisions( |
283 | 1048 | start_date, self.revision_end_date, oldest_first=True) | ||
284 | 1049 | return [ | ||
285 | 1050 | ((revision.date_created, branch_revision.sequence), | ||
286 | 1051 | branch_revision) | ||
287 | 1052 | for branch_revision, revision in revisions] | ||
288 | 1053 | else: | ||
289 | 1054 | commits = reversed(self.source_git_ref.getCommits( | ||
290 | 1055 | self.source_git_commit_sha1, stop=self.target_git_commit_sha1, | ||
291 | 1056 | start_date=start_date, end_date=self.revision_end_date)) | ||
292 | 1057 | return [ | ||
293 | 1058 | ((commit["author_date"], count), commit) | ||
294 | 1059 | for count, commit in enumerate(commits)] | ||
295 | 1042 | 1060 | ||
296 | 1043 | def getRevisionsSinceReviewStart(self): | 1061 | def getRevisionsSinceReviewStart(self): |
297 | 1044 | """Get the grouped revisions since the review started.""" | 1062 | """Get the grouped revisions since the review started.""" |
298 | 1045 | entries = [ | 1063 | entries = [ |
299 | 1046 | ((comment.date_created, -1), comment) for comment | 1064 | ((comment.date_created, -1), comment) for comment |
300 | 1047 | in self.all_comments] | 1065 | in self.all_comments] |
306 | 1048 | revisions = self._getNewerRevisions() | 1066 | entries.extend(self._getNewerRevisions()) |
302 | 1049 | entries.extend( | ||
303 | 1050 | ((revision.date_created, branch_revision.sequence), | ||
304 | 1051 | branch_revision) | ||
305 | 1052 | for branch_revision, revision in revisions) | ||
307 | 1053 | entries.sort() | 1067 | entries.sort() |
308 | 1054 | current_group = [] | 1068 | current_group = [] |
309 | 1055 | for sortkey, entry in entries: | 1069 | for sortkey, entry in entries: |
313 | 1056 | if IBranchRevision.providedBy(entry): | 1070 | if ICodeReviewComment.providedBy(entry): |
311 | 1057 | current_group.append(entry) | ||
312 | 1058 | else: | ||
314 | 1059 | if current_group != []: | 1071 | if current_group != []: |
315 | 1060 | yield current_group | 1072 | yield current_group |
316 | 1061 | current_group = [] | 1073 | current_group = [] |
317 | 1074 | else: | ||
318 | 1075 | current_group.append(entry) | ||
319 | 1062 | if current_group != []: | 1076 | if current_group != []: |
320 | 1063 | yield current_group | 1077 | yield current_group |
321 | 1064 | 1078 | ||
322 | 1065 | 1079 | ||
323 | === modified file 'lib/lp/code/stories/branches/xx-code-review-comments.txt' | |||
324 | --- lib/lp/code/stories/branches/xx-code-review-comments.txt 2015-10-06 06:48:01 +0000 | |||
325 | +++ lib/lp/code/stories/branches/xx-code-review-comments.txt 2016-05-18 22:37:48 +0000 | |||
326 | @@ -188,6 +188,56 @@ | |||
327 | 188 | 4. By ... on 2009-09-12 | 188 | 4. By ... on 2009-09-12 |
328 | 189 | and it works! | 189 | and it works! |
329 | 190 | 190 | ||
330 | 191 | The same thing works for Git. Note that the hosting client returns newest | ||
331 | 192 | log entries first. | ||
332 | 193 | |||
333 | 194 | >>> from lp.code.interfaces.githosting import IGitHostingClient | ||
334 | 195 | >>> from lp.testing.fakemethod import FakeMethod | ||
335 | 196 | >>> from lp.testing.fixture import ZopeUtilityFixture | ||
336 | 197 | |||
337 | 198 | >>> login('admin@canonical.com') | ||
338 | 199 | >>> bmp = factory.makeBranchMergeProposalForGit() | ||
339 | 200 | >>> bmp.requestReview(review_date) | ||
340 | 201 | >>> epoch = datetime.fromtimestamp(0, tz=pytz.UTC) | ||
341 | 202 | >>> commit_date = review_date + timedelta(days=1) | ||
342 | 203 | >>> hosting_client = FakeMethod() | ||
343 | 204 | >>> hosting_client.getLog = FakeMethod(result=[]) | ||
344 | 205 | >>> for i in range(2): | ||
345 | 206 | ... hosting_client.getLog.result.insert(0, { | ||
346 | 207 | ... u'sha1': unicode(i * 2) * 40, | ||
347 | 208 | ... u'message': u'Testing commits in conversation', | ||
348 | 209 | ... u'author': { | ||
349 | 210 | ... u'name': bmp.registrant.display_name, | ||
350 | 211 | ... u'email': bmp.registrant.preferredemail.email, | ||
351 | 212 | ... u'time': int((commit_date - epoch).total_seconds()), | ||
352 | 213 | ... }, | ||
353 | 214 | ... }) | ||
354 | 215 | ... hosting_client.getLog.result.insert(0, { | ||
355 | 216 | ... u'sha1': unicode(i * 2 + 1) * 40, | ||
356 | 217 | ... u'message': u'and it works!', | ||
357 | 218 | ... u'author': { | ||
358 | 219 | ... u'name': bmp.registrant.display_name, | ||
359 | 220 | ... u'email': bmp.registrant.preferredemail.email, | ||
360 | 221 | ... u'time': int((commit_date - epoch).total_seconds()), | ||
361 | 222 | ... }, | ||
362 | 223 | ... }) | ||
363 | 224 | ... commit_date += timedelta(days=1) | ||
364 | 225 | >>> url = canonical_url(bmp) | ||
365 | 226 | >>> logout() | ||
366 | 227 | |||
367 | 228 | >>> with ZopeUtilityFixture(hosting_client, IGitHostingClient): | ||
368 | 229 | ... browser.open(url) | ||
369 | 230 | >>> print_tag_with_id(browser.contents, 'conversation') | ||
370 | 231 | ~.../+git/...:... updated on 2009-09-12 ... | ||
371 | 232 | 0000000... by ... on 2009-09-11 | ||
372 | 233 | Testing commits in conversation | ||
373 | 234 | 1111111... by ... on 2009-09-11 | ||
374 | 235 | and it works! | ||
375 | 236 | 2222222... by ... on 2009-09-12 | ||
376 | 237 | Testing commits in conversation | ||
377 | 238 | 3333333... by ... on 2009-09-12 | ||
378 | 239 | and it works! | ||
379 | 240 | |||
380 | 191 | 241 | ||
381 | 192 | Inline Comments | 242 | Inline Comments |
382 | 193 | --------------- | 243 | --------------- |
383 | 194 | 244 | ||
384 | === modified file 'lib/lp/code/templates/branchmergeproposal-index.pt' | |||
385 | --- lib/lp/code/templates/branchmergeproposal-index.pt 2015-04-22 16:11:40 +0000 | |||
386 | +++ lib/lp/code/templates/branchmergeproposal-index.pt 2016-05-18 22:37:48 +0000 | |||
387 | @@ -170,6 +170,14 @@ | |||
388 | 170 | <p>Recent revisions are not available due to the source branch being remote.</p> | 170 | <p>Recent revisions are not available due to the source branch being remote.</p> |
389 | 171 | </tal:remote-branch> | 171 | </tal:remote-branch> |
390 | 172 | </tal:bzr-revisions> | 172 | </tal:bzr-revisions> |
391 | 173 | <tal:git-revisions condition="context/source_git_ref"> | ||
392 | 174 | <tal:history-available condition="context/source_git_ref/has_commits" | ||
393 | 175 | define="ref context/source_git_ref; | ||
394 | 176 | commit_infos view/unlanded_revisions"> | ||
395 | 177 | <h2>Unmerged commits</h2> | ||
396 | 178 | <metal:commits use-macro="ref/@@+macros/ref-commits"/> | ||
397 | 179 | </tal:history-available> | ||
398 | 180 | </tal:git-revisions> | ||
399 | 173 | </div> | 181 | </div> |
400 | 174 | </div> | 182 | </div> |
401 | 175 | 183 | ||
402 | 176 | 184 | ||
403 | === modified file 'lib/lp/code/templates/branchmergeproposal-resubmit.pt' | |||
404 | --- lib/lp/code/templates/branchmergeproposal-resubmit.pt 2015-04-28 16:39:15 +0000 | |||
405 | +++ lib/lp/code/templates/branchmergeproposal-resubmit.pt 2016-05-18 22:37:48 +0000 | |||
406 | @@ -24,18 +24,28 @@ | |||
407 | 24 | </div> | 24 | </div> |
408 | 25 | </div> | 25 | </div> |
409 | 26 | 26 | ||
417 | 27 | <div id="source-revisions" tal:condition="context/source_branch"> | 27 | <div id="source-revisions"> |
418 | 28 | <tal:history-available condition="context/source_branch/revision_count" | 28 | <tal:bzr-revisions condition="context/source_branch"> |
419 | 29 | define="branch context/source_branch; | 29 | <tal:history-available condition="context/source_branch/revision_count" |
420 | 30 | revisions view/unlanded_revisions"> | 30 | define="branch context/source_branch; |
421 | 31 | <h2>Unmerged revisions</h2> | 31 | revisions view/unlanded_revisions"> |
422 | 32 | <metal:landing-target use-macro="branch/@@+macros/branch-revisions"/> | 32 | <h2>Unmerged revisions</h2> |
423 | 33 | </tal:history-available> | 33 | <metal:landing-target use-macro="branch/@@+macros/branch-revisions"/> |
424 | 34 | </tal:history-available> | ||
425 | 34 | 35 | ||
430 | 35 | <tal:remote-branch condition="context/source_branch/branch_type/enumvalue:REMOTE"> | 36 | <tal:remote-branch condition="context/source_branch/branch_type/enumvalue:REMOTE"> |
431 | 36 | <h2>Unmerged revisions</h2> | 37 | <h2>Unmerged revisions</h2> |
432 | 37 | <p>Recent revisions are not available due to the source branch being remote.</p> | 38 | <p>Recent revisions are not available due to the source branch being remote.</p> |
433 | 38 | </tal:remote-branch> | 39 | </tal:remote-branch> |
434 | 40 | </tal:bzr-revisions> | ||
435 | 41 | <tal:git-revisions condition="context/source_git_ref"> | ||
436 | 42 | <tal:history-available condition="context/source_git_ref/has_commits" | ||
437 | 43 | define="ref context/source_git_ref; | ||
438 | 44 | commit_infos view/unlanded_revisions"> | ||
439 | 45 | <h2>Unmerged commits</h2> | ||
440 | 46 | <metal:commits use-macro="ref/@@+macros/ref-commits"/> | ||
441 | 47 | </tal:history-available> | ||
442 | 48 | </tal:git-revisions> | ||
443 | 39 | </div> | 49 | </div> |
444 | 40 | 50 | ||
445 | 41 | </div> | 51 | </div> |
446 | 42 | 52 | ||
447 | === modified file 'lib/lp/code/templates/codereviewcomment-reply.pt' | |||
448 | --- lib/lp/code/templates/codereviewcomment-reply.pt 2016-01-21 03:23:01 +0000 | |||
449 | +++ lib/lp/code/templates/codereviewcomment-reply.pt 2016-05-18 22:37:48 +0000 | |||
450 | @@ -8,8 +8,8 @@ | |||
451 | 8 | 8 | ||
452 | 9 | <body> | 9 | <body> |
453 | 10 | <h1 metal:fill-slot="heading" | 10 | <h1 metal:fill-slot="heading" |
456 | 11 | tal:define="branch view/branch_merge_proposal/merge_source"> | 11 | tal:define="source view/branch_merge_proposal/merge_source"> |
457 | 12 | Code review comment for <tal:source content="branch/identity"/> | 12 | Code review comment for <tal:source content="source/identity"/> |
458 | 13 | </h1> | 13 | </h1> |
459 | 14 | 14 | ||
460 | 15 | <div metal:fill-slot="main"> | 15 | <div metal:fill-slot="main"> |
461 | 16 | 16 | ||
462 | === modified file 'lib/lp/code/templates/codereviewnewrevisions-footer.pt' | |||
463 | --- lib/lp/code/templates/codereviewnewrevisions-footer.pt 2015-06-23 17:30:39 +0000 | |||
464 | +++ lib/lp/code/templates/codereviewnewrevisions-footer.pt 2016-05-18 22:37:48 +0000 | |||
465 | @@ -3,11 +3,19 @@ | |||
466 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
467 | 4 | omit-tag=""> | 4 | omit-tag=""> |
468 | 5 | 5 | ||
474 | 6 | <tal:revisions define="branch context/branch; | 6 | <tal:bzr-revisions condition="context/branch"> |
475 | 7 | revisions context/revisions; | 7 | <tal:revisions define="branch context/branch; |
476 | 8 | show_diff_expander python:True;"> | 8 | revisions context/revisions; |
477 | 9 | <metal:landing-target use-macro="branch/@@+macros/branch-revisions"/> | 9 | show_diff_expander python:True;"> |
478 | 10 | </tal:revisions> | 10 | <metal:revisions use-macro="branch/@@+macros/branch-revisions"/> |
479 | 11 | </tal:revisions> | ||
480 | 12 | </tal:bzr-revisions> | ||
481 | 13 | <tal:git-revisions condition="context/git_ref"> | ||
482 | 14 | <tal:revisions define="ref context/git_ref; | ||
483 | 15 | commit_infos context/revisions;"> | ||
484 | 16 | <metal:commits use-macro="ref/@@+macros/ref-commits"/> | ||
485 | 17 | </tal:revisions> | ||
486 | 18 | </tal:git-revisions> | ||
487 | 11 | <tal:has-diff condition="context/diff"> | 19 | <tal:has-diff condition="context/diff"> |
488 | 12 | <tal:diff condition="not: request/ss|nothing" | 20 | <tal:diff condition="not: request/ss|nothing" |
489 | 13 | replace="structure context/diff/text/fmt:diff" /> | 21 | replace="structure context/diff/text/fmt:diff" /> |
490 | 14 | 22 | ||
491 | === modified file 'lib/lp/code/templates/codereviewnewrevisions-header.pt' | |||
492 | --- lib/lp/code/templates/codereviewnewrevisions-header.pt 2009-12-10 01:33:59 +0000 | |||
493 | +++ lib/lp/code/templates/codereviewnewrevisions-header.pt 2016-05-18 22:37:48 +0000 | |||
494 | @@ -3,7 +3,7 @@ | |||
495 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
496 | 4 | omit-tag=""> | 4 | omit-tag=""> |
497 | 5 | 5 | ||
499 | 6 | <tal:branch replace="structure context/branch/fmt:link"/> | 6 | <tal:source replace="structure context/source/fmt:link"/> |
500 | 7 | updated | 7 | updated |
501 | 8 | <tal:date replace="context/date/fmt:displaydate" /> | 8 | <tal:date replace="context/date/fmt:displaydate" /> |
502 | 9 | 9 | ||
503 | 10 | 10 | ||
504 | === modified file 'lib/lp/code/templates/git-macros.pt' | |||
505 | --- lib/lp/code/templates/git-macros.pt 2016-05-18 11:49:31 +0000 | |||
506 | +++ lib/lp/code/templates/git-macros.pt 2016-05-18 22:37:48 +0000 | |||
507 | @@ -135,7 +135,7 @@ | |||
508 | 135 | sha1 python:commit_info['sha1']; | 135 | sha1 python:commit_info['sha1']; |
509 | 136 | author python:commit_info['author']; | 136 | author python:commit_info['author']; |
510 | 137 | author_date python:commit_info['author_date']"> | 137 | author_date python:commit_info['author_date']"> |
512 | 138 | <a tal:attributes="href python: context.getCodebrowseUrlForRevision(sha1)" | 138 | <a tal:attributes="href python: ref.getCodebrowseUrlForRevision(sha1)" |
513 | 139 | tal:content="sha1/fmt:shorten/10" /> | 139 | tal:content="sha1/fmt:shorten/10" /> |
514 | 140 | by | 140 | by |
515 | 141 | <tal:known-person condition="author/person"> | 141 | <tal:known-person condition="author/person"> |
516 | @@ -153,7 +153,7 @@ | |||
517 | 153 | replace="structure commit_message/fmt:obfuscate-email/fmt:text-to-html" /> | 153 | replace="structure commit_message/fmt:obfuscate-email/fmt:text-to-html" /> |
518 | 154 | </dd> | 154 | </dd> |
519 | 155 | 155 | ||
521 | 156 | <div tal:define="merge_proposal python:commit_info['merge_proposal']" | 156 | <div tal:define="merge_proposal python:commit_info.get('merge_proposal')" |
522 | 157 | tal:condition="merge_proposal"> | 157 | tal:condition="merge_proposal"> |
523 | 158 | <dd class="subordinate commit-comment" | 158 | <dd class="subordinate commit-comment" |
524 | 159 | tal:define="committer_date merge_proposal/merge_source/committer_date|nothing"> | 159 | tal:define="committer_date merge_proposal/merge_source/committer_date|nothing"> |