Merge lp:~cjwatson/launchpad/branch-unscan-affordances into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18497
Proposed branch: lp:~cjwatson/launchpad/branch-unscan-affordances
Merge into: lp:launchpad
Diff against target: 509 lines (+161/-60)
15 files modified
lib/lp/code/browser/branch.py (+3/-3)
lib/lp/code/browser/branchmergeproposal.py (+3/-3)
lib/lp/code/browser/tests/test_branch.py (+1/-1)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+20/-0)
lib/lp/code/interfaces/branch.py (+6/-0)
lib/lp/code/interfaces/gitref.py (+1/-1)
lib/lp/code/interfaces/gitrepository.py (+1/-1)
lib/lp/code/model/branch.py (+37/-9)
lib/lp/code/model/gitref.py (+3/-3)
lib/lp/code/model/gitrepository.py (+1/-1)
lib/lp/code/model/tests/test_branch.py (+73/-26)
lib/lp/code/model/tests/test_gitrepository.py (+7/-7)
lib/lp/code/templates/branch-index.pt (+2/-2)
lib/lp/code/templates/gitrepository-index.pt (+2/-2)
lib/lp/codehosting/tests/test_branchdistro.py (+1/-1)
To merge this branch: bzr merge lp:~cjwatson/launchpad/branch-unscan-affordances
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+333251@code.launchpad.net

Commit message

Improve handling of branches with various kinds of partial data.

Description of the change

This tidies up OOPSes on e.g. dogfood, and allows us to unscan branches without having the branches and any associated merge proposals displaying permanent "Updating" UI indications.

