10312.5.5
by Jeroen Vermeulen
IBranch.composePublicURL. |
1 |
# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
|
8687.15.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
8511.2.5
by Aaron Bentley
Fix lint errors |
4 |
# pylint: disable-msg=E0611,W0212,W0141,F0401
|
1670
by Canonical.com Patch Queue Manager
Big lot of database clean-up r=stub except for resolution of conflicts. |
5 |
|
6 |
__metaclass__ = type |
|
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
7 |
__all__ = [ |
8 |
'Branch', |
|
9 |
'BranchSet', |
|
10 |
]
|
|
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
11 |
|
6233.4.1
by Paul Hummer
Removed the hide_dormant checkbox |
12 |
from datetime import datetime |
11822.4.3
by Robert Collins
Really drop last uses of prejoin. |
13 |
import operator |
3215.1.4
by Andrew Bennetts
Use properly validated URLs in the configuration, as suggested by Bjorn. |
14 |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
15 |
from bzrlib import urlutils |
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
16 |
from bzrlib.revision import NULL_REVISION |
4652.1.7
by Jonathan Lange
Use mirror_request_time for all branches, making sure that mirrorComplete |
17 |
import pytz |
12499.1.6
by Leonard Richardson
Fix imports. |
18 |
import simplejson |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
19 |
from sqlobject import ( |
20 |
BoolCol, |
|
21 |
ForeignKey, |
|
22 |
IntCol, |
|
23 |
SQLMultipleJoin, |
|
24 |
SQLRelatedJoin, |
|
25 |
StringCol, |
|
26 |
)
|
|
27 |
from storm.expr import ( |
|
28 |
And, |
|
29 |
Count, |
|
30 |
Desc, |
|
31 |
NamedFunc, |
|
32 |
Not, |
|
33 |
Or, |
|
34 |
Select, |
|
35 |
)
|
|
7675.887.20
by Paul Hummer
Added IBranch.addToQueue with accompanying tests |
36 |
from storm.locals import ( |
37 |
AutoReload, |
|
38 |
Int, |
|
39 |
Reference, |
|
40 |
)
|
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
41 |
from storm.store import Store |
5543.8.4
by Tim Penhey
Hooks in progress. |
42 |
from zope.component import getUtility |
43 |
from zope.event import notify |
|
7735.3.1
by Aaron Bentley
Split branchjob out of branch |
44 |
from zope.interface import implements |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
45 |
from zope.security.proxy import ( |
46 |
ProxyFactory, |
|
47 |
removeSecurityProxy, |
|
48 |
)
|
|
10312.5.5
by Jeroen Vermeulen
IBranch.composePublicURL. |
49 |
|
3215.1.3
by Andrew Bennetts
Generate different pull_urls for imported branches, and add some configuration options for pull url prefixes. |
50 |
from canonical.config import config |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
51 |
from canonical.database.constants import ( |
52 |
DEFAULT, |
|
53 |
UTC_NOW, |
|
54 |
)
|
|
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
55 |
from canonical.database.datetimecol import UtcDateTimeCol |
3691.373.5
by Christian Reis
Move DBSchema and Item into webapp.enum, and put EnumCol into canonical.database.enumcol |
56 |
from canonical.database.enumcol import EnumCol |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
57 |
from canonical.database.sqlbase import ( |
58 |
SQLBase, |
|
59 |
sqlvalues, |
|
60 |
)
|
|
5616.2.5
by Aaron Bentley
Corrections from make lint |
61 |
from canonical.launchpad import _ |
11822.4.3
by Robert Collins
Really drop last uses of prejoin. |
62 |
from canonical.launchpad.components.decoratedresultset import ( |
63 |
DecoratedResultSet, |
|
64 |
)
|
|
12457.2.6
by Robert Collins
Review feedback: use a shortlist, don't spread the any pollution of default symbols. Docstring fixup and unbreak the legacy linked_bugs. |
65 |
from canonical.launchpad.helpers import shortlist |
11134.6.2
by Tim Penhey
More interface mangling. |
66 |
from canonical.launchpad.interfaces.launchpad import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
67 |
ILaunchpadCelebrities, |
68 |
IPrivacy, |
|
69 |
)
|
|
7675.814.4
by Tim Penhey
Add implementation and remove lint. |
70 |
from canonical.launchpad.interfaces.lpstorm import IMasterStore |
8225.3.2
by Tim Penhey
Sort the imports. |
71 |
from canonical.launchpad.webapp import urlappend |
7675.708.15
by Tim Penhey
Add the check to make sure that the user unsubscribing actually is allowed to. |
72 |
from lp.app.errors import UserCannotUnsubscribePerson |
12457.2.3
by Robert Collins
Lock down scaling of branch:+index for product bugtasks - still to do productseries and distroseries. |
73 |
from lp.bugs.interfaces.bugtask import ( |
12499.1.24
by Leonard Richardson
Added missing import. |
74 |
BugTaskSearchParams, |
12457.2.3
by Robert Collins
Lock down scaling of branch:+index for product bugtasks - still to do productseries and distroseries. |
75 |
IBugTaskSet, |
76 |
)
|
|
12588.3.21
by Tim Penhey
Remove branch specific bug task filtering, and add the possibility of titles to the generic link formatter. |
77 |
from lp.bugs.interfaces.bugtaskfilter import filter_bugtasks_by_context |
11134.3.2
by Jeroen Vermeulen
Clean up BuildQueues for BranchJobs. |
78 |
from lp.buildmaster.model.buildqueue import BuildQueue |
8555.2.1
by Tim Penhey
Create lp/code level modules for enums, separating out those that rely on bzrlib. |
79 |
from lp.code.bzr import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
80 |
BranchFormat, |
81 |
ControlFormat, |
|
82 |
CURRENT_BRANCH_FORMATS, |
|
83 |
CURRENT_REPOSITORY_FORMATS, |
|
84 |
RepositoryFormat, |
|
85 |
)
|
|
8555.2.2
by Tim Penhey
Move enum -> enums. |
86 |
from lp.code.enums import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
87 |
BranchLifecycleStatus, |
88 |
BranchMergeProposalStatus, |
|
89 |
BranchType, |
|
90 |
)
|
|
7675.429.3
by Tim Penhey
Move merge proposal errors to lp.code.errors. |
91 |
from lp.code.errors import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
92 |
BranchCannotBePrivate, |
93 |
BranchCannotBePublic, |
|
94 |
BranchMergeProposalExists, |
|
95 |
BranchTargetError, |
|
96 |
BranchTypeError, |
|
97 |
CannotDeleteBranch, |
|
98 |
InvalidBranchMergeProposal, |
|
7675.887.21
by Paul Hummer
Added IBranch.setMergeQueueConfig with accompanying tests |
99 |
InvalidMergeQueueConfig, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
100 |
)
|
11733.1.4
by Tim Penhey
Add an extra event for the needs review, but keep the same functionality for now. |
101 |
from lp.code.event.branchmergeproposal import ( |
102 |
BranchMergeProposalNeedsReviewEvent, |
|
103 |
NewBranchMergeProposalEvent, |
|
104 |
)
|
|
8225.3.2
by Tim Penhey
Sort the imports. |
105 |
from lp.code.interfaces.branch import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
106 |
BzrIdentityMixin, |
107 |
DEFAULT_BRANCH_STATUS_IN_LISTING, |
|
108 |
IBranch, |
|
109 |
IBranchNavigationMenu, |
|
110 |
IBranchSet, |
|
111 |
user_has_special_branch_access, |
|
112 |
)
|
|
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
113 |
from lp.code.interfaces.branchcollection import IAllBranches |
8777.4.6
by Jonathan Lange
Merge the new branches interface with branch set. |
114 |
from lp.code.interfaces.branchlookup import IBranchLookup |
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
115 |
from lp.code.interfaces.branchmergeproposal import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
116 |
BRANCH_MERGE_PROPOSAL_FINAL_STATES, |
117 |
)
|
|
8137.17.24
by Barry Warsaw
thread merge |
118 |
from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy |
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
119 |
from lp.code.interfaces.branchpuller import IBranchPuller |
120 |
from lp.code.interfaces.branchtarget import IBranchTarget |
|
12707.4.8
by Tim Penhey
Support the branch-id alias in the setting of the stacked on branch in the model code. |
121 |
from lp.code.interfaces.codehosting import ( |
122 |
BRANCH_ID_ALIAS_PREFIX, |
|
123 |
compose_public_url, |
|
124 |
)
|
|
8211.4.12
by Jonathan Lange
Allow branches linked to source packages to be deleted. |
125 |
from lp.code.interfaces.seriessourcepackagebranch import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
126 |
IFindOfficialBranchLinks, |
127 |
)
|
|
128 |
from lp.code.mail.branch import send_branch_modified_notifications |
|
129 |
from lp.code.model.branchmergeproposal import ( |
|
130 |
BranchMergeProposal, |
|
131 |
BranchMergeProposalGetter, |
|
132 |
)
|
|
133 |
from lp.code.model.branchrevision import BranchRevision |
|
134 |
from lp.code.model.branchsubscription import BranchSubscription |
|
135 |
from lp.code.model.revision import ( |
|
136 |
Revision, |
|
137 |
RevisionAuthor, |
|
138 |
)
|
|
139 |
from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch |
|
9590.1.96
by Michael Hudson
more tests, documentation, make getBzrBranch use safe_open |
140 |
from lp.codehosting.bzrutils import safe_open |
7675.759.17
by Brad Crittenden
Reverted removal of validate_person. |
141 |
from lp.registry.interfaces.person import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
142 |
validate_person, |
143 |
validate_public_person, |
|
144 |
)
|
|
12640.1.1
by Robert Collins
Improve query plan for getMainlineBranchRevisions by using a second set based query to get authors rather than a single wide query. |
145 |
from lp.services.database.bulk import load_related |
7675.493.2
by Paul Hummer
Fixed an issue with upgrade_pending |
146 |
from lp.services.job.interfaces.job import JobStatus |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
147 |
from lp.services.job.model.job import Job |
148 |
from lp.services.mail.notificationrecipientset import NotificationRecipientSet |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
149 |
from lp.services.propertycache import cachedproperty |
3311.1.5
by Mark Shuttleworth
Tighten up branch listings |
150 |
|
151 |
||
9080.8.19
by Tim Penhey
Change the Branch object to inherit from the bzr identity mixin class. |
152 |
class Branch(SQLBase, BzrIdentityMixin): |
1102.1.96
by David Allouche
update sqlobject and interfaces for RevisionNumber |
153 |
"""A sequence of ordered revisions in Bazaar."""
|
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
154 |
|
11134.6.2
by Tim Penhey
More interface mangling. |
155 |
implements(IBranch, IBranchNavigationMenu, IPrivacy) |
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
156 |
_table = 'Branch' |
3814.2.4
by Tim Penhey
new branch set methods |
157 |
|
4608.1.2
by Tim Penhey
More import fixes, and schema -> enum renames. |
158 |
branch_type = EnumCol(enum=BranchType, notNull=True) |
4359.2.1
by Tim Penhey
Start of minimal explicit branch type. |
159 |
|
2868.2.1
by David Allouche
[incomplete] optional-branch-title |
160 |
name = StringCol(notNull=False) |
1102.1.55
by David Allouche
populate IBranch with easy attributes |
161 |
url = StringCol(dbName='url') |
8503.2.1
by Paul Hummer
Re-introduced IBranch.description |
162 |
description = StringCol(dbName='summary') |
6465.2.1
by Aaron Bentley
Scanner stores branch, repository, control formats |
163 |
branch_format = EnumCol(enum=BranchFormat) |
164 |
repository_format = EnumCol(enum=RepositoryFormat) |
|
6465.2.15
by Aaron Bentley
Updates from review |
165 |
# XXX: Aaron Bentley 2008-06-13
|
166 |
# Rename the metadir_format in the database, see bug 239746
|
|
6465.2.1
by Aaron Bentley
Scanner stores branch, repository, control formats |
167 |
control_format = EnumCol(enum=ControlFormat, dbName='metadir_format') |
8303.16.2
by Paul Hummer
Added back in whiteboard, removed zcml for title and summary |
168 |
whiteboard = StringCol(default=None) |
2770.1.65
by Guilherme Salgado
lots of fixes |
169 |
mirror_status_message = StringCol(default=None) |
1102.1.55
by David Allouche
populate IBranch with easy attributes |
170 |
|
4190.3.10
by Tim Penhey
moved from visibility_team to private |
171 |
private = BoolCol(default=False, notNull=True) |
172 |
||
9941.1.3
by Tim Penhey
Let admins and bzr experts set privacy. |
173 |
def setPrivate(self, private, user): |
8137.17.24
by Barry Warsaw
thread merge |
174 |
"""See `IBranch`."""
|
175 |
if private == self.private: |
|
176 |
return
|
|
9941.1.5
by Tim Penhey
Two prose text updates. |
177 |
# Only check the privacy policy if the user is not special.
|
9941.1.3
by Tim Penhey
Let admins and bzr experts set privacy. |
178 |
if (not user_has_special_branch_access(user)): |
179 |
policy = IBranchNamespacePolicy(self.namespace) |
|
8137.17.24
by Barry Warsaw
thread merge |
180 |
|
9941.1.3
by Tim Penhey
Let admins and bzr experts set privacy. |
181 |
if private and not policy.canBranchesBePrivate(): |
182 |
raise BranchCannotBePrivate() |
|
183 |
if not private and not policy.canBranchesBePublic(): |
|
184 |
raise BranchCannotBePublic() |
|
8137.17.24
by Barry Warsaw
thread merge |
185 |
self.private = private |
186 |
||
5543.6.1
by Tim Penhey
Added branch registrant. |
187 |
registrant = ForeignKey( |
5485.1.21
by Edwin Grubbs
Added validator to Branch.registrant |
188 |
dbName='registrant', foreignKey='Person', |
5821.2.40
by James Henstridge
* Move all the uses of public_person_validator over to the Storm |
189 |
storm_validator=validate_public_person, notNull=True) |
5485.1.15
by Edwin Grubbs
Merged in RF |
190 |
owner = ForeignKey( |
191 |
dbName='owner', foreignKey='Person', |
|
7675.759.17
by Brad Crittenden
Reverted removal of validate_person. |
192 |
storm_validator=validate_person, notNull=True) |
8971.24.7
by Tim Penhey
Add implementation of Branch.setOwner. |
193 |
|
194 |
def setOwner(self, new_owner, user): |
|
195 |
"""See `IBranch`."""
|
|
196 |
new_namespace = self.target.getNamespace(new_owner) |
|
197 |
new_namespace.moveBranch(self, user, rename_if_necessary=True) |
|
198 |
||
5280.3.4
by Tim Penhey
Getting the interface for the merge proposal to match the tests. |
199 |
reviewer = ForeignKey( |
5485.1.13
by Edwin Grubbs
Sorta working |
200 |
dbName='reviewer', foreignKey='Person', |
5821.2.40
by James Henstridge
* Move all the uses of public_person_validator over to the Storm |
201 |
storm_validator=validate_public_person, default=None) |
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
202 |
|
203 |
product = ForeignKey(dbName='product', foreignKey='Product', default=None) |
|
1102.1.55
by David Allouche
populate IBranch with easy attributes |
204 |
|
7349.1.1
by Jonathan Lange
Cherry pick the content class stuff into a separate branch. |
205 |
distroseries = ForeignKey( |
206 |
dbName='distroseries', foreignKey='DistroSeries', default=None) |
|
207 |
sourcepackagename = ForeignKey( |
|
208 |
dbName='sourcepackagename', foreignKey='SourcePackageName', |
|
209 |
default=None) |
|
210 |
||
3864.2.15
by Tim Penhey
Moved BranchLifecycleStatus to new EnumeratedTypes |
211 |
lifecycle_status = EnumCol( |
212 |
enum=BranchLifecycleStatus, notNull=True, |
|
7675.5.1
by Tim Penhey
Remove the NEW BranchLifecycleStatus value, defaulting to DEVELOPMENT now. |
213 |
default=BranchLifecycleStatus.DEVELOPMENT) |
1102.1.55
by David Allouche
populate IBranch with easy attributes |
214 |
|
1102.1.80
by David Allouche
product/+addbranch, branch.registrant to branch.author in db patch and sample data |
215 |
last_mirrored = UtcDateTimeCol(default=None) |
3656.1.1
by James Henstridge
db changes |
216 |
last_mirrored_id = StringCol(default=None) |
1102.1.80
by David Allouche
product/+addbranch, branch.registrant to branch.author in db patch and sample data |
217 |
last_mirror_attempt = UtcDateTimeCol(default=None) |
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
218 |
mirror_failures = IntCol(default=0, notNull=True) |
5223.7.2
by jml at canonical
Rename mirror_request_time to next_mirror_time in code. |
219 |
next_mirror_time = UtcDateTimeCol(default=None) |
1102.1.55
by David Allouche
populate IBranch with easy attributes |
220 |
|
3656.1.1
by James Henstridge
db changes |
221 |
last_scanned = UtcDateTimeCol(default=None) |
222 |
last_scanned_id = StringCol(default=None) |
|
3691.290.8
by Tim Penhey
tests passing for revision changes |
223 |
revision_count = IntCol(default=DEFAULT, notNull=True) |
6125.33.5
by Jonathan Lange
Merge rename of stacked_on_branch to stacked_branch, renaming things at the |
224 |
stacked_on = ForeignKey( |
225 |
dbName='stacked_on', foreignKey='Branch', default=None) |
|
3656.1.1
by James Henstridge
db changes |
226 |
|
7675.171.1
by Tim Penhey
Add attributes for the new branch columns. |
227 |
# The unique_name is maintined by a SQL trigger.
|
228 |
unique_name = StringCol() |
|
229 |
# Denormalised colums used primarily for sorting.
|
|
230 |
owner_name = StringCol() |
|
231 |
target_suffix = StringCol() |
|
232 |
||
4652.1.4
by Jonathan Lange
Make mirror_request_time the determining variable for mirrored branches |
233 |
def __repr__(self): |
234 |
return '<Branch %r (%d)>' % (self.unique_name, self.id) |
|
235 |
||
3691.410.2
by David Allouche
adjust database.Branch to deal with RevisionNumber where sequence is NULL |
236 |
@property
|
7779.1.5
by Jonathan Lange
Change the property from 'container' to 'target' |
237 |
def target(self): |
7362.4.13
by Jonathan Lange
Add a basic context variable, call it "container" to avoid decorates() confusion. |
238 |
"""See `IBranch`."""
|
239 |
if self.product is None: |
|
240 |
if self.distroseries is None: |
|
7779.1.7
by Jonathan Lange
Use the adapter, simplifying the code a little. |
241 |
target = self.owner |
7362.4.13
by Jonathan Lange
Add a basic context variable, call it "container" to avoid decorates() confusion. |
242 |
else: |
7779.1.7
by Jonathan Lange
Use the adapter, simplifying the code a little. |
243 |
target = self.sourcepackage |
7362.4.13
by Jonathan Lange
Add a basic context variable, call it "container" to avoid decorates() confusion. |
244 |
else: |
7779.1.7
by Jonathan Lange
Use the adapter, simplifying the code a little. |
245 |
target = self.product |
246 |
return IBranchTarget(target) |
|
7362.4.13
by Jonathan Lange
Add a basic context variable, call it "container" to avoid decorates() confusion. |
247 |
|
8971.24.14
by Tim Penhey
Make setTarget actually exportable. |
248 |
def setTarget(self, user, project=None, source_package=None): |
8971.24.8
by Tim Penhey
Add setTarget for branch. |
249 |
"""See `IBranch`."""
|
8971.24.14
by Tim Penhey
Make setTarget actually exportable. |
250 |
if project is not None: |
251 |
if source_package is not None: |
|
252 |
raise BranchTargetError( |
|
253 |
'Cannot specify both a project and a source package.') |
|
254 |
else: |
|
255 |
target = IBranchTarget(project) |
|
256 |
if target is None: |
|
257 |
raise BranchTargetError( |
|
258 |
'%r is not a valid project target' % project) |
|
259 |
elif source_package is not None: |
|
260 |
target = IBranchTarget(source_package) |
|
8971.24.8
by Tim Penhey
Add setTarget for branch. |
261 |
if target is None: |
8971.24.14
by Tim Penhey
Make setTarget actually exportable. |
262 |
raise BranchTargetError( |
9222.5.4
by Aaron Bentley
Fix lint errors. |
263 |
'%r is not a valid source package target' % |
264 |
source_package) |
|
8971.24.14
by Tim Penhey
Make setTarget actually exportable. |
265 |
else: |
266 |
target = IBranchTarget(self.owner) |
|
267 |
# Person targets are always valid.
|
|
268 |
namespace = target.getNamespace(self.owner) |
|
269 |
namespace.moveBranch(self, user, rename_if_necessary=True) |
|
8971.24.8
by Tim Penhey
Add setTarget for branch. |
270 |
|
7362.4.13
by Jonathan Lange
Add a basic context variable, call it "container" to avoid decorates() confusion. |
271 |
@property
|
7847.1.18
by Jonathan Lange
Add a 'namespace' attribute to Branch that returns the branch's namespace. |
272 |
def namespace(self): |
273 |
"""See `IBranch`."""
|
|
274 |
return self.target.getNamespace(self.owner) |
|
275 |
||
276 |
@property
|
|
7362.13.2
by Jonathan Lange
Add a distribution property to IBranch. |
277 |
def distribution(self): |
278 |
"""See `IBranch`."""
|
|
279 |
if self.distroseries is None: |
|
280 |
return None |
|
281 |
return self.distroseries.distribution |
|
282 |
||
283 |
@property
|
|
7362.13.4
by Jonathan Lange
Add a sourcepackage property. |
284 |
def sourcepackage(self): |
285 |
"""See `IBranch`."""
|
|
286 |
# Avoid circular imports.
|
|
7675.110.3
by Curtis Hovey
Ran the migration script to move registry code to lp.registry. |
287 |
from lp.registry.model.sourcepackage import SourcePackage |
7362.13.4
by Jonathan Lange
Add a sourcepackage property. |
288 |
if self.distroseries is None: |
289 |
return None |
|
290 |
return SourcePackage(self.sourcepackagename, self.distroseries) |
|
291 |
||
292 |
@property
|
|
3691.410.2
by David Allouche
adjust database.Branch to deal with RevisionNumber where sequence is NULL |
293 |
def revision_history(self): |
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
294 |
result = Store.of(self).find( |
7675.747.10
by Jeroen Vermeulen
Lint. |
295 |
(BranchRevision, Revision), |
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
296 |
BranchRevision.branch_id == self.id, |
7675.747.10
by Jeroen Vermeulen
Lint. |
297 |
Revision.id == BranchRevision.revision_id, |
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
298 |
BranchRevision.sequence != None) |
7675.747.10
by Jeroen Vermeulen
Lint. |
299 |
result = result.order_by(Desc(BranchRevision.sequence)) |
11822.4.3
by Robert Collins
Really drop last uses of prejoin. |
300 |
return DecoratedResultSet(result, operator.itemgetter(0)) |
3691.410.2
by David Allouche
adjust database.Branch to deal with RevisionNumber where sequence is NULL |
301 |
|
3226.2.1
by Diogo Matsubara
Fix https://launchpad.net/products/launchpad/+bug/33625 (Change MultipleJoin to use the new SQLMultipleJoin.) |
302 |
subscriptions = SQLMultipleJoin( |
1102.1.85
by David Allouche
can subscribe to and unsubscribe from branch |
303 |
'BranchSubscription', joinColumn='branch', orderBy='id') |
3504.1.13
by kiko
Implement initial SQLRelatedJoin migration across Launchpad tree. Still needs to reconsider the Snapshot approach which will be a big performance hit. |
304 |
subscribers = SQLRelatedJoin( |
1102.1.85
by David Allouche
can subscribe to and unsubscribe from branch |
305 |
'Person', joinColumn='branch', otherColumn='person', |
306 |
intermediateTable='BranchSubscription', orderBy='name') |
|
307 |
||
3283.3.3
by Brad Bollenbach
pair code reviewing with lifeless |
308 |
bug_branches = SQLMultipleJoin( |
309 |
'BugBranch', joinColumn='branch', orderBy='id') |
|
310 |
||
8752.4.13
by Paul Hummer
Fixed test with new bug branch removal |
311 |
linked_bugs = SQLRelatedJoin( |
312 |
'Bug', joinColumn='branch', otherColumn='bug', |
|
313 |
intermediateTable='BugBranch', orderBy='id') |
|
8752.4.12
by Paul Hummer
Added IBranch.linked_bugs |
314 |
|
12505.6.1
by Ian Booth
Remove DecoratedBug and refactor mp linked_bugs to use branch.getRelatedBugTasks |
315 |
def getLinkedBugTasks(self, user, status_filter=None): |
12457.2.3
by Robert Collins
Lock down scaling of branch:+index for product bugtasks - still to do productseries and distroseries. |
316 |
"""See `IBranch`."""
|
317 |
params = BugTaskSearchParams(user=user, linked_branches=self.id, |
|
318 |
status=status_filter) |
|
12457.2.6
by Robert Collins
Review feedback: use a shortlist, don't spread the any pollution of default symbols. Docstring fixup and unbreak the legacy linked_bugs. |
319 |
tasks = shortlist(getUtility(IBugTaskSet).search(params), 1000) |
12457.2.3
by Robert Collins
Lock down scaling of branch:+index for product bugtasks - still to do productseries and distroseries. |
320 |
# Post process to discard irrelevant tasks: we only return one task per
|
321 |
# bug, and cannot easily express this in sql (yet).
|
|
12588.3.21
by Tim Penhey
Remove branch specific bug task filtering, and add the possibility of titles to the generic link formatter. |
322 |
return filter_bugtasks_by_context(self.target.context, tasks) |
10974.1.2
by Tim Penhey
Add a method to get all the bugtasks for the linked bugs at one go. |
323 |
|
8752.4.4
by Paul Hummer
Fixed the linking tests |
324 |
def linkBug(self, bug, registrant): |
325 |
"""See `IBranch`."""
|
|
326 |
return bug.linkBranch(self, registrant) |
|
327 |
||
8752.4.5
by Paul Hummer
Fixed the unlinking tests |
328 |
def unlinkBug(self, bug, user): |
329 |
"""See `IBranch`."""
|
|
330 |
return bug.unlinkBranch(self, user) |
|
331 |
||
3691.233.11
by James Henstridge
add a similar portlet to the branch index page |
332 |
spec_links = SQLMultipleJoin('SpecificationBranch', |
333 |
joinColumn='branch', |
|
334 |
orderBy='id') |
|
335 |
||
8752.4.4
by Paul Hummer
Fixed the linking tests |
336 |
def linkSpecification(self, spec, registrant): |
337 |
"""See `IBranch`."""
|
|
338 |
return spec.linkBranch(self, registrant) |
|
339 |
||
8752.4.5
by Paul Hummer
Fixed the unlinking tests |
340 |
def unlinkSpecification(self, spec, user): |
341 |
"""See `IBranch`."""
|
|
342 |
return spec.unlinkBranch(self, user) |
|
343 |
||
3754.2.8
by Tim Penhey
review comment fixes |
344 |
date_created = UtcDateTimeCol(notNull=True, default=DEFAULT) |
5001.2.3
by Tim Penhey
More test details. |
345 |
date_last_modified = UtcDateTimeCol(notNull=True, default=DEFAULT) |
3754.2.8
by Tim Penhey
review comment fixes |
346 |
|
4414.6.6
by Tim Penhey
More moves and changes. |
347 |
landing_targets = SQLMultipleJoin( |
4414.5.13
by Tim Penhey
Still work in progress |
348 |
'BranchMergeProposal', joinColumn='source_branch') |
4414.6.8
by Tim Penhey
Added two necessary fields. |
349 |
|
350 |
@property
|
|
9222.5.6
by Aaron Bentley
Don't update preview diffs for merge proposals in final states. |
351 |
def active_landing_targets(self): |
352 |
"""Merge proposals not in final states where this branch is source."""
|
|
353 |
store = Store.of(self) |
|
354 |
return store.find( |
|
355 |
BranchMergeProposal, BranchMergeProposal.source_branch == self, |
|
356 |
Not(BranchMergeProposal.queue_status.is_in( |
|
357 |
BRANCH_MERGE_PROPOSAL_FINAL_STATES))) |
|
358 |
||
359 |
@property
|
|
4414.6.8
by Tim Penhey
Added two necessary fields. |
360 |
def landing_candidates(self): |
361 |
"""See `IBranch`."""
|
|
5600.2.2
by Tim Penhey
Resubmit merge proposals. |
362 |
return BranchMergeProposal.select(""" |
363 |
BranchMergeProposal.target_branch = %s AND |
|
364 |
BranchMergeProposal.queue_status NOT IN %s |
|
365 |
""" % sqlvalues(self, BRANCH_MERGE_PROPOSAL_FINAL_STATES)) |
|
4414.6.6
by Tim Penhey
More moves and changes. |
366 |
|
4414.5.13
by Tim Penhey
Still work in progress |
367 |
@property
|
368 |
def dependent_branches(self): |
|
369 |
"""See `IBranch`."""
|
|
5600.2.2
by Tim Penhey
Resubmit merge proposals. |
370 |
return BranchMergeProposal.select(""" |
371 |
BranchMergeProposal.dependent_branch = %s AND |
|
372 |
BranchMergeProposal.queue_status NOT IN %s |
|
373 |
""" % sqlvalues(self, BRANCH_MERGE_PROPOSAL_FINAL_STATES)) |
|
4414.5.13
by Tim Penhey
Still work in progress |
374 |
|
11929.5.1
by Aaron Bentley
Support getMergeProposals with merged_revno. |
375 |
def getMergeProposals(self, status=None, visible_by_user=None, |
11929.5.2
by Aaron Bentley
Switch from single-revno UI to multi-revno. |
376 |
merged_revnos=None): |
11929.5.3
by Aaron Bentley
Update docs. |
377 |
"""See `IBranch`."""
|
9269.3.17
by Tim Penhey
Make a branch implement IHasMergeProposals for proposals that target it. |
378 |
if not status: |
379 |
status = ( |
|
380 |
BranchMergeProposalStatus.CODE_APPROVED, |
|
381 |
BranchMergeProposalStatus.NEEDS_REVIEW, |
|
382 |
BranchMergeProposalStatus.WORK_IN_PROGRESS) |
|
383 |
||
384 |
collection = getUtility(IAllBranches).visibleByUser(visible_by_user) |
|
11929.5.1
by Aaron Bentley
Support getMergeProposals with merged_revno. |
385 |
return collection.getMergeProposals( |
11929.5.2
by Aaron Bentley
Switch from single-revno UI to multi-revno. |
386 |
status, target_branch=self, merged_revnos=merged_revnos) |
9269.3.17
by Tim Penhey
Make a branch implement IHasMergeProposals for proposals that target it. |
387 |
|
8377.8.3
by Tim Penhey
Add a branch level method that delegates to the branch target for now. |
388 |
def isBranchMergeable(self, target_branch): |
389 |
"""See `IBranch`."""
|
|
390 |
# In some imaginary time we may actually check to see if this branch
|
|
391 |
# and the target branch have common ancestry.
|
|
392 |
return self.target.areBranchesMergeable(target_branch.target) |
|
393 |
||
4414.6.7
by Tim Penhey
More tests. |
394 |
def addLandingTarget(self, registrant, target_branch, |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
395 |
prerequisite_branch=None, whiteboard=None, |
7325.5.11
by Aaron Bentley
Ensure BMP.review_diff is attached to the MailController |
396 |
date_created=None, needs_review=False, |
7675.548.9
by Tim Penhey
Stop pretending it is an initial comment. |
397 |
description=None, review_requests=None, |
11542.3.20
by Ian Booth
Test refactoring as per code review |
398 |
review_diff=None, commit_message=None): |
4414.6.6
by Tim Penhey
More moves and changes. |
399 |
"""See `IBranch`."""
|
8377.8.13
by Tim Penhey
Fix the checks in addLandingTarget. |
400 |
if not self.target.supports_merge_proposals: |
401 |
raise InvalidBranchMergeProposal( |
|
402 |
'%s branches do not support merge proposals.' |
|
403 |
% self.target.displayname) |
|
4414.6.6
by Tim Penhey
More moves and changes. |
404 |
if self == target_branch: |
405 |
raise InvalidBranchMergeProposal( |
|
406 |
'Source and target branches must be different.') |
|
8377.8.13
by Tim Penhey
Fix the checks in addLandingTarget. |
407 |
if not target_branch.isBranchMergeable(self): |
4414.6.6
by Tim Penhey
More moves and changes. |
408 |
raise InvalidBranchMergeProposal( |
8377.8.13
by Tim Penhey
Fix the checks in addLandingTarget. |
409 |
'%s is not mergeable into %s' % ( |
8377.8.17
by Tim Penhey
Make the displayname the bzr_identity. |
410 |
self.displayname, target_branch.displayname)) |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
411 |
if prerequisite_branch is not None: |
412 |
if not self.isBranchMergeable(prerequisite_branch): |
|
8377.8.13
by Tim Penhey
Fix the checks in addLandingTarget. |
413 |
raise InvalidBranchMergeProposal( |
414 |
'%s is not mergeable into %s' % ( |
|
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
415 |
prerequisite_branch.displayname, self.displayname)) |
416 |
if self == prerequisite_branch: |
|
417 |
raise InvalidBranchMergeProposal( |
|
418 |
'Source and prerequisite branches must be different.') |
|
419 |
if target_branch == prerequisite_branch: |
|
420 |
raise InvalidBranchMergeProposal( |
|
421 |
'Target and prerequisite branches must be different.') |
|
4414.6.6
by Tim Penhey
More moves and changes. |
422 |
|
8511.2.2
by Aaron Bentley
Prevent activating a proposal when an active duplicate exists. |
423 |
target = BranchMergeProposalGetter.activeProposalsForBranches( |
424 |
self, target_branch) |
|
5600.2.1
by Tim Penhey
State transition test complete. |
425 |
if target.count() > 0: |
7573.2.2
by Paul Hummer
Added try/except block, catching the oops |
426 |
raise BranchMergeProposalExists( |
4414.6.6
by Tim Penhey
More moves and changes. |
427 |
'There is already a branch merge proposal registered for '
|
5600.2.1
by Tim Penhey
State transition test complete. |
428 |
'branch %s to land on %s that is still active.' |
8377.8.17
by Tim Penhey
Make the displayname the bzr_identity. |
429 |
% (self.displayname, target_branch.displayname)) |
4414.6.6
by Tim Penhey
More moves and changes. |
430 |
|
4414.6.8
by Tim Penhey
Added two necessary fields. |
431 |
if date_created is None: |
432 |
date_created = UTC_NOW |
|
5001.2.10
by Tim Penhey
Missing zcml attribute, typo and login required on a doc test. |
433 |
|
6623.3.3
by Tim Penhey
Updates following review. |
434 |
if needs_review: |
435 |
queue_status = BranchMergeProposalStatus.NEEDS_REVIEW |
|
7074.2.1
by Tim Penhey
Change the register a merge proposal to be a form where the user can specify an initial comment and request a reviewer. |
436 |
date_review_requested = date_created |
6623.3.3
by Tim Penhey
Updates following review. |
437 |
else: |
438 |
queue_status = BranchMergeProposalStatus.WORK_IN_PROGRESS |
|
7074.2.1
by Tim Penhey
Change the register a merge proposal to be a form where the user can specify an initial comment and request a reviewer. |
439 |
date_review_requested = None |
6623.3.3
by Tim Penhey
Updates following review. |
440 |
|
7334.4.18
by Tim Penhey
Updates following review comments. |
441 |
if review_requests is None: |
442 |
review_requests = [] |
|
7334.4.4
by Tim Penhey
Add the ability to set the initial comment and requested reviewers when adding the landing target to the branch. |
443 |
|
11542.3.23
by Ian Booth
Minor fixes |
444 |
# If no reviewer is specified, use the default for the branch.
|
445 |
if len(review_requests) == 0: |
|
446 |
review_requests.append((target_branch.code_reviewer, None)) |
|
11542.3.1
by Ian Booth
Initial core code changes |
447 |
|
5608.5.5
by Aaron Bentley
Add notification on BranchMergeProposal creation |
448 |
bmp = BranchMergeProposal( |
4414.6.6
by Tim Penhey
More moves and changes. |
449 |
registrant=registrant, source_branch=self, |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
450 |
target_branch=target_branch, |
451 |
prerequisite_branch=prerequisite_branch, whiteboard=whiteboard, |
|
452 |
date_created=date_created, |
|
7074.2.1
by Tim Penhey
Change the register a merge proposal to be a form where the user can specify an initial comment and request a reviewer. |
453 |
date_review_requested=date_review_requested, |
9801.1.4
by Aaron Bentley
Expose commit_message throughout the stack. |
454 |
queue_status=queue_status, review_diff=review_diff, |
7675.548.2
by Tim Penhey
Update for the description field. |
455 |
commit_message=commit_message, |
7675.548.9
by Tim Penhey
Stop pretending it is an initial comment. |
456 |
description=description) |
7334.4.4
by Tim Penhey
Add the ability to set the initial comment and requested reviewers when adding the landing target to the branch. |
457 |
|
7334.4.18
by Tim Penhey
Updates following review comments. |
458 |
for reviewer, review_type in review_requests: |
7334.4.4
by Tim Penhey
Add the ability to set the initial comment and requested reviewers when adding the landing target to the branch. |
459 |
bmp.nominateReviewer( |
460 |
reviewer, registrant, review_type, _notify_listeners=False) |
|
461 |
||
462 |
notify(NewBranchMergeProposalEvent(bmp)) |
|
11733.1.5
by Tim Penhey
Raise the needs review event when created in needs review or going from work in progress to needs review. |
463 |
if needs_review: |
464 |
notify(BranchMergeProposalNeedsReviewEvent(bmp)) |
|
11733.1.4
by Tim Penhey
Add an extra event for the needs review, but keep the same functionality for now. |
465 |
|
5608.5.5
by Aaron Bentley
Add notification on BranchMergeProposal creation |
466 |
return bmp |
4414.6.6
by Tim Penhey
More moves and changes. |
467 |
|
9801.1.6
by Aaron Bentley
Allow creating merge proposal with reviewers via API. |
468 |
def _createMergeProposal( |
469 |
self, registrant, target_branch, prerequisite_branch=None, |
|
470 |
needs_review=True, initial_comment=None, commit_message=None, |
|
471 |
reviewers=None, review_types=None): |
|
9801.1.7
by Aaron Bentley
Add comment. |
472 |
"""See `IBranch`."""
|
9801.1.6
by Aaron Bentley
Allow creating merge proposal with reviewers via API. |
473 |
if reviewers is None: |
474 |
reviewers = [] |
|
475 |
if review_types is None: |
|
476 |
review_types = [] |
|
477 |
if len(reviewers) != len(review_types): |
|
478 |
raise ValueError( |
|
479 |
'reviewers and review_types must be equal length.') |
|
480 |
review_requests = zip(reviewers, review_types) |
|
10466.1.5
by Paul Hummer
Better solution! |
481 |
return self.addLandingTarget( |
482 |
registrant, target_branch, prerequisite_branch, |
|
483 |
needs_review=needs_review, description=initial_comment, |
|
484 |
commit_message=commit_message, review_requests=review_requests) |
|
9801.1.6
by Aaron Bentley
Allow creating merge proposal with reviewers via API. |
485 |
|
9222.5.1
by Aaron Bentley
Provide for scheduling diff updates. |
486 |
def scheduleDiffUpdates(self): |
487 |
"""See `IBranch`."""
|
|
11486.4.19
by Aaron Bentley
Create GenerateIncrementalDiff jobs missing incremental diffs on tip change. |
488 |
from lp.code.model.branchmergeproposaljob import ( |
489 |
GenerateIncrementalDiffJob, |
|
490 |
UpdatePreviewDiffJob, |
|
11486.4.36
by Aaron Bentley
Updates from review. |
491 |
)
|
11486.4.19
by Aaron Bentley
Create GenerateIncrementalDiff jobs missing incremental diffs on tip change. |
492 |
jobs = [] |
493 |
for merge_proposal in self.active_landing_targets: |
|
494 |
if merge_proposal.target_branch.last_scanned_id is None: |
|
495 |
continue
|
|
496 |
jobs.append(UpdatePreviewDiffJob.create(merge_proposal)) |
|
497 |
for old, new in merge_proposal.getMissingIncrementalDiffs(): |
|
498 |
GenerateIncrementalDiffJob.create( |
|
499 |
merge_proposal, old.revision_id, new.revision_id) |
|
9222.5.1
by Aaron Bentley
Provide for scheduling diff updates. |
500 |
return jobs |
501 |
||
7362.11.41
by Jonathan Lange
Add an addToLaunchBag method. |
502 |
def addToLaunchBag(self, launchbag): |
503 |
"""See `IBranch`."""
|
|
504 |
launchbag.add(self.product) |
|
505 |
if self.distroseries is not None: |
|
506 |
launchbag.add(self.distroseries) |
|
7362.13.3
by Jonathan Lange
Use distribution property more effectively. |
507 |
launchbag.add(self.distribution) |
7362.13.5
by Jonathan Lange
Some cleanups, now that we have a source package property. |
508 |
launchbag.add(self.sourcepackage) |
7362.11.41
by Jonathan Lange
Add an addToLaunchBag method. |
509 |
|
6983.2.1
by Jonathan Lange
Add a getStackedBranches method to IBranch. |
510 |
def getStackedBranches(self): |
511 |
"""See `IBranch`."""
|
|
6983.2.2
by Jonathan Lange
Give getStackedBranches a working implementation. |
512 |
store = Store.of(self) |
513 |
return store.find(Branch, Branch.stacked_on == self) |
|
6983.2.1
by Jonathan Lange
Add a getStackedBranches method to IBranch. |
514 |
|
1102.1.69
by David Allouche
link to branch page from branch-summary-listing |
515 |
@property
|
4682.2.4
by Tim Penhey
Updates following review comments |
516 |
def code_is_browseable(self): |
517 |
"""See `IBranch`."""
|
|
7675.747.9
by Jeroen Vermeulen
Lint. |
518 |
return (self.revision_count > 0 or self.last_mirrored != None) |
7622.1.2
by Michael Hudson
some progress |
519 |
|
520 |
def codebrowse_url(self, *extras): |
|
521 |
"""See `IBranch`."""
|
|
522 |
if self.private: |
|
523 |
root = config.codehosting.secure_codebrowse_root |
|
524 |
else: |
|
525 |
root = config.codehosting.codebrowse_root |
|
526 |
return urlutils.join(root, self.unique_name, *extras) |
|
4813.8.1
by Tim Penhey
Lots of url moving on the branch index page. |
527 |
|
5805.2.1
by Tim Penhey
Initial work. |
528 |
@property
|
9643.1.1
by Jonathan Lange
Add a browse_source_url property to branch that points to the URL to browse |
529 |
def browse_source_url(self): |
530 |
return self.codebrowse_url('files') |
|
531 |
||
10312.5.5
by Jeroen Vermeulen
IBranch.composePublicURL. |
532 |
def composePublicURL(self, scheme='http'): |
533 |
"""See `IBranch`."""
|
|
534 |
# Not all protocols work for private branches.
|
|
535 |
public_schemes = ['http'] |
|
536 |
assert not (self.private and scheme in public_schemes), ( |
|
537 |
"Private branch %s has no public URL." % self.unique_name) |
|
10312.8.1
by Aaron Bentley
Refactor Branch.composePublicUrl and getUniqueNameResultDict |
538 |
return compose_public_url(scheme, self.unique_name) |
10312.5.5
by Jeroen Vermeulen
IBranch.composePublicURL. |
539 |
|
9590.1.104
by Michael Hudson
test_codehandler tests now pass |
540 |
def getInternalBzrUrl(self): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
541 |
"""See `IBranch`."""
|
9590.1.104
by Michael Hudson
test_codehandler tests now pass |
542 |
return 'lp-internal:///' + self.unique_name |
3335.2.4
by David Allouche
review comments and test fixes |
543 |
|
6805.13.71
by Aaron Bentley
Rename diff.StaticDiffJob to branch.BranchDiffJob |
544 |
def getBzrBranch(self): |
9590.1.89
by Michael Hudson
add getBzrBranch to the interface |
545 |
"""See `IBranch`."""
|
9590.1.104
by Michael Hudson
test_codehandler tests now pass |
546 |
return safe_open('lp-internal', self.getInternalBzrUrl()) |
6805.13.71
by Aaron Bentley
Rename diff.StaticDiffJob to branch.BranchDiffJob |
547 |
|
3249.5.1
by David Allouche
Branch pages title fixes |
548 |
@property
|
549 |
def displayname(self): |
|
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
550 |
"""See `IBranch`."""
|
8377.8.17
by Tim Penhey
Make the displayname the bzr_identity. |
551 |
return self.bzr_identity |
3249.5.1
by David Allouche
Branch pages title fixes |
552 |
|
3412.1.15
by David Allouche
factor out and document Branch.sort_key |
553 |
@property
|
5280.4.25
by Tim Penhey
Updates following review. |
554 |
def code_reviewer(self): |
555 |
"""See `IBranch`."""
|
|
556 |
if self.reviewer: |
|
557 |
return self.reviewer |
|
558 |
else: |
|
559 |
return self.owner |
|
560 |
||
9041.4.1
by Tim Penhey
Move isPersonTrustedReviewer to the IBranch interface. |
561 |
def isPersonTrustedReviewer(self, reviewer): |
562 |
"""See `IBranch`."""
|
|
563 |
if reviewer is None: |
|
564 |
return False |
|
565 |
# We trust Launchpad admins.
|
|
566 |
lp_admins = getUtility(ILaunchpadCelebrities).admin |
|
567 |
# Both the branch owner and the review team are checked.
|
|
568 |
owner = self.owner |
|
569 |
review_team = self.code_reviewer |
|
570 |
return ( |
|
571 |
reviewer.inTeam(owner) or |
|
572 |
reviewer.inTeam(review_team) or |
|
573 |
reviewer.inTeam(lp_admins)) |
|
574 |
||
1102.1.73
by David Allouche
branch portlets and revision list limit |
575 |
def latest_revisions(self, quantity=10): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
576 |
"""See `IBranch`."""
|
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
577 |
return self.revision_history.config(limit=quantity) |
1102.1.73
by David Allouche
branch portlets and revision list limit |
578 |
|
9984.4.5
by Tim Penhey
New storm style method to get mainline branch revisions. |
579 |
def getMainlineBranchRevisions(self, start_date, end_date=None, |
580 |
oldest_first=False): |
|
581 |
"""See `IBranch`."""
|
|
582 |
date_clause = Revision.revision_date >= start_date |
|
583 |
if end_date is not None: |
|
584 |
date_clause = And(date_clause, Revision.revision_date <= end_date) |
|
585 |
result = Store.of(self).find( |
|
12640.1.1
by Robert Collins
Improve query plan for getMainlineBranchRevisions by using a second set based query to get authors rather than a single wide query. |
586 |
(BranchRevision, Revision), |
9984.4.5
by Tim Penhey
New storm style method to get mainline branch revisions. |
587 |
BranchRevision.branch == self, |
588 |
BranchRevision.sequence != None, |
|
589 |
BranchRevision.revision == Revision.id, |
|
590 |
date_clause) |
|
591 |
if oldest_first: |
|
592 |
result = result.order_by(BranchRevision.sequence) |
|
593 |
else: |
|
594 |
result = result.order_by(Desc(BranchRevision.sequence)) |
|
12640.1.1
by Robert Collins
Improve query plan for getMainlineBranchRevisions by using a second set based query to get authors rather than a single wide query. |
595 |
def eager_load(rows): |
596 |
revisions = map(operator.itemgetter(1), rows) |
|
597 |
load_related(RevisionAuthor, revisions, ['revision_author_id']) |
|
598 |
return DecoratedResultSet(result, pre_iter_hook=eager_load) |
|
9984.4.5
by Tim Penhey
New storm style method to get mainline branch revisions. |
599 |
|
9984.4.1
by Tim Penhey
Rename revisions_since to follow the LP coding standard. |
600 |
def getRevisionsSince(self, timestamp): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
601 |
"""See `IBranch`."""
|
7675.747.12
by Jeroen Vermeulen
One more prejoin, as per reviewer. |
602 |
result = Store.of(self).find( |
603 |
(BranchRevision, Revision), |
|
7675.747.2
by Jeroen Vermeulen
Stormified rest of BranchRevision usage. |
604 |
Revision.id == BranchRevision.revision_id, |
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
605 |
BranchRevision.branch == self, |
606 |
BranchRevision.sequence != None, |
|
607 |
Revision.revision_date > timestamp) |
|
7675.747.12
by Jeroen Vermeulen
One more prejoin, as per reviewer. |
608 |
result = result.order_by(Desc(BranchRevision.sequence)) |
609 |
# Return BranchRevision but prejoin Revision as well.
|
|
11822.4.3
by Robert Collins
Really drop last uses of prejoin. |
610 |
return DecoratedResultSet(result, operator.itemgetter(0)) |
1102.1.121
by david
show author of revisions and number of revisions in the last 30 days |
611 |
|
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
612 |
def canBeDeleted(self): |
613 |
"""See `IBranch`."""
|
|
7735.1.1
by Tim Penhey
Don't allow branches with other branches stacked on them to be deleted. |
614 |
if ((len(self.deletionRequirements()) != 0) or |
615 |
self.getStackedBranches().count() > 0): |
|
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
616 |
# Can't delete if the branch is associated with anything.
|
617 |
return False |
|
618 |
else: |
|
619 |
return True |
|
1102.1.52
by David Allouche
remove archbranch.py, fix branch goo until the product page works |
620 |
|
12393.27.5
by Danilo Segan
Merge with latest accordionoverlay. |
621 |
@cachedproperty
|
5616.2.14
by Aaron Bentley
Updates from tests |
622 |
def code_import(self): |
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
623 |
from lp.code.model.codeimport import CodeImportSet |
5616.2.14
by Aaron Bentley
Updates from tests |
624 |
return CodeImportSet().getByBranch(self) |
625 |
||
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
626 |
def _deletionRequirements(self): |
5616.2.12
by Aaron Bentley
Document eeeverything |
627 |
"""Determine what operations must be performed to delete this branch.
|
628 |
||
629 |
Two dictionaries are returned, one for items that must be deleted,
|
|
630 |
one for items that must be altered. The item in question is the
|
|
631 |
key, and the value is a user-facing string explaining why the item
|
|
632 |
is affected.
|
|
633 |
||
5616.2.40
by Aaron Bentley
Update docs |
634 |
As well as the dictionaries, this method returns two list of callables
|
635 |
that may be called to perform the alterations and deletions needed.
|
|
5616.2.12
by Aaron Bentley
Document eeeverything |
636 |
"""
|
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
637 |
alteration_operations = [] |
5616.2.26
by Aaron Bentley
Do object deletion via callbacks |
638 |
deletion_operations = [] |
5616.2.13
by Aaron Bentley
Tweak comments |
639 |
# Merge proposals require their source and target branches to exist.
|
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
640 |
for merge_proposal in self.landing_targets: |
6019.2.1
by Aaron Bentley
Use objects instead of closures for deletion |
641 |
deletion_operations.append( |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
642 |
DeletionCallable(merge_proposal, |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
643 |
_('This branch is the source branch of this merge' |
6475.2.22
by Barry Warsaw
mergeRF |
644 |
' proposal.'), merge_proposal.deleteProposal)) |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
645 |
# Cannot use self.landing_candidates, because it ignores merged
|
5616.2.13
by Aaron Bentley
Tweak comments |
646 |
# merge proposals.
|
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
647 |
for merge_proposal in BranchMergeProposal.selectBy( |
648 |
target_branch=self): |
|
6019.2.2
by Aaron Bentley
Use DeletionOperation everywhere |
649 |
deletion_operations.append( |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
650 |
DeletionCallable(merge_proposal, |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
651 |
_('This branch is the target branch of this merge' |
6475.2.22
by Barry Warsaw
mergeRF |
652 |
' proposal.'), merge_proposal.deleteProposal)) |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
653 |
for merge_proposal in BranchMergeProposal.selectBy( |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
654 |
prerequisite_branch=self): |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
655 |
alteration_operations.append(ClearDependentBranch(merge_proposal)) |
656 |
||
5616.2.2
by Aaron Bentley
Support deleting subscriptions and bug branches |
657 |
for bugbranch in self.bug_branches: |
6019.2.2
by Aaron Bentley
Use DeletionOperation everywhere |
658 |
deletion_operations.append( |
10362.2.3
by Paul Hummer
Removed the ugly tal change. |
659 |
DeletionCallable(bugbranch.bug.default_bugtask, |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
660 |
_('This bug is linked to this branch.'), |
661 |
bugbranch.destroySelf)) |
|
5616.2.4
by Aaron Bentley
Handle spec subscriptions when deleting branches |
662 |
for spec_link in self.spec_links: |
6019.2.2
by Aaron Bentley
Use DeletionOperation everywhere |
663 |
deletion_operations.append( |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
664 |
DeletionCallable(spec_link, |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
665 |
_('This blueprint is linked to this branch.'), |
666 |
spec_link.destroySelf)) |
|
5616.2.6
by Aaron Bentley
Handle branch deletion for branches associated with series |
667 |
for series in self.associatedProductSeries(): |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
668 |
alteration_operations.append(ClearSeriesBranch(series, self)) |
8771.6.1
by Jeroen Vermeulen
UI for exporting translations to bzr branch. |
669 |
for series in self.getProductSeriesPushingTranslations(): |
670 |
alteration_operations.append( |
|
671 |
ClearSeriesTranslationsBranch(series, self)) |
|
8211.4.12
by Jonathan Lange
Allow branches linked to source packages to be deleted. |
672 |
|
8211.4.14
by Jonathan Lange
Further split the interfaces, correct the permissions. |
673 |
series_set = getUtility(IFindOfficialBranchLinks) |
8211.4.12
by Jonathan Lange
Allow branches linked to source packages to be deleted. |
674 |
alteration_operations.extend( |
675 |
map(ClearOfficialPackageBranch, series_set.findForBranch(self))) |
|
10498.5.36
by Aaron Bentley
Deleting branches used in recipes deletes the recipes. |
676 |
deletion_operations.extend( |
677 |
DeletionCallable.forSourcePackageRecipe(recipe) |
|
12397.2.8
by Ian Booth
Change from using getter methods to properties for exported recipe and build accessors |
678 |
for recipe in self.recipes) |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
679 |
return (alteration_operations, deletion_operations) |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
680 |
|
681 |
def deletionRequirements(self): |
|
5616.2.12
by Aaron Bentley
Document eeeverything |
682 |
"""See `IBranch`."""
|
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
683 |
alteration_operations, deletion_operations, = ( |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
684 |
self._deletionRequirements()) |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
685 |
result = dict( |
686 |
(operation.affected_object, ('alter', operation.rationale)) for |
|
687 |
operation in alteration_operations) |
|
5616.2.13
by Aaron Bentley
Tweak comments |
688 |
# Deletion entries should overwrite alteration entries.
|
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
689 |
result.update( |
690 |
(operation.affected_object, ('delete', operation.rationale)) for |
|
691 |
operation in deletion_operations) |
|
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
692 |
return result |
693 |
||
694 |
def _breakReferences(self): |
|
5616.2.12
by Aaron Bentley
Document eeeverything |
695 |
"""Break all external references to this branch.
|
696 |
||
697 |
NULLable references will be NULLed. References which are not NULLable
|
|
698 |
will cause the item holding the reference to be deleted.
|
|
699 |
||
700 |
This function is guaranteed to perform the operations predicted by
|
|
701 |
deletionRequirements, because it uses the same backing function.
|
|
702 |
"""
|
|
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
703 |
(alteration_operations, |
5616.2.36
by Aaron Bentley
Fix lint errors |
704 |
deletion_operations) = self._deletionRequirements() |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
705 |
for operation in alteration_operations: |
6019.2.10
by Aaron Bentley
Updatest from review |
706 |
operation() |
5616.2.26
by Aaron Bentley
Do object deletion via callbacks |
707 |
for operation in deletion_operations: |
6019.2.10
by Aaron Bentley
Updatest from review |
708 |
operation() |
9636.5.15
by Jonathan Lange
Make it possible to delete the code import branch if you own it. |
709 |
# Special-case code import, since users don't have lp.Edit on them,
|
710 |
# since if you can delete a branch you should be able to delete the
|
|
711 |
# code import and since deleting the code import object itself isn't
|
|
712 |
# actually a very interesting thing to tell the user about.
|
|
713 |
if self.code_import is not None: |
|
714 |
DeleteCodeImport(self.code_import)() |
|
11316.6.2
by Tim Penhey
The translation clearing class didn't do what it said, and it wasn't tested. |
715 |
Store.of(self).flush() |
5616.2.1
by Aaron Bentley
Allow branches with merge proposals to be deleted |
716 |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
717 |
@cachedproperty
|
718 |
def _associatedProductSeries(self): |
|
719 |
"""Helper for eager loading associatedProductSeries."""
|
|
720 |
# This is eager loaded by BranchCollection.getBranches.
|
|
721 |
# Imported here to avoid circular import.
|
|
722 |
from lp.registry.model.productseries import ProductSeries |
|
723 |
return Store.of(self).find( |
|
724 |
ProductSeries, |
|
725 |
ProductSeries.branch == self) |
|
726 |
||
12508.1.1
by William Grant
Revert r12505 and 12489. The former was meant to fix the latter, but did not. |
727 |
def associatedProductSeries(self): |
728 |
"""See `IBranch`."""
|
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
729 |
return self._associatedProductSeries |
12475.1.4
by Robert Collins
Eager load associated product series for getBranches. |
730 |
|
8771.6.1
by Jeroen Vermeulen
UI for exporting translations to bzr branch. |
731 |
def getProductSeriesPushingTranslations(self): |
732 |
"""See `IBranch`."""
|
|
733 |
# Imported here to avoid circular import.
|
|
734 |
from lp.registry.model.productseries import ProductSeries |
|
735 |
return Store.of(self).find( |
|
736 |
ProductSeries, |
|
737 |
ProductSeries.translations_branch == self) |
|
738 |
||
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
739 |
@cachedproperty
|
740 |
def _associatedSuiteSourcePackages(self): |
|
741 |
"""Helper for associatedSuiteSourcePackages."""
|
|
742 |
# This is eager loaded by BranchCollection.getBranches.
|
|
8852.2.1
by Tim Penhey
Make the decorated branch listing item pass itself through when determining the bazaar_identity so the cached associated product series can be used. |
743 |
series_set = getUtility(IFindOfficialBranchLinks) |
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
744 |
# Order by the pocket to get the release one first. If changing this be
|
745 |
# sure to also change BranchCollection.getBranches.
|
|
8852.2.1
by Tim Penhey
Make the decorated branch listing item pass itself through when determining the bazaar_identity so the cached associated product series can be used. |
746 |
links = series_set.findForBranch(self).order_by( |
747 |
SeriesSourcePackageBranch.pocket) |
|
748 |
return [link.suite_sourcepackage for link in links] |
|
749 |
||
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
750 |
def associatedSuiteSourcePackages(self): |
751 |
"""See `IBranch`."""
|
|
752 |
return self._associatedSuiteSourcePackages |
|
753 |
||
1102.1.85
by David Allouche
can subscribe to and unsubscribe from branch |
754 |
# subscriptions
|
5608.5.1
by Aaron Bentley
Add BranchSubscription.review_level |
755 |
def subscribe(self, person, notification_level, max_diff_lines, |
7675.708.5
by Tim Penhey
Some other necessary bits. |
756 |
code_review_level, subscribed_by): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
757 |
"""See `IBranch`."""
|
4620.2.2
by Tim Penhey
Added the misteriously disappearing doctest. |
758 |
# If the person is already subscribed, update the subscription with
|
759 |
# the specified notification details.
|
|
760 |
subscription = self.getSubscription(person) |
|
761 |
if subscription is None: |
|
762 |
subscription = BranchSubscription( |
|
763 |
branch=self, person=person, |
|
764 |
notification_level=notification_level, |
|
7675.708.5
by Tim Penhey
Some other necessary bits. |
765 |
max_diff_lines=max_diff_lines, review_level=code_review_level, |
766 |
subscribed_by=subscribed_by) |
|
5821.18.2
by James Henstridge
Add flush() calls to Branch.subscribe() and unsubscribe(), fixing |
767 |
Store.of(subscription).flush() |
4620.2.2
by Tim Penhey
Added the misteriously disappearing doctest. |
768 |
else: |
769 |
subscription.notification_level = notification_level |
|
770 |
subscription.max_diff_lines = max_diff_lines |
|
7781.4.8
by Paul Hummer
Fixed review_level issue |
771 |
subscription.review_level = code_review_level |
4620.2.2
by Tim Penhey
Added the misteriously disappearing doctest. |
772 |
return subscription |
3691.431.11
by Tim Penhey
Branch subscription pages edited |
773 |
|
774 |
def getSubscription(self, person): |
|
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
775 |
"""See `IBranch`."""
|
3691.431.12
by Tim Penhey
And now the tests pass again |
776 |
if person is None: |
777 |
return None |
|
1102.1.143
by David Allouche
Review fixes to Branch view. |
778 |
subscription = BranchSubscription.selectOneBy( |
3691.62.21
by kiko
Clean up the use of ID/.id in select*By and constructors |
779 |
person=person, branch=self) |
3691.431.11
by Tim Penhey
Branch subscription pages edited |
780 |
return subscription |
781 |
||
5767.1.8
by jml at canonical
Use the database instead of Python to do some querying. |
782 |
def getSubscriptionsByLevel(self, notification_levels): |
783 |
"""See `IBranch`."""
|
|
7960.4.70
by Jonathan Lange
Fix up XXX comment. |
784 |
# XXX: JonathanLange 2009-05-07 bug=373026: This is only used by real
|
785 |
# code to determine whether there are any subscribers at the given
|
|
786 |
# notification levels. The only code that cares about the actual
|
|
787 |
# object is in a test:
|
|
7960.4.23
by Jonathan Lange
Comments; shuffling transaction.commit. |
788 |
# test_only_nodiff_subscribers_means_no_diff_generated.
|
7960.4.25
by Jonathan Lange
Extract out a function that determines whether you need branch subscription |
789 |
store = Store.of(self) |
790 |
return store.find( |
|
791 |
BranchSubscription, |
|
792 |
BranchSubscription.branch == self, |
|
793 |
BranchSubscription.notification_level.is_in(notification_levels)) |
|
5767.1.8
by jml at canonical
Use the database instead of Python to do some querying. |
794 |
|
3691.431.11
by Tim Penhey
Branch subscription pages edited |
795 |
def hasSubscription(self, person): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
796 |
"""See `IBranch`."""
|
3691.431.11
by Tim Penhey
Branch subscription pages edited |
797 |
return self.getSubscription(person) is not None |
798 |
||
7675.708.3
by Tim Penhey
Add subscribed_by and unsubscribed_by to the subscribe and unsubscribe branch methods. |
799 |
def unsubscribe(self, person, unsubscribed_by): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
800 |
"""See `IBranch`."""
|
3691.431.11
by Tim Penhey
Branch subscription pages edited |
801 |
subscription = self.getSubscription(person) |
7675.708.15
by Tim Penhey
Add the check to make sure that the user unsubscribing actually is allowed to. |
802 |
if subscription is None: |
803 |
# Silent success seems order of the day (like bugs).
|
|
804 |
return
|
|
805 |
if not subscription.canBeUnsubscribedByUser(unsubscribed_by): |
|
806 |
raise UserCannotUnsubscribePerson( |
|
807 |
'%s does not have permission to unsubscribe %s.' % ( |
|
808 |
unsubscribed_by.displayname, |
|
809 |
person.displayname)) |
|
5821.18.2
by James Henstridge
Add flush() calls to Branch.subscribe() and unsubscribe(), fixing |
810 |
store = Store.of(subscription) |
7675.708.15
by Tim Penhey
Add the check to make sure that the user unsubscribing actually is allowed to. |
811 |
store.remove(subscription) |
5821.18.2
by James Henstridge
Add flush() calls to Branch.subscribe() and unsubscribe(), fixing |
812 |
store.flush() |
1102.1.143
by David Allouche
Review fixes to Branch view. |
813 |
|
6736.3.5
by Tim Penhey
Clean up the Branch.getBranchRevision method. |
814 |
def getBranchRevision(self, sequence=None, revision=None, |
815 |
revision_id=None): |
|
816 |
"""See `IBranch`."""
|
|
817 |
params = (sequence, revision, revision_id) |
|
6736.3.12
by Tim Penhey
Updates following review. |
818 |
if len([p for p in params if p is not None]) != 1: |
6736.3.5
by Tim Penhey
Clean up the Branch.getBranchRevision method. |
819 |
raise AssertionError( |
820 |
"One and only one of sequence, revision, or revision_id "
|
|
821 |
"should have a value.") |
|
822 |
if sequence is not None: |
|
823 |
query = BranchRevision.sequence == sequence |
|
824 |
elif revision is not None: |
|
825 |
query = BranchRevision.revision == revision |
|
826 |
else: |
|
827 |
query = And(BranchRevision.revision == Revision.id, |
|
828 |
Revision.revision_id == revision_id) |
|
829 |
||
830 |
store = Store.of(self) |
|
831 |
||
832 |
return store.find( |
|
833 |
BranchRevision, |
|
834 |
BranchRevision.branch == self, |
|
835 |
query).one() |
|
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
836 |
|
7675.814.11
by Tim Penhey
Update the branch method to take an iterable. |
837 |
def removeBranchRevisions(self, revision_ids): |
7675.814.4
by Tim Penhey
Add implementation and remove lint. |
838 |
"""See `IBranch`."""
|
7675.814.11
by Tim Penhey
Update the branch method to take an iterable. |
839 |
if isinstance(revision_ids, basestring): |
840 |
revision_ids = [revision_ids] |
|
7675.814.4
by Tim Penhey
Add implementation and remove lint. |
841 |
IMasterStore(BranchRevision).find( |
842 |
BranchRevision, |
|
843 |
BranchRevision.branch == self, |
|
844 |
BranchRevision.revision_id.is_in( |
|
845 |
Select(Revision.id, |
|
7675.814.11
by Tim Penhey
Update the branch method to take an iterable. |
846 |
Revision.revision_id.is_in(revision_ids)))).remove() |
7675.814.4
by Tim Penhey
Add implementation and remove lint. |
847 |
|
3691.416.1
by David Allouche
replace RevisionNumber by BranchRevision across |
848 |
def createBranchRevision(self, sequence, revision): |
4629.4.9
by Tim Penhey
Update following review comments |
849 |
"""See `IBranch`."""
|
6623.4.1
by Tim Penhey
Initial karma allocation done. TODO: karma when revision author linked. |
850 |
branch_revision = BranchRevision( |
3691.425.33
by David Allouche
update documentation and interfaces for BranchRevision semantics |
851 |
branch=self, sequence=sequence, revision=revision) |
6623.4.1
by Tim Penhey
Initial karma allocation done. TODO: karma when revision author linked. |
852 |
# Allocate karma if no karma has been allocated for this revision.
|
853 |
if not revision.karma_allocated: |
|
854 |
revision.allocateKarma(self) |
|
855 |
return branch_revision |
|
3691.25.6
by James Henstridge
remove direct RevisionNumber usage in bzrsync |
856 |
|
7049.1.5
by Michael Hudson
scary temporary table nonsense |
857 |
def createBranchRevisionFromIDs(self, revision_id_sequence_pairs): |
858 |
"""See `IBranch`."""
|
|
7049.1.12
by Michael Hudson
test and fix for the empty-argument case |
859 |
if not revision_id_sequence_pairs: |
860 |
return
|
|
7049.1.5
by Michael Hudson
scary temporary table nonsense |
861 |
store = Store.of(self) |
7049.1.8
by Michael Hudson
tidy |
862 |
store.execute( |
863 |
"""
|
|
864 |
CREATE TEMPORARY TABLE RevidSequence
|
|
865 |
(revision_id text, sequence integer)
|
|
866 |
""") |
|
7049.1.5
by Michael Hudson
scary temporary table nonsense |
867 |
data = [] |
7049.1.16
by Michael Hudson
docstrings, comments |
868 |
for revid, sequence in revision_id_sequence_pairs: |
869 |
data.append('(%s, %s)' % sqlvalues(revid, sequence)) |
|
7049.1.8
by Michael Hudson
tidy |
870 |
data = ', '.join(data) |
871 |
store.execute( |
|
872 |
"INSERT INTO RevidSequence (revision_id, sequence) VALUES %s" |
|
873 |
% data) |
|
874 |
store.execute( |
|
875 |
"""
|
|
876 |
INSERT INTO BranchRevision (branch, revision, sequence)
|
|
877 |
SELECT %s, Revision.id, RevidSequence.sequence
|
|
878 |
FROM RevidSequence, Revision
|
|
879 |
WHERE Revision.revision_id = RevidSequence.revision_id
|
|
880 |
""" % sqlvalues(self)) |
|
881 |
store.execute("DROP TABLE RevidSequence") |
|
7049.1.5
by Michael Hudson
scary temporary table nonsense |
882 |
|
3691.290.8
by Tim Penhey
tests passing for revision changes |
883 |
def getTipRevision(self): |
4629.4.9
by Tim Penhey
Update following review comments |
884 |
"""See `IBranch`."""
|
3691.290.8
by Tim Penhey
tests passing for revision changes |
885 |
tip_revision_id = self.last_scanned_id |
886 |
if tip_revision_id is None: |
|
887 |
return None |
|
888 |
return Revision.selectOneBy(revision_id=tip_revision_id) |
|
889 |
||
7236.4.3
by Tim Penhey
Updates following review. |
890 |
def updateScannedDetails(self, db_revision, revision_count): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
891 |
"""See `IBranch`."""
|
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
892 |
# By taking the minimum of the revision date and the date created, we
|
893 |
# cap the revision date to make sure that we don't use a future date.
|
|
894 |
# The date created is set to be the time that the revision was created
|
|
895 |
# in the database, so if the revision_date is a future date, then we
|
|
896 |
# use the date created instead.
|
|
7236.4.3
by Tim Penhey
Updates following review. |
897 |
if db_revision is None: |
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
898 |
revision_id = NULL_REVISION |
899 |
revision_date = UTC_NOW |
|
900 |
else: |
|
7236.4.3
by Tim Penhey
Updates following review. |
901 |
revision_id = db_revision.revision_id |
902 |
revision_date = min( |
|
903 |
db_revision.revision_date, db_revision.date_created) |
|
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
904 |
|
7236.4.3
by Tim Penhey
Updates following review. |
905 |
# If the branch has changed through either a different tip revision or
|
906 |
# revision count, then update.
|
|
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
907 |
if ((revision_id != self.last_scanned_id) or |
908 |
(revision_count != self.revision_count)): |
|
909 |
# If the date of the last revision is greated than the date last
|
|
910 |
# modified, then bring the date last modified forward to the last
|
|
911 |
# revision date (as long as the revision date isn't in the
|
|
912 |
# future).
|
|
7236.4.3
by Tim Penhey
Updates following review. |
913 |
if db_revision is None or revision_date > self.date_last_modified: |
7236.4.1
by Tim Penhey
Move the functionality into the branch class for update scanned details, and awaken inactive branches on new revisions. |
914 |
self.date_last_modified = revision_date |
915 |
self.last_scanned = UTC_NOW |
|
916 |
self.last_scanned_id = revision_id |
|
917 |
self.revision_count = revision_count |
|
918 |
if self.lifecycle_status in (BranchLifecycleStatus.MERGED, |
|
919 |
BranchLifecycleStatus.ABANDONED): |
|
920 |
self.lifecycle_status = BranchLifecycleStatus.DEVELOPMENT |
|
3691.431.26
by Tim Penhey
added tests to confirm email format and recipients |
921 |
|
4333.2.7
by Tim Penhey
Updates following review |
922 |
def getNotificationRecipients(self): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
923 |
"""See `IBranch`."""
|
4333.2.7
by Tim Penhey
Updates following review |
924 |
recipients = NotificationRecipientSet() |
925 |
for subscription in self.subscriptions: |
|
4333.2.10
by Tim Penhey
yet more review updates |
926 |
if subscription.person.isTeam(): |
927 |
rationale = 'Subscriber @%s' % subscription.person.name |
|
928 |
else: |
|
929 |
rationale = 'Subscriber' |
|
930 |
recipients.add(subscription.person, subscription, rationale) |
|
4333.2.7
by Tim Penhey
Updates following review |
931 |
return recipients |
3691.25.6
by James Henstridge
remove direct RevisionNumber usage in bzrsync |
932 |
|
8128.7.1
by Jonathan Lange
Add a pending_writes property to Branch. |
933 |
@property
|
934 |
def pending_writes(self): |
|
8128.7.3
by Jonathan Lange
More documentation. |
935 |
"""See `IBranch`.
|
936 |
||
8128.7.5
by Jonathan Lange
Docstring updates |
937 |
A branch has pending writes if it has just been pushed to, if it has
|
938 |
been mirrored and not yet scanned or if it is in the middle of being
|
|
939 |
mirrored.
|
|
8128.7.3
by Jonathan Lange
More documentation. |
940 |
"""
|
8128.7.4
by Jonathan Lange
More tests. |
941 |
new_data_pushed = ( |
10984.2.1
by Tim Penhey
Raise errors if trying to mirror a hosted branch. |
942 |
self.branch_type == BranchType.IMPORTED |
8128.7.4
by Jonathan Lange
More tests. |
943 |
and self.next_mirror_time is not None) |
9590.1.80
by Michael Hudson
de-xxx |
944 |
# XXX 2010-04-22, MichaelHudson: This should really look for a branch
|
10984.2.15
by Tim Penhey
Comment tweak. |
945 |
# scan job.
|
8128.7.4
by Jonathan Lange
More tests. |
946 |
pulled_but_not_scanned = self.last_mirrored_id != self.last_scanned_id |
947 |
pull_in_progress = ( |
|
948 |
self.last_mirror_attempt is not None |
|
949 |
and (self.last_mirrored is None |
|
950 |
or self.last_mirror_attempt > self.last_mirrored)) |
|
8128.7.1
by Jonathan Lange
Add a pending_writes property to Branch. |
951 |
return ( |
8128.7.4
by Jonathan Lange
More tests. |
952 |
new_data_pushed or pulled_but_not_scanned or pull_in_progress) |
8128.7.1
by Jonathan Lange
Add a pending_writes property to Branch. |
953 |
|
3836.2.13
by David Allouche
refactor BranchRevisionSet.getScannerDataForBranch into Branch |
954 |
def getScannerData(self): |
4629.4.1
by Tim Penhey
First cut, and some branch cleanup. |
955 |
"""See `IBranch`."""
|
12243.2.1
by Jeroen Vermeulen
Stop using BranchRevision.id from our code. |
956 |
columns = (BranchRevision.sequence, Revision.revision_id) |
7675.747.4
by Jeroen Vermeulen
Review changes, minus prejoins. |
957 |
rows = Store.of(self).using(Revision, BranchRevision).find( |
958 |
columns, |
|
959 |
Revision.id == BranchRevision.revision_id, |
|
960 |
BranchRevision.branch_id == self.id) |
|
961 |
rows = rows.order_by(BranchRevision.sequence) |
|
3836.2.13
by David Allouche
refactor BranchRevisionSet.getScannerDataForBranch into Branch |
962 |
ancestry = set() |
963 |
history = [] |
|
12243.2.1
by Jeroen Vermeulen
Stop using BranchRevision.id from our code. |
964 |
for sequence, revision_id in rows: |
3836.2.13
by David Allouche
refactor BranchRevisionSet.getScannerDataForBranch into Branch |
965 |
ancestry.add(revision_id) |
966 |
if sequence is not None: |
|
967 |
history.append(revision_id) |
|
7675.814.8
by Tim Penhey
Simplify the branch method for getting scanner data. |
968 |
return ancestry, history |
3836.2.13
by David Allouche
refactor BranchRevisionSet.getScannerDataForBranch into Branch |
969 |
|
4756.1.14
by Jonathan Lange
Move pull URL logic into Branch |
970 |
def getPullURL(self): |
971 |
"""See `IBranch`."""
|
|
972 |
if self.branch_type == BranchType.MIRRORED: |
|
973 |
# This is a pull branch, hosted externally.
|
|
974 |
return self.url |
|
975 |
elif self.branch_type == BranchType.IMPORTED: |
|
976 |
# This is an import branch, imported into bzr from
|
|
977 |
# another RCS system such as CVS.
|
|
978 |
prefix = config.launchpad.bzr_imports_root_url |
|
979 |
return urlappend(prefix, '%08x' % self.id) |
|
980 |
else: |
|
7675.747.9
by Jeroen Vermeulen
Lint. |
981 |
raise AssertionError("No pull URL for %r" % (self, )) |
4756.1.14
by Jonathan Lange
Move pull URL logic into Branch |
982 |
|
4386.2.5
by Jonathan Lange
requestMirror uses SQLObject. Add a requestMirror method to Branch |
983 |
def requestMirror(self): |
984 |
"""See `IBranch`."""
|
|
10984.2.1
by Tim Penhey
Raise errors if trying to mirror a hosted branch. |
985 |
if self.branch_type in (BranchType.REMOTE, BranchType.HOSTED): |
4813.4.7
by Tim Penhey
Missing imports |
986 |
raise BranchTypeError(self.unique_name) |
11134.3.3
by Jeroen Vermeulen
Drive-by lint. |
987 |
branch = Store.of(self).find( |
9587.2.1
by Michael Hudson
probably rather over engineered fix |
988 |
Branch, |
989 |
Branch.id == self.id, |
|
9587.2.2
by Michael Hudson
wrap long line |
990 |
Or(Branch.next_mirror_time > UTC_NOW, |
7675.747.9
by Jeroen Vermeulen
Lint. |
991 |
Branch.next_mirror_time == None)) |
992 |
branch.set(next_mirror_time=UTC_NOW) |
|
9587.2.1
by Michael Hudson
probably rather over engineered fix |
993 |
self.next_mirror_time = AutoReload |
5223.7.2
by jml at canonical
Rename mirror_request_time to next_mirror_time in code. |
994 |
return self.next_mirror_time |
4386.2.5
by Jonathan Lange
requestMirror uses SQLObject. Add a requestMirror method to Branch |
995 |
|
4386.2.8
by Jonathan Lange
Move startMirroring over to SQLObject, move implementation to Branch class. |
996 |
def startMirroring(self): |
997 |
"""See `IBranch`."""
|
|
10984.2.1
by Tim Penhey
Raise errors if trying to mirror a hosted branch. |
998 |
if self.branch_type in (BranchType.REMOTE, BranchType.HOSTED): |
4813.4.7
by Tim Penhey
Missing imports |
999 |
raise BranchTypeError(self.unique_name) |
4386.2.8
by Jonathan Lange
Move startMirroring over to SQLObject, move implementation to Branch class. |
1000 |
self.last_mirror_attempt = UTC_NOW |
6983.2.3
by Jonathan Lange
Make starting a mirror remove a branch from the pull queue. |
1001 |
self.next_mirror_time = None |
4386.2.8
by Jonathan Lange
Move startMirroring over to SQLObject, move implementation to Branch class. |
1002 |
|
12707.4.8
by Tim Penhey
Support the branch-id alias in the setting of the stacked on branch in the model code. |
1003 |
def _findStackedBranch(self, stacked_on_location): |
1004 |
location = stacked_on_location.strip('/') |
|
1005 |
if location.startswith(BRANCH_ID_ALIAS_PREFIX + '/'): |
|
1006 |
try: |
|
1007 |
branch_id = int(location.split('/', 1)[1]) |
|
1008 |
except (ValueError, IndexError): |
|
1009 |
return None |
|
1010 |
return getUtility(IBranchLookup).get(branch_id) |
|
1011 |
else: |
|
1012 |
return getUtility(IBranchLookup).getByUniqueName(location) |
|
1013 |
||
9590.4.7
by Michael Hudson
move the guts branchChanged onto the branch itself |
1014 |
def branchChanged(self, stacked_on_location, last_revision_id, |
1015 |
control_format, branch_format, repository_format): |
|
1016 |
"""See `IBranch`."""
|
|
1017 |
self.mirror_status_message = None |
|
10850.3.1
by Jeroen Vermeulen
Porting production-devel fix to devel. |
1018 |
if stacked_on_location == '' or stacked_on_location is None: |
9590.4.7
by Michael Hudson
move the guts branchChanged onto the branch itself |
1019 |
stacked_on_branch = None |
1020 |
else: |
|
12707.4.8
by Tim Penhey
Support the branch-id alias in the setting of the stacked on branch in the model code. |
1021 |
stacked_on_branch = self._findStackedBranch(stacked_on_location) |
9590.4.7
by Michael Hudson
move the guts branchChanged onto the branch itself |
1022 |
if stacked_on_branch is None: |
1023 |
self.mirror_status_message = ( |
|
1024 |
'Invalid stacked on location: ' + stacked_on_location) |
|
1025 |
self.stacked_on = stacked_on_branch |
|
9590.1.73
by Michael Hudson
tweaks to get the puller acceptance tests running |
1026 |
if self.branch_type == BranchType.HOSTED: |
1027 |
self.last_mirrored = UTC_NOW |
|
1028 |
else: |
|
1029 |
self.last_mirrored = self.last_mirror_attempt |
|
9590.4.7
by Michael Hudson
move the guts branchChanged onto the branch itself |
1030 |
self.mirror_failures = 0 |
1031 |
if (self.next_mirror_time is None |
|
1032 |
and self.branch_type == BranchType.MIRRORED): |
|
1033 |
# No mirror was requested since we started mirroring.
|
|
1034 |
increment = getUtility(IBranchPuller).MIRROR_TIME_INCREMENT |
|
1035 |
self.next_mirror_time = ( |
|
9590.1.73
by Michael Hudson
tweaks to get the puller acceptance tests running |
1036 |
datetime.now(pytz.timezone('UTC')) + increment) |
11573.6.2
by Tim Penhey
Only create a scan job if the new revision is different to the last scanned revision. |
1037 |
self.last_mirrored_id = last_revision_id |
1038 |
if self.last_scanned_id != last_revision_id: |
|
9590.4.7
by Michael Hudson
move the guts branchChanged onto the branch itself |
1039 |
from lp.code.model.branchjob import BranchScanJob |
1040 |
BranchScanJob.create(self) |
|
1041 |
self.control_format = control_format |
|
1042 |
self.branch_format = branch_format |
|
1043 |
self.repository_format = repository_format |
|
1044 |
||
4386.2.10
by Jonathan Lange
Move mirrorFailed's implementation to SQLObject, change RPC method to |
1045 |
def mirrorFailed(self, reason): |
1046 |
"""See `IBranch`."""
|
|
10984.2.1
by Tim Penhey
Raise errors if trying to mirror a hosted branch. |
1047 |
if self.branch_type in (BranchType.REMOTE, BranchType.HOSTED): |
4813.4.7
by Tim Penhey
Missing imports |
1048 |
raise BranchTypeError(self.unique_name) |
4386.2.10
by Jonathan Lange
Move mirrorFailed's implementation to SQLObject, change RPC method to |
1049 |
self.mirror_failures += 1 |
1050 |
self.mirror_status_message = reason |
|
8028.3.7
by Jonathan Lange
Store it on a local variable. |
1051 |
branch_puller = getUtility(IBranchPuller) |
1052 |
max_failures = branch_puller.MAXIMUM_MIRROR_FAILURES |
|
1053 |
increment = branch_puller.MIRROR_TIME_INCREMENT |
|
4795.1.6
by Jonathan Lange
Don't backoff imported or hosted branches -- they aren't going to correct |
1054 |
if (self.branch_type == BranchType.MIRRORED |
8028.3.2
by Jonathan Lange
Move the puller interface off branchset and into a new utility interface |
1055 |
and self.mirror_failures < max_failures): |
5223.7.2
by jml at canonical
Rename mirror_request_time to next_mirror_time in code. |
1056 |
self.next_mirror_time = ( |
4795.1.4
by Jonathan Lange
Stop mirroring after a certain number of failures. |
1057 |
datetime.now(pytz.timezone('UTC')) |
8028.3.2
by Jonathan Lange
Move the puller interface off branchset and into a new utility interface |
1058 |
+ increment * 2 ** (self.mirror_failures - 1)) |
4386.2.10
by Jonathan Lange
Move mirrorFailed's implementation to SQLObject, change RPC method to |
1059 |
|
10054.25.9
by Jelmer Vernooij
Drop the underscore. |
1060 |
def destroySelfBreakReferences(self): |
10054.25.7
by Jelmer Vernooij
Break references by default in the Branch destructor, per Thumpers suggestion. |
1061 |
"""See `IBranch`."""
|
12252.1.5
by j.c.sackett
Test running. |
1062 |
try: |
1063 |
return self.destroySelf(break_references=True) |
|
1064 |
except CannotDeleteBranch, e: |
|
1065 |
# Reraise and expose exception here so that the webservice_error
|
|
1066 |
# is propogated.
|
|
12499.1.5
by Leonard Richardson
Fix bug 728507 by removing calls to export(). |
1067 |
raise CannotDeleteBranch(e.message) |
10054.25.7
by Jelmer Vernooij
Break references by default in the Branch destructor, per Thumpers suggestion. |
1068 |
|
11134.3.2
by Jeroen Vermeulen
Clean up BuildQueues for BranchJobs. |
1069 |
def _deleteBranchSubscriptions(self): |
1070 |
"""Delete subscriptions for this branch prior to deleting branch."""
|
|
1071 |
subscriptions = Store.of(self).find( |
|
1072 |
BranchSubscription, BranchSubscription.branch == self) |
|
1073 |
subscriptions.remove() |
|
1074 |
||
1075 |
def _deleteJobs(self): |
|
1076 |
"""Delete jobs for this branch prior to deleting branch.
|
|
1077 |
||
1078 |
This deletion includes `BranchJob`s associated with the branch,
|
|
7675.823.2
by Jeroen Vermeulen
Register extra branch deletion requirement. |
1079 |
as well as `BuildQueue` entries for `TranslationTemplateBuildJob`s
|
1080 |
and `TranslationTemplateBuild`s.
|
|
11134.3.2
by Jeroen Vermeulen
Clean up BuildQueues for BranchJobs. |
1081 |
"""
|
1082 |
# Avoid circular imports.
|
|
1083 |
from lp.code.model.branchjob import BranchJob |
|
7675.823.3
by Jeroen Vermeulen
Circular import. |
1084 |
from lp.translations.model.translationtemplatesbuild import ( |
1085 |
TranslationTemplatesBuild, |
|
1086 |
)
|
|
11134.3.2
by Jeroen Vermeulen
Clean up BuildQueues for BranchJobs. |
1087 |
|
1088 |
store = Store.of(self) |
|
1089 |
affected_jobs = Select( |
|
1090 |
[BranchJob.jobID], |
|
1091 |
And(BranchJob.job == Job.id, BranchJob.branch == self)) |
|
1092 |
||
1093 |
# Delete BuildQueue entries for affected Jobs. They would pin
|
|
1094 |
# the affected Jobs in the database otherwise.
|
|
1095 |
store.find(BuildQueue, BuildQueue.jobID.is_in(affected_jobs)).remove() |
|
1096 |
||
1097 |
# Delete Jobs. Their BranchJobs cascade along in the database.
|
|
1098 |
store.find(Job, Job.id.is_in(affected_jobs)).remove() |
|
1099 |
||
7675.823.2
by Jeroen Vermeulen
Register extra branch deletion requirement. |
1100 |
store.find( |
1101 |
TranslationTemplatesBuild, |
|
1102 |
TranslationTemplatesBuild.branch == self).remove() |
|
1103 |
||
5616.2.16
by Aaron Bentley
Change BranchSet.delete to Branch.destroySelf |
1104 |
def destroySelf(self, break_references=False): |
1105 |
"""See `IBranch`."""
|
|
7675.202.11
by Michael Hudson
create a reclaimbranchspacejob on branch deletion |
1106 |
from lp.code.interfaces.branchjob import IReclaimBranchSpaceJobSource |
5616.2.16
by Aaron Bentley
Change BranchSet.delete to Branch.destroySelf |
1107 |
if break_references: |
1108 |
self._breakReferences() |
|
8211.4.11
by Jonathan Lange
Shuffle around slightly to reduce indentation. |
1109 |
if not self.canBeDeleted(): |
5616.2.16
by Aaron Bentley
Change BranchSet.delete to Branch.destroySelf |
1110 |
raise CannotDeleteBranch( |
1111 |
"Cannot delete branch: %s" % self.unique_name) |
|
11134.3.2
by Jeroen Vermeulen
Clean up BuildQueues for BranchJobs. |
1112 |
|
1113 |
self._deleteBranchSubscriptions() |
|
1114 |
self._deleteJobs() |
|
1115 |
||
8211.4.11
by Jonathan Lange
Shuffle around slightly to reduce indentation. |
1116 |
# Now destroy the branch.
|
7675.202.11
by Michael Hudson
create a reclaimbranchspacejob on branch deletion |
1117 |
branch_id = self.id |
8211.4.11
by Jonathan Lange
Shuffle around slightly to reduce indentation. |
1118 |
SQLBase.destroySelf(self) |
7675.202.11
by Michael Hudson
create a reclaimbranchspacejob on branch deletion |
1119 |
# And now create a job to remove the branch from disk when it's done.
|
1120 |
getUtility(IReclaimBranchSpaceJobSource).create(branch_id) |
|
5616.2.16
by Aaron Bentley
Change BranchSet.delete to Branch.destroySelf |
1121 |
|
8137.17.24
by Barry Warsaw
thread merge |
1122 |
def commitsForDays(self, since): |
1123 |
"""See `IBranch`."""
|
|
7675.747.9
by Jeroen Vermeulen
Lint. |
1124 |
|
8137.17.24
by Barry Warsaw
thread merge |
1125 |
class DateTrunc(NamedFunc): |
1126 |
name = "date_trunc" |
|
11134.3.3
by Jeroen Vermeulen
Drive-by lint. |
1127 |
|
8137.17.24
by Barry Warsaw
thread merge |
1128 |
results = Store.of(self).find( |
7675.166.305
by Stuart Bishop
DB Unicode fixes |
1129 |
(DateTrunc(u'day', Revision.revision_date), Count(Revision.id)), |
7675.747.1
by Jeroen Vermeulen
Intermediate state: stormifying BranchRevision. |
1130 |
Revision.id == BranchRevision.revision_id, |
8137.17.24
by Barry Warsaw
thread merge |
1131 |
Revision.revision_date > since, |
1132 |
BranchRevision.branch == self) |
|
1133 |
results = results.group_by( |
|
7675.166.305
by Stuart Bishop
DB Unicode fixes |
1134 |
DateTrunc(u'day', Revision.revision_date)) |
8137.17.24
by Barry Warsaw
thread merge |
1135 |
return sorted(results) |
1136 |
||
8303.17.1
by Paul Hummer
Added tests for needsUpgrading |
1137 |
@property
|
8303.17.5
by Paul Hummer
Responded to Aaron's second review |
1138 |
def needs_upgrading(self): |
8303.17.1
by Paul Hummer
Added tests for needsUpgrading |
1139 |
"""See `IBranch`."""
|
10249.1.2
by Paul Hummer
Added logic and tests to ensure that the branch is a hosted branch, so we don't try and upgrade other branch types. |
1140 |
if self.branch_type is not BranchType.HOSTED: |
1141 |
return False |
|
7675.477.1
by Paul Hummer
Reverted the reversion of the patch that went into devel by mistake |
1142 |
if self.upgrade_pending: |
1143 |
return False |
|
1144 |
return not ( |
|
1145 |
self.branch_format in CURRENT_BRANCH_FORMATS and |
|
1146 |
self.repository_format in CURRENT_REPOSITORY_FORMATS) |
|
1147 |
||
1148 |
@property
|
|
1149 |
def upgrade_pending(self): |
|
1150 |
"""See `IBranch`."""
|
|
1151 |
from lp.code.model.branchjob import BranchJob, BranchJobType |
|
1152 |
store = Store.of(self) |
|
1153 |
jobs = store.find( |
|
1154 |
BranchJob, |
|
1155 |
BranchJob.branch == self, |
|
7675.493.2
by Paul Hummer
Fixed an issue with upgrade_pending |
1156 |
Job.id == BranchJob.jobID, |
1157 |
Job._status != JobStatus.COMPLETED, |
|
1158 |
Job._status != JobStatus.FAILED, |
|
7675.477.1
by Paul Hummer
Reverted the reversion of the patch that went into devel by mistake |
1159 |
BranchJob.job_type == BranchJobType.UPGRADE_BRANCH) |
1160 |
return jobs.count() > 0 |
|
10174.2.4
by Paul Hummer
Added IBranch.upgrade_pending property. |
1161 |
|
9644.8.6
by Paul Hummer
Added test and stub code for IBranch.requestUpgrade |
1162 |
def requestUpgrade(self): |
1163 |
"""See `IBranch`."""
|
|
9644.8.9
by Paul Hummer
Changed how the job gets created |
1164 |
from lp.code.interfaces.branchjob import IBranchUpgradeJobSource |
1165 |
return getUtility(IBranchUpgradeJobSource).create(self) |
|
9644.8.6
by Paul Hummer
Added test and stub code for IBranch.requestUpgrade |
1166 |
|
9550.16.2
by Tim Penhey
Move the access branch logic into the branch itself. |
1167 |
def _checkBranchVisibleByUser(self, user): |
1168 |
"""Is *this* branch visible by the user.
|
|
1169 |
||
1170 |
This method doesn't check the stacked upon branch. That is handled by
|
|
1171 |
the `visibleByUser` method.
|
|
1172 |
"""
|
|
1173 |
if not self.private: |
|
1174 |
return True |
|
1175 |
if user is None: |
|
1176 |
return False |
|
1177 |
if user.inTeam(self.owner): |
|
1178 |
return True |
|
1179 |
for subscriber in self.subscribers: |
|
1180 |
if user.inTeam(subscriber): |
|
1181 |
return True |
|
1182 |
return user_has_special_branch_access(user) |
|
1183 |
||
1184 |
def visibleByUser(self, user, checked_branches=None): |
|
1185 |
"""See `IBranch`."""
|
|
1186 |
if checked_branches is None: |
|
1187 |
checked_branches = [] |
|
1188 |
can_access = self._checkBranchVisibleByUser(user) |
|
1189 |
if can_access and self.stacked_on is not None: |
|
1190 |
checked_branches.append(self) |
|
1191 |
if self.stacked_on not in checked_branches: |
|
1192 |
can_access = self.stacked_on.visibleByUser( |
|
1193 |
user, checked_branches) |
|
1194 |
return can_access |
|
1195 |
||
12397.2.8
by Ian Booth
Change from using getter methods to properties for exported recipe and build accessors |
1196 |
@property
|
1197 |
def recipes(self): |
|
7675.615.4
by Paul Hummer
Added IHasRecipes |
1198 |
"""See `IHasRecipes`."""
|
7675.615.9
by Paul Hummer
SUCCESS!!!! |
1199 |
from lp.code.model.sourcepackagerecipedata import ( |
1200 |
SourcePackageRecipeData) |
|
10498.5.36
by Aaron Bentley
Deleting branches used in recipes deletes the recipes. |
1201 |
return SourcePackageRecipeData.findRecipes(self) |
7675.615.4
by Paul Hummer
Added IHasRecipes |
1202 |
|
7675.887.20
by Paul Hummer
Added IBranch.addToQueue with accompanying tests |
1203 |
merge_queue_id = Int(name='merge_queue', allow_none=True) |
1204 |
merge_queue = Reference(merge_queue_id, 'BranchMergeQueue.id') |
|
1205 |
||
7675.887.18
by Paul Hummer
Added merge_queue and merge_queue_config, removed getMergeQueue |
1206 |
merge_queue_config = StringCol(dbName='merge_queue_config') |
1207 |
||
7675.887.20
by Paul Hummer
Added IBranch.addToQueue with accompanying tests |
1208 |
def addToQueue(self, queue): |
1209 |
"""See `IBranchEdit`."""
|
|
1210 |
self.merge_queue = queue |
|
1211 |
||
7675.887.21
by Paul Hummer
Added IBranch.setMergeQueueConfig with accompanying tests |
1212 |
def setMergeQueueConfig(self, config): |
1213 |
"""See `IBranchEdit`."""
|
|
1214 |
try: |
|
1215 |
simplejson.loads(config) |
|
1216 |
self.merge_queue_config = config |
|
1217 |
except ValueError: # The json string is invalid |
|
1218 |
raise InvalidMergeQueueConfig |
|
1219 |
||
4960.1.13
by Michael Hudson
docstrings and line lengths in database/branch.py |
1220 |
|
6019.2.1
by Aaron Bentley
Use objects instead of closures for deletion |
1221 |
class DeletionOperation: |
1222 |
"""Represent an operation to perform as part of branch deletion."""
|
|
1223 |
||
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1224 |
def __init__(self, affected_object, rationale): |
10498.5.42
by Aaron Bentley
Ensure branch deletion respects zope permissions |
1225 |
self.affected_object = ProxyFactory(affected_object) |
6019.2.4
by Aaron Bentley
Move affected_object, rationale into into DeletionOperation |
1226 |
self.rationale = rationale |
7675.747.9
by Jeroen Vermeulen
Lint. |
1227 |
|
6019.2.10
by Aaron Bentley
Updatest from review |
1228 |
def __call__(self): |
1229 |
"""Perform the deletion operation."""
|
|
1230 |
raise NotImplementedError(DeletionOperation.__call__) |
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1231 |
|
6019.2.11
by Aaron Bentley
PEP8 |
1232 |
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1233 |
class DeletionCallable(DeletionOperation): |
6019.2.7
by Aaron Bentley
Update docs |
1234 |
"""Deletion operation that invokes a callable."""
|
1235 |
||
6019.2.8
by Aaron Bentley
Remove DeletionCallable.func_args, add tests |
1236 |
def __init__(self, affected_object, rationale, func): |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1237 |
DeletionOperation.__init__(self, affected_object, rationale) |
6019.2.1
by Aaron Bentley
Use objects instead of closures for deletion |
1238 |
self.func = func |
1239 |
||
6019.2.10
by Aaron Bentley
Updatest from review |
1240 |
def __call__(self): |
6019.2.8
by Aaron Bentley
Remove DeletionCallable.func_args, add tests |
1241 |
self.func() |
6019.2.1
by Aaron Bentley
Use objects instead of closures for deletion |
1242 |
|
10498.5.36
by Aaron Bentley
Deleting branches used in recipes deletes the recipes. |
1243 |
@classmethod
|
1244 |
def forSourcePackageRecipe(cls, recipe): |
|
1245 |
return cls( |
|
1246 |
recipe, _('This recipe uses this branch.'), recipe.destroySelf) |
|
1247 |
||
6019.2.1
by Aaron Bentley
Use objects instead of closures for deletion |
1248 |
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1249 |
class ClearDependentBranch(DeletionOperation): |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
1250 |
"""Delete operation that clears a merge proposal's prerequisite branch."""
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1251 |
|
1252 |
def __init__(self, merge_proposal): |
|
1253 |
DeletionOperation.__init__(self, merge_proposal, |
|
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
1254 |
_('This branch is the prerequisite branch of this merge' |
1255 |
' proposal.')) |
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1256 |
|
6019.2.10
by Aaron Bentley
Updatest from review |
1257 |
def __call__(self): |
7675.343.1
by Aaron Bentley
Rename dependent branch to prerequisite branch. |
1258 |
self.affected_object.prerequisite_branch = None |
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1259 |
|
1260 |
||
1261 |
class ClearSeriesBranch(DeletionOperation): |
|
6019.2.7
by Aaron Bentley
Update docs |
1262 |
"""Deletion operation that clears a series' branch."""
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1263 |
|
1264 |
def __init__(self, series, branch): |
|
1265 |
DeletionOperation.__init__( |
|
1266 |
self, series, _('This series is linked to this branch.')) |
|
1267 |
self.branch = branch |
|
1268 |
||
6019.2.10
by Aaron Bentley
Updatest from review |
1269 |
def __call__(self): |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
1270 |
if self.affected_object.branch == self.branch: |
1271 |
self.affected_object.branch = None |
|
6019.2.6
by Aaron Bentley
Split callables out, convert to subclasses |
1272 |
|
1273 |
||
8771.6.1
by Jeroen Vermeulen
UI for exporting translations to bzr branch. |
1274 |
class ClearSeriesTranslationsBranch(DeletionOperation): |
1275 |
"""Deletion operation that clears a series' translations branch."""
|
|
1276 |
||
1277 |
def __init__(self, series, branch): |
|
1278 |
DeletionOperation.__init__( |
|
1279 |
self, series, |
|
1280 |
_('This series exports its translations to this branch.')) |
|
1281 |
self.branch = branch |
|
1282 |
||
1283 |
def __call__(self): |
|
11316.6.2
by Tim Penhey
The translation clearing class didn't do what it said, and it wasn't tested. |
1284 |
if self.affected_object.translations_branch == self.branch: |
1285 |
self.affected_object.translations_branch = None |
|
8771.6.1
by Jeroen Vermeulen
UI for exporting translations to bzr branch. |
1286 |
|
1287 |
||
8211.4.12
by Jonathan Lange
Allow branches linked to source packages to be deleted. |
1288 |
class ClearOfficialPackageBranch(DeletionOperation): |
1289 |
"""Deletion operation that clears an official package branch."""
|
|
1290 |
||
1291 |
def __init__(self, sspb): |
|
1292 |
DeletionOperation.__init__( |
|
1293 |
self, sspb, _('Branch is officially linked to a source package.')) |
|
1294 |
||
1295 |
def __call__(self): |
|
1296 |
package = self.affected_object.sourcepackage |
|
1297 |
pocket = self.affected_object.pocket |
|
1298 |
package.setBranch(pocket, None, None) |
|
1299 |
||
1300 |
||
6019.2.9
by Aaron Bentley
Add DeleteCodeImport class |
1301 |
class DeleteCodeImport(DeletionOperation): |
1302 |
"""Deletion operation that deletes a branch's import."""
|
|
1303 |
||
1304 |
def __init__(self, code_import): |
|
1305 |
DeletionOperation.__init__( |
|
7675.747.9
by Jeroen Vermeulen
Lint. |
1306 |
self, code_import, _('This is the import data for this branch.')) |
6019.2.9
by Aaron Bentley
Add DeleteCodeImport class |
1307 |
|
6019.2.10
by Aaron Bentley
Updatest from review |
1308 |
def __call__(self): |
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
1309 |
from lp.code.model.codeimport import CodeImportSet |
6019.2.9
by Aaron Bentley
Add DeleteCodeImport class |
1310 |
CodeImportSet().delete(self.affected_object) |
1311 |
||
1312 |
||
1102.1.80
by David Allouche
product/+addbranch, branch.registrant to branch.author in db patch and sample data |
1313 |
class BranchSet: |
1314 |
"""The set of all branches."""
|
|
1315 |
||
8028.2.5
by Jonathan Lange
Move the implementation. |
1316 |
implements(IBranchSet) |
1102.1.80
by David Allouche
product/+addbranch, branch.registrant to branch.author in db patch and sample data |
1317 |
|
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1318 |
def getRecentlyChangedBranches( |
1319 |
self, branch_count=None, |
|
1320 |
lifecycle_statuses=DEFAULT_BRANCH_STATUS_IN_LISTING, |
|
1321 |
visible_by_user=None): |
|
1322 |
"""See `IBranchSet`."""
|
|
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1323 |
all_branches = getUtility(IAllBranches) |
1324 |
branches = all_branches.visibleByUser( |
|
1325 |
visible_by_user).withLifecycleStatus(*lifecycle_statuses) |
|
1326 |
branches = branches.withBranchType( |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
1327 |
BranchType.HOSTED, BranchType.MIRRORED).scanned().getBranches( |
1328 |
eager_load=False) |
|
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1329 |
branches.order_by( |
7675.92.2
by Tim Penhey
Make the pagetests work again. |
1330 |
Desc(Branch.date_last_modified), Desc(Branch.id)) |
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1331 |
if branch_count is not None: |
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1332 |
branches.config(limit=branch_count) |
1333 |
return branches |
|
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1334 |
|
1335 |
def getRecentlyImportedBranches( |
|
1336 |
self, branch_count=None, |
|
1337 |
lifecycle_statuses=DEFAULT_BRANCH_STATUS_IN_LISTING, |
|
1338 |
visible_by_user=None): |
|
1339 |
"""See `IBranchSet`."""
|
|
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1340 |
all_branches = getUtility(IAllBranches) |
1341 |
branches = all_branches.visibleByUser( |
|
1342 |
visible_by_user).withLifecycleStatus(*lifecycle_statuses) |
|
1343 |
branches = branches.withBranchType( |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
1344 |
BranchType.IMPORTED).scanned().getBranches(eager_load=False) |
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1345 |
branches.order_by( |
7675.92.2
by Tim Penhey
Make the pagetests work again. |
1346 |
Desc(Branch.date_last_modified), Desc(Branch.id)) |
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1347 |
if branch_count is not None: |
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1348 |
branches.config(limit=branch_count) |
1349 |
return branches |
|
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1350 |
|
1351 |
def getRecentlyRegisteredBranches( |
|
1352 |
self, branch_count=None, |
|
1353 |
lifecycle_statuses=DEFAULT_BRANCH_STATUS_IN_LISTING, |
|
1354 |
visible_by_user=None): |
|
1355 |
"""See `IBranchSet`."""
|
|
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1356 |
all_branches = getUtility(IAllBranches) |
1357 |
branches = all_branches.withLifecycleStatus( |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
1358 |
*lifecycle_statuses).visibleByUser(visible_by_user).getBranches( |
1359 |
eager_load=False) |
|
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1360 |
branches.order_by( |
1361 |
Desc(Branch.date_created), Desc(Branch.id)) |
|
4619.1.1
by Tim Penhey
Project cloud preview, and more... for code front page listings. |
1362 |
if branch_count is not None: |
7839.2.1
by Jonathan Lange
Make all of the BranchSet.getRecentFoo methods use IBranchCollection. |
1363 |
branches.config(limit=branch_count) |
1364 |
return branches |
|
3754.2.3
by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page |
1365 |
|
8777.4.6
by Jonathan Lange
Merge the new branches interface with branch set. |
1366 |
def getByUniqueName(self, unique_name): |
1367 |
"""See `IBranchSet`."""
|
|
1368 |
return getUtility(IBranchLookup).getByUniqueName(unique_name) |
|
1369 |
||
1370 |
def getByUrl(self, url): |
|
1371 |
"""See `IBranchSet`."""
|
|
1372 |
return getUtility(IBranchLookup).getByUrl(url) |
|
1373 |
||
9841.2.2
by Jonathan Lange
Actually expose the method over the API, but it doesn't work because we |
1374 |
def getByUrls(self, urls): |
1375 |
"""See `IBranchSet`."""
|
|
9841.2.11
by Jonathan Lange
Re-add the code to branch lookup, since it's actually kind of useful. |
1376 |
return getUtility(IBranchLookup).getByUrls(urls) |
9841.2.2
by Jonathan Lange
Actually expose the method over the API, but it doesn't work because we |
1377 |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
1378 |
def getBranches(self, limit=50, eager_load=True): |
8777.4.6
by Jonathan Lange
Merge the new branches interface with branch set. |
1379 |
"""See `IBranchSet`."""
|
1380 |
anon_branches = getUtility(IAllBranches).visibleByUser(None) |
|
12504.1.3
by Robert Collins
Reject reversion of this branch on trunk. |
1381 |
branches = anon_branches.scanned().getBranches(eager_load=eager_load) |
8777.4.6
by Jonathan Lange
Merge the new branches interface with branch set. |
1382 |
branches.order_by( |
1383 |
Desc(Branch.date_last_modified), Desc(Branch.id)) |
|
1384 |
branches.config(limit=limit) |
|
1385 |
return branches |
|
1386 |
||
6266.2.1
by Tim Penhey
Refactor the many getBranchesForXXX into a single getBranchesForContext. |
1387 |
|
7675.171.10
by Tim Penhey
Have a single subscriber to the modified event do the field updating and call the method to send the branch email. |
1388 |
def update_trigger_modified_fields(branch): |
1389 |
"""Make the trigger updated fields reload when next accessed."""
|
|
7675.171.6
by Tim Penhey
Add a function to reload the trigger update fields on an object modifed event. |
1390 |
# Not all the fields are exposed through the interface, and some are read
|
1391 |
# only, so remove the security proxy.
|
|
1392 |
naked_branch = removeSecurityProxy(branch) |
|
1393 |
naked_branch.unique_name = AutoReload |
|
1394 |
naked_branch.owner_name = AutoReload |
|
1395 |
naked_branch.target_suffix = AutoReload |
|
7675.171.10
by Tim Penhey
Have a single subscriber to the modified event do the field updating and call the method to send the branch email. |
1396 |
|
1397 |
||
1398 |
def branch_modified_subscriber(branch, event): |
|
1399 |
"""This method is subscribed to IObjectModifiedEvents for branches.
|
|
1400 |
||
1401 |
We have a single subscriber registered and dispatch from here to ensure
|
|
1402 |
that the database fields are updated first before other subscribers.
|
|
1403 |
"""
|
|
1404 |
update_trigger_modified_fields(branch) |
|
1405 |
send_branch_modified_notifications(branch, event) |