I could probably have made this shorter by renaming the other half of the pending_updates/pending_writes split, but I've always found the naming a bit confusing and thought it was clearer this way round (hence also why I renamed the Git analogue to match). I tried making pending_writes be a superset of pending_updates, but the test failures were a bit catastrophic, and users of this really do care about whether the actual scanned data is in sync rather than whether there happens to be a branch scan job in progress.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py 2016-11-11 12:51:58 +0000
+++ lib/lp/code/browser/branch.py 2017-11-08 11:16:30 +0000
@@ -451,9 +451,9 @@
451 return self.context.control_format is None451 return self.context.control_format is None
452452
453 @property453 @property
454 def pending_writes(self):454 def pending_updates(self):
455 """Whether or not there are pending writes for this branch."""455 """Whether or not there are pending updates for this branch."""
456 return self.context.pending_writes456 return self.context.pending_updates
457457
458 def bzr_download_url(self):458 def bzr_download_url(self):
459 """Return the generic URL for downloading the branch."""459 """Return the generic URL for downloading the branch."""
460460
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2017-05-24 12:04:18 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2017-11-08 11:16:30 +0000
@@ -370,7 +370,7 @@
370 return []370 return []
371371
372 @property372 @property
373 def pending_writes(self):373 def pending_updates(self):
374 """Needed to make the branch-revisions metal macro work."""374 """Needed to make the branch-revisions metal macro work."""
375 return False375 return False
376376
@@ -532,7 +532,7 @@
532 diff = preview_diff.text.decode('utf-8')532 diff = preview_diff.text.decode('utf-8')
533 except UnicodeDecodeError:533 except UnicodeDecodeError:
534 diff = preview_diff.text.decode('windows-1252', 'replace')534 diff = preview_diff.text.decode('windows-1252', 'replace')
535 except LibrarianServerError:535 except (LookupError, LibrarianServerError):
536 self._diff_available = False536 self._diff_available = False
537 diff = ''537 diff = ''
538 # Strip off the trailing carriage returns.538 # Strip off the trailing carriage returns.
@@ -736,7 +736,7 @@
736 def pending_diff(self):736 def pending_diff(self):
737 return (737 return (
738 self.context.next_preview_diff_job is not None or738 self.context.next_preview_diff_job is not None or
739 self.context.merge_source.pending_writes)739 self.context.merge_source.pending_updates)
740740
741 @cachedproperty741 @cachedproperty
742 def preview_diff(self):742 def preview_diff(self):
743743
=== modified file 'lib/lp/code/browser/tests/test_branch.py'
--- lib/lp/code/browser/tests/test_branch.py 2017-10-04 01:16:22 +0000
+++ lib/lp/code/browser/tests/test_branch.py 2017-11-08 11:16:30 +0000
@@ -607,7 +607,7 @@
607 logout()607 logout()
608 with StormStatementRecorder() as recorder:608 with StormStatementRecorder() as recorder:
609 browser.open(branch_url)609 browser.open(branch_url)
610 self.assertThat(recorder, HasQueryCount(Equals(27)))610 self.assertThat(recorder, HasQueryCount(Equals(28)))
611611
612612
613class TestBranchViewPrivateArtifacts(BrowserTestCase):613class TestBranchViewPrivateArtifacts(BrowserTestCase):
614614
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2017-10-04 01:16:22 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2017-11-08 11:16:30 +0000
@@ -1395,6 +1395,26 @@
1395 markup = view()1395 markup = view()
1396 self.assertIn('The diff is not available at this time.', markup)1396 self.assertIn('The diff is not available at this time.', markup)
13971397
1398 def test_preview_diff_lookup_error(self):
1399 # The preview_diff will recover from a LookupError while getting the
1400 # librarian content. (This can happen e.g. on staging replicas of
1401 # the production database.)
1402 text = b''.join(chr(x) for x in range(255))
1403 diff_bytes = b''.join(unified_diff(b'', text))
1404 preview_diff = self.setPreviewDiff(diff_bytes)
1405 transaction.commit()
1406
1407 def fake_open(*args):
1408 raise LookupError
1409
1410 lfa = preview_diff.diff.diff_text
1411 with monkey_patch(lfa, open=fake_open):
1412 view = create_initialized_view(preview_diff, '+diff')
1413 self.assertEqual('', view.preview_diff_text)
1414 self.assertFalse(view.diff_available)
1415 markup = view()
1416 self.assertIn('The diff is not available at this time.', markup)
1417
1398 def setPreviewDiff(self, preview_diff_bytes):1418 def setPreviewDiff(self, preview_diff_bytes):
1399 return PreviewDiff.create(1419 return PreviewDiff.create(
1400 self.bmp, preview_diff_bytes, 'a', 'b', None, '')1420 self.bmp, preview_diff_bytes, 'a', 'b', None, '')
14011421
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2016-11-11 12:51:58 +0000
+++ lib/lp/code/interfaces/branch.py 2017-11-08 11:16:30 +0000
@@ -538,6 +538,12 @@
538 pending_writes = Attribute(538 pending_writes = Attribute(
539 "Whether there is new Bazaar data for this branch.")539 "Whether there is new Bazaar data for this branch.")
540540
541 pending_updates = Attribute(
542 "Whether there is an update job of some kind (mirroring or scanning) "
543 "pending for the Bazaar data in this branch. Note that "
544 "pending_writes may be True and pending_updates False if a branch "
545 "has been unscanned.")
546
541 def latest_revisions(quantity=10):547 def latest_revisions(quantity=10):
542 """A specific number of the latest revisions in that branch."""548 """A specific number of the latest revisions in that branch."""
543549
544550
=== modified file 'lib/lp/code/interfaces/gitref.py'
--- lib/lp/code/interfaces/gitref.py 2016-12-05 14:46:40 +0000
+++ lib/lp/code/interfaces/gitref.py 2017-11-08 11:16:30 +0000
@@ -358,7 +358,7 @@
358 eager_load=False):358 eager_load=False):
359 """Return BranchMergeProposals dependent on merging this reference."""359 """Return BranchMergeProposals dependent on merging this reference."""
360360
361 pending_writes = Attribute(361 pending_updates = Attribute(
362 "Whether there are recent changes in this repository that have not "362 "Whether there are recent changes in this repository that have not "
363 "yet been scanned.")363 "yet been scanned.")
364364
365365
=== modified file 'lib/lp/code/interfaces/gitrepository.py'
--- lib/lp/code/interfaces/gitrepository.py 2017-02-10 12:52:07 +0000
+++ lib/lp/code/interfaces/gitrepository.py 2017-11-08 11:16:30 +0000
@@ -537,7 +537,7 @@
537 def isRepositoryMergeable(other):537 def isRepositoryMergeable(other):
538 """Is the other repository mergeable into this one (or vice versa)?"""538 """Is the other repository mergeable into this one (or vice versa)?"""
539539
540 pending_writes = Attribute(540 pending_updates = Attribute(
541 "Whether there are recent changes in this repository that have not "541 "Whether there are recent changes in this repository that have not "
542 "yet been scanned.")542 "yet been scanned.")
543543
544544
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2016-11-11 14:24:38 +0000
+++ lib/lp/code/model/branch.py 2017-11-08 11:16:30 +0000
@@ -1163,25 +1163,53 @@
1163 return recipients1163 return recipients
11641164
1165 @property1165 @property
1166 def pending_writes(self):1166 def _pending_mirror_operations(self):
1167 """See `IBranch`.1167 """Does this branch have pending mirror operations?
11681168
1169 A branch has pending writes if it has just been pushed to, if it has1169 A branch has pending mirror operations if it is an imported branch
1170 been mirrored and not yet scanned or if it is in the middle of being1170 that has just been pushed to or if it is in the middle of being
1171 mirrored.1171 mirrored.
1172 """1172 """
1173 new_data_pushed = (1173 new_data_pushed = (
1174 self.branch_type == BranchType.IMPORTED1174 self.branch_type == BranchType.IMPORTED
1175 and self.next_mirror_time is not None)1175 and self.next_mirror_time is not None)
1176 # XXX 2010-04-22, MichaelHudson: This should really look for a branch
1177 # scan job.
1178 pulled_but_not_scanned = self.last_mirrored_id != self.last_scanned_id
1179 pull_in_progress = (1176 pull_in_progress = (
1180 self.last_mirror_attempt is not None1177 self.last_mirror_attempt is not None
1181 and (self.last_mirrored is None1178 and (self.last_mirrored is None
1182 or self.last_mirror_attempt > self.last_mirrored))1179 or self.last_mirror_attempt > self.last_mirrored))
1183 return (1180 return new_data_pushed or pull_in_progress
1184 new_data_pushed or pulled_but_not_scanned or pull_in_progress)1181
1182 @property
1183 def pending_writes(self):
1184 """See `IBranch`.
1185
1186 A branch has pending writes if it has pending mirror operations or
1187 if it has been mirrored and not yet scanned. Use this when you need
1188 to know if the branch is in a condition where it is possible to run
1189 other jobs on it: for example, a branch that has been unscanned
1190 cannot support jobs being run for its related merge proposals.
1191 """
1192 pulled_but_not_scanned = self.last_mirrored_id != self.last_scanned_id
1193 return self._pending_mirror_operations or pulled_but_not_scanned
1194
1195 @property
1196 def pending_updates(self):
1197 """See `IBranch`.
1198
1199 A branch has pending updates if it has pending mirror operations or
1200 if it has a pending scan job. Use this when you need to know if
1201 there is work queued, for example when deciding whether to display
1202 in-progress UI indicators.
1203 """
1204 from lp.code.model.branchjob import BranchJob, BranchJobType
1205 jobs = Store.of(self).find(
1206 BranchJob,
1207 BranchJob.branch == self,
1208 Job.id == BranchJob.jobID,
1209 Job._status.is_in([JobStatus.WAITING, JobStatus.RUNNING]),
1210 BranchJob.job_type == BranchJobType.SCAN_BRANCH)
1211 pending_scan_job = not jobs.is_empty()
1212 return self._pending_mirror_operations or pending_scan_job
11851213
1186 def getScannerData(self):1214 def getScannerData(self):
1187 """See `IBranch`."""1215 """See `IBranch`."""
11881216
=== modified file 'lib/lp/code/model/gitref.py'
--- lib/lp/code/model/gitref.py 2017-08-22 11:33:34 +0000
+++ lib/lp/code/model/gitref.py 2017-11-08 11:16:30 +0000
@@ -282,9 +282,9 @@
282 prerequisite_path=self.path, eager_load=eager_load)282 prerequisite_path=self.path, eager_load=eager_load)
283283
284 @property284 @property
285 def pending_writes(self):285 def pending_updates(self):
286 """See `IGitRef`."""286 """See `IGitRef`."""
287 return self.repository.pending_writes287 return self.repository.pending_updates
288288
289 def _getLog(self, start, limit=None, stop=None, union_repository=None,289 def _getLog(self, start, limit=None, stop=None, union_repository=None,
290 enable_hosting=None, enable_memcache=None, logger=None):290 enable_hosting=None, enable_memcache=None, logger=None):
@@ -715,7 +715,7 @@
715 createMergeProposal = _unimplemented715 createMergeProposal = _unimplemented
716 getMergeProposals = _unimplemented716 getMergeProposals = _unimplemented
717 getDependentMergeProposals = _unimplemented717 getDependentMergeProposals = _unimplemented
718 pending_writes = False718 pending_updates = False
719719
720 def getCommits(self, *args, **kwargs):720 def getCommits(self, *args, **kwargs):
721 """See `IGitRef`."""721 """See `IGitRef`."""
722722
=== modified file 'lib/lp/code/model/gitrepository.py'
--- lib/lp/code/model/gitrepository.py 2017-05-04 16:02:40 +0000
+++ lib/lp/code/model/gitrepository.py 2017-11-08 11:16:30 +0000
@@ -949,7 +949,7 @@
949 return self.namespace.areRepositoriesMergeable(other.namespace)949 return self.namespace.areRepositoriesMergeable(other.namespace)
950950
951 @property951 @property
952 def pending_writes(self):952 def pending_updates(self):
953 """See `IGitRepository`."""953 """See `IGitRepository`."""
954 from lp.code.model.gitjob import (954 from lp.code.model.gitjob import (
955 GitJob,955 GitJob,
956956
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2017-10-04 01:49:22 +0000
+++ lib/lp/code/model/tests/test_branch.py 2017-11-08 11:16:30 +0000
@@ -130,6 +130,8 @@
130from lp.services.database.constants import UTC_NOW130from lp.services.database.constants import UTC_NOW
131from lp.services.database.interfaces import IStore131from lp.services.database.interfaces import IStore
132from lp.services.features.testing import FeatureFixture132from lp.services.features.testing import FeatureFixture
133from lp.services.job.interfaces.job import JobStatus
134from lp.services.job.runner import JobRunner
133from lp.services.job.tests import (135from lp.services.job.tests import (
134 block_on_job,136 block_on_job,
135 monitor_celery,137 monitor_celery,
@@ -155,6 +157,7 @@
155 TestCaseWithFactory,157 TestCaseWithFactory,
156 WebServiceTestCase,158 WebServiceTestCase,
157 )159 )
160from lp.testing.dbuser import dbuser
158from lp.testing.factory import LaunchpadObjectFactory161from lp.testing.factory import LaunchpadObjectFactory
159from lp.testing.layers import (162from lp.testing.layers import (
160 CeleryBranchWriteJobLayer,163 CeleryBranchWriteJobLayer,
@@ -2364,89 +2367,133 @@
2364 self.assertNamespaceEqual(namespace, branch.namespace)2367 self.assertNamespaceEqual(namespace, branch.namespace)
23652368
23662369
2367class TestPendingWrites(TestCaseWithFactory):2370class TestPendingWritesAndUpdates(TestCaseWithFactory):
2368 """Are there changes to this branch not reflected in the database?"""2371 """Are there changes to this branch not reflected in the database?"""
23692372
2370 layer = LaunchpadFunctionalLayer2373 layer = LaunchpadFunctionalLayer
23712374
2372 def test_new_branch_no_writes(self):2375 def test_new_branch_no_writes(self):
2373 # New branches have no pending writes.2376 # New branches have no pending writes or pending updates.
2374 branch = self.factory.makeAnyBranch()2377 branch = self.factory.makeAnyBranch()
2375 self.assertEqual(False, branch.pending_writes)2378 self.assertFalse(branch.pending_writes)
2379 self.assertFalse(branch.pending_updates)
23762380
2377 def test_branchChanged_for_hosted(self):2381 def test_branchChanged_for_hosted(self):
2378 # If branchChanged has been called with a new tip revision id, there2382 # If branchChanged has been called with a new tip revision id, there
2379 # are pending writes.2383 # are pending writes and pending updates.
2380 branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)2384 branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED)
2381 with person_logged_in(branch.owner):2385 with person_logged_in(branch.owner):
2382 branch.branchChanged('', 'new-tip', None, None, None)2386 branch.branchChanged('', 'new-tip', None, None, None)
2383 self.assertEqual(True, branch.pending_writes)2387 self.assertTrue(branch.pending_writes)
2388 self.assertTrue(branch.pending_updates)
2389
2390 def test_unscanned_without_rescan(self):
2391 # If a branch was unscanned without requesting a rescan, then there
2392 # are pending writes but no pending updates.
2393 self.useBzrBranches(direct_database=True)
2394 branch, bzr_tree = self.create_branch_and_tree()
2395 rev_id = self.factory.getUniqueString(b'rev-id')
2396 bzr_tree.commit('Commit', committer='me@example.com', rev_id=rev_id)
2397 removeSecurityProxy(branch).branchChanged('', rev_id, None, None, None)
2398 transaction.commit()
2399 [job] = getUtility(IBranchScanJobSource).iterReady()
2400 with dbuser('branchscanner'):
2401 JobRunner([job]).runAll()
2402 self.assertFalse(branch.pending_writes)
2403 self.assertFalse(branch.pending_updates)
2404 removeSecurityProxy(branch).unscan(rescan=False)
2405 self.assertTrue(branch.pending_writes)
2406 self.assertFalse(branch.pending_updates)
2407
2408 def test_unscanned_with_rescan(self):
2409 # If a branch was unscanned and a rescan was requested, then there
2410 # are pending writes and pending updates.
2411 self.useBzrBranches(direct_database=True)
2412 branch, bzr_tree = self.create_branch_and_tree()
2413 rev_id = self.factory.getUniqueString(b'rev-id')
2414 bzr_tree.commit('Commit', committer='me@example.com', rev_id=rev_id)
2415 removeSecurityProxy(branch).branchChanged('', rev_id, None, None, None)
2416 transaction.commit()
2417 [job] = getUtility(IBranchScanJobSource).iterReady()
2418 with dbuser('branchscanner'):
2419 JobRunner([job]).runAll()
2420 self.assertFalse(branch.pending_writes)
2421 self.assertFalse(branch.pending_updates)
2422 removeSecurityProxy(branch).unscan(rescan=True)
2423 self.assertTrue(branch.pending_writes)
2424 self.assertTrue(branch.pending_updates)
23842425
2385 def test_requestMirror_for_imported(self):2426 def test_requestMirror_for_imported(self):
2386 # If an imported branch has a requested mirror, then we've just2427 # If an imported branch has a requested mirror, then we've just
2387 # imported new changes. Therefore, pending writes.2428 # imported new changes. Therefore, pending writes and pending
2429 # updates.
2388 branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED)2430 branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED)
2389 branch.requestMirror()2431 branch.requestMirror()
2390 self.assertEqual(True, branch.pending_writes)2432 self.assertTrue(branch.pending_writes)
2433 self.assertTrue(branch.pending_updates)
23912434
2392 def test_requestMirror_for_mirrored(self):2435 def test_requestMirror_for_mirrored(self):
2393 # Mirrored branches *always* have a requested mirror. The fact that a2436 # Mirrored branches *always* have a requested mirror. The fact that
2394 # mirror is requested has no bearing on whether there are pending2437 # a mirror is requested has no bearing on whether there are pending
2395 # writes. Thus, pending_writes is False.2438 # writes or pending updates. Thus, pending_writes and
2439 # pending_updates are both False.
2396 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)2440 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
2397 branch.requestMirror()2441 branch.requestMirror()
2398 self.assertEqual(False, branch.pending_writes)2442 self.assertFalse(branch.pending_writes)
2443 self.assertFalse(branch.pending_updates)
23992444
2400 def test_pulled_but_not_scanned(self):2445 def test_pulled_but_not_scanned(self):
2401 # If a branch has been pulled (mirrored) but not scanned, then we have2446 # If a branch has been pulled (mirrored) but not scanned, then we have
2402 # yet to load the revisions into the database. This means there are2447 # yet to load the revisions into the database. This means there are
2403 # pending writes.2448 # pending writes and pending updates.
2404 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)2449 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
2405 branch.startMirroring()2450 branch.startMirroring()
2406 rev_id = self.factory.getUniqueString('rev-id')2451 rev_id = self.factory.getUniqueString('rev-id')
2407 removeSecurityProxy(branch).branchChanged(2452 removeSecurityProxy(branch).branchChanged(
2408 '', rev_id, None, None, None)2453 '', rev_id, None, None, None)
2409 self.assertEqual(True, branch.pending_writes)2454 self.assertTrue(branch.pending_writes)
2455 self.assertTrue(branch.pending_updates)
24102456
2411 def test_pulled_and_scanned(self):2457 def test_pulled_and_scanned(self):
2412 # If a branch has been pulled and scanned, then there are no pending2458 # If a branch has been pulled and scanned, then there are no pending
2413 # writes.2459 # writes or pending updates.
2414 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)2460 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
2415 branch.startMirroring()2461 branch.startMirroring()
2416 rev_id = self.factory.getUniqueString('rev-id')2462 rev_id = self.factory.getUniqueString('rev-id')
2417 removeSecurityProxy(branch).branchChanged(2463 removeSecurityProxy(branch).branchChanged(
2418 '', rev_id, None, None, None)2464 '', rev_id, None, None, None)
2419 # Cheat! The actual API for marking a branch as scanned is2465 # Cheat! The actual API for marking a branch as scanned is to run
2420 # updateScannedDetails. That requires a revision in the database2466 # the BranchScanJob. That requires a revision in the database
2421 # though.2467 # though.
2422 removeSecurityProxy(branch).last_scanned_id = rev_id2468 removeSecurityProxy(branch).last_scanned_id = rev_id
2423 self.assertEqual(False, branch.pending_writes)2469 [job] = getUtility(IBranchScanJobSource).iterReady()
2470 removeSecurityProxy(job).job._status = JobStatus.COMPLETED
2471 self.assertFalse(branch.pending_writes)
2472 self.assertFalse(branch.pending_updates)
24242473
2425 def test_first_mirror_started(self):2474 def test_first_mirror_started(self):
2426 # If we have started mirroring the branch for the first time, then2475 # If we have started mirroring the branch for the first time, then
2427 # there are probably pending writes.2476 # there are probably pending writes and pending updates.
2428 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)2477 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
2429 branch.startMirroring()2478 branch.startMirroring()
2430 self.assertEqual(True, branch.pending_writes)2479 self.assertTrue(branch.pending_writes)
2480 self.assertTrue(branch.pending_updates)
24312481
2432 def test_following_mirror_started(self):2482 def test_following_mirror_started(self):
2433 # If we have started mirroring the branch, then there are probably2483 # If we have started mirroring the branch, then there are probably
2434 # pending writes.2484 # pending writes and pending updates.
2435 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)2485 branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
2436 branch.startMirroring()2486 branch.startMirroring()
2437 rev_id = self.factory.getUniqueString('rev-id')2487 rev_id = self.factory.getUniqueString('rev-id')
2438 removeSecurityProxy(branch).branchChanged(2488 removeSecurityProxy(branch).branchChanged(
2439 '', rev_id, None, None, None)2489 '', rev_id, None, None, None)
2440 # Cheat! The actual API for marking a branch as scanned is2490 # Cheat! We can only tell if mirroring has started if the last
2441 # updateScannedDetails. That requires a revision in the database
2442 # though.
2443 removeSecurityProxy(branch).last_scanned_id = rev_id
2444 # Cheat again! We can only tell if mirroring has started if the last
2445 # mirrored attempt is different from the last mirrored time. To ensure2491 # mirrored attempt is different from the last mirrored time. To ensure
2446 # this, we start the second mirror in a new transaction.2492 # this, we start the second mirror in a new transaction.
2447 transaction.commit()2493 transaction.commit()
2448 branch.startMirroring()2494 branch.startMirroring()
2449 self.assertEqual(True, branch.pending_writes)2495 self.assertTrue(branch.pending_writes)
2496 self.assertTrue(branch.pending_updates)
24502497
24512498
2452class TestBranchPrivacy(TestCaseWithFactory):2499class TestBranchPrivacy(TestCaseWithFactory):
24532500
=== modified file 'lib/lp/code/model/tests/test_gitrepository.py'
--- lib/lp/code/model/tests/test_gitrepository.py 2017-10-04 01:29:35 +0000
+++ lib/lp/code/model/tests/test_gitrepository.py 2017-11-08 11:16:30 +0000
@@ -960,28 +960,28 @@
960 self.assertEqual(namespace, repository.namespace)960 self.assertEqual(namespace, repository.namespace)
961961
962962
963class TestGitRepositoryPendingWrites(TestCaseWithFactory):963class TestGitRepositoryPendingUpdates(TestCaseWithFactory):
964 """Are there changes to this repository not reflected in the database?"""964 """Are there changes to this repository not reflected in the database?"""
965965
966 layer = LaunchpadFunctionalLayer966 layer = LaunchpadFunctionalLayer
967967
968 def test_new_repository_no_writes(self):968 def test_new_repository_no_updates(self):
969 # New repositories have no pending writes.969 # New repositories have no pending updates.
970 repository = self.factory.makeGitRepository()970 repository = self.factory.makeGitRepository()
971 self.assertFalse(repository.pending_writes)971 self.assertFalse(repository.pending_updates)
972972
973 def test_notify(self):973 def test_notify(self):
974 # If the hosting service has just sent us a change notification,974 # If the hosting service has just sent us a change notification,
975 # then there are pending writes, but running the ref-scanning job975 # then there are pending updates, but running the ref-scanning job
976 # clears that flag.976 # clears that flag.
977 git_api = GitAPI(None, None)977 git_api = GitAPI(None, None)
978 repository = self.factory.makeGitRepository()978 repository = self.factory.makeGitRepository()
979 self.assertIsNone(git_api.notify(repository.getInternalPath()))979 self.assertIsNone(git_api.notify(repository.getInternalPath()))
980 self.assertTrue(repository.pending_writes)980 self.assertTrue(repository.pending_updates)
981 [job] = list(getUtility(IGitRefScanJobSource).iterReady())981 [job] = list(getUtility(IGitRefScanJobSource).iterReady())
982 with dbuser("branchscanner"):982 with dbuser("branchscanner"):
983 JobRunner([job]).runAll()983 JobRunner([job]).runAll()
984 self.assertFalse(repository.pending_writes)984 self.assertFalse(repository.pending_updates)
985985
986986
987class TestGitRepositoryPrivacy(TestCaseWithFactory):987class TestGitRepositoryPrivacy(TestCaseWithFactory):
988988
=== modified file 'lib/lp/code/templates/branch-index.pt'
--- lib/lp/code/templates/branch-index.pt 2016-10-13 12:43:14 +0000
+++ lib/lp/code/templates/branch-index.pt 2017-11-08 11:16:30 +0000
@@ -130,9 +130,9 @@
130130
131 </div>131 </div>
132132
133 <div class="yui-g" tal:condition="view/pending_writes">133 <div class="yui-g" tal:condition="view/pending_updates">
134 <div class="portlet">134 <div class="portlet">
135 <div id="branch-pending-writes" class="pending-update">135 <div id="branch-pending-updates" class="pending-update">
136 <h3>Updating branch...</h3>136 <h3>Updating branch...</h3>
137 <p>137 <p>
138 Launchpad is processing new changes to this branch which will be138 Launchpad is processing new changes to this branch which will be
139139
=== modified file 'lib/lp/code/templates/gitrepository-index.pt'
--- lib/lp/code/templates/gitrepository-index.pt 2016-10-13 12:43:14 +0000
+++ lib/lp/code/templates/gitrepository-index.pt 2017-11-08 11:16:30 +0000
@@ -72,9 +72,9 @@
72 </div>72 </div>
73 </div>73 </div>
7474
75 <div class="yui-g" tal:condition="context/pending_writes">75 <div class="yui-g" tal:condition="context/pending_updates">
76 <div class="portlet">76 <div class="portlet">
77 <div id="repository-pending-writes" class="pending-update">77 <div id="repository-pending-updates" class="pending-update">
78 <h3>Updating repository...</h3>78 <h3>Updating repository...</h3>
79 <p>79 <p>
80 Launchpad is processing new changes to this repository which will80 Launchpad is processing new changes to this repository which will
8181
=== modified file 'lib/lp/codehosting/tests/test_branchdistro.py'
--- lib/lp/codehosting/tests/test_branchdistro.py 2012-02-15 17:29:54 +0000
+++ lib/lp/codehosting/tests/test_branchdistro.py 2017-11-08 11:16:30 +0000
@@ -273,12 +273,12 @@
273 new_branch).getScannerData()273 new_branch).getScannerData()
274 self.assertEqual(old_ancestry, new_ancestry)274 self.assertEqual(old_ancestry, new_ancestry)
275 self.assertEqual(old_history, new_history)275 self.assertEqual(old_history, new_history)
276 self.assertFalse(new_branch.pending_writes)
277 self.assertIs(None, new_branch.stacked_on)276 self.assertIs(None, new_branch.stacked_on)
278 self.assertEqual(new_branch, db_branch.stacked_on)277 self.assertEqual(new_branch, db_branch.stacked_on)
279 # The script doesn't have permission to create branch jobs, but just278 # The script doesn't have permission to create branch jobs, but just
280 # to be insanely paranoid.279 # to be insanely paranoid.
281 switch_dbuser('launchpad')280 switch_dbuser('launchpad')
281 self.assertFalse(new_branch.pending_writes)
282 scan_jobs = list(getUtility(IBranchScanJobSource).iterReady())282 scan_jobs = list(getUtility(IBranchScanJobSource).iterReady())
283 self.assertEqual(existing_scan_job_count, len(scan_jobs))283 self.assertEqual(existing_scan_job_count, len(scan_jobs))
284284