launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23252
[Merge] lp:~twom/launchpad/merge-proposal-rescan-link into lp:launchpad
Tom Wardill has proposed merging lp:~twom/launchpad/merge-proposal-rescan-link into lp:launchpad.
Commit message:
Add rescan button to branch merge proposals.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~twom/launchpad/merge-proposal-rescan-link/+merge/362469
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~twom/launchpad/merge-proposal-rescan-link into lp:launchpad.
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2018-09-06 16:00:45 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2019-01-30 16:16:13 +0000
@@ -57,6 +57,7 @@
SimpleTerm,
SimpleVocabulary,
)
+from zope.security.proxy import removeSecurityProxy
from lp import _
from lp.app.browser.launchpadform import (
@@ -101,6 +102,7 @@
)
from lp.services.config import config
from lp.services.features import getFeatureFlag
+from lp.services.job.interfaces.job import JobStatus
from lp.services.librarian.interfaces.client import LibrarianServerError
from lp.services.propertycache import (
cachedproperty,
@@ -797,6 +799,13 @@
'launchpad.Edit', self.context),
})
+ @property
+ def show_rescan_link(self):
+ latest_preview = self.context.getLatestScanJob()
+ if not latest_preview:
+ return True
+ return latest_preview.job.status == JobStatus.FAILED
+
@delegate_to(ICodeReviewVoteReference)
class DecoratedCodeReviewVoteReference:
@@ -922,6 +931,19 @@
reverse=True)
+class BranchMergeProposalRescanView(LaunchpadEditFormView):
+
+ schema = Interface
+
+ field_names = []
+
+ @action('Rescan', name='rescan')
+ def rescan(self, action, data):
+ self.context.rescan()
+ self.request.response.addNotification("Diff scan scheduled")
+ self.next_url = canonical_url(self.context)
+
+
class IReviewRequest(Interface):
"""Schema for requesting a review."""
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2019-01-28 17:34:01 +0000
+++ lib/lp/code/browser/configure.zcml 2019-01-30 16:16:13 +0000
@@ -259,6 +259,12 @@
permission="launchpad.Edit"
template="../../app/templates/generic-edit.pt"/>
<browser:page
+ name="+rescan"
+ for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
+ class="lp.code.browser.branchmergeproposal.BranchMergeProposalRescanView"
+ permission="launchpad.Edit"
+ template="../templates/branchmergeproposal-rescan.pt"/>
+ <browser:page
name="+linkbug"
for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
class="lp.bugs.browser.buglinktarget.BugLinkView"
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2018-09-27 13:50:06 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2019-01-30 16:16:13 +0000
@@ -74,6 +74,7 @@
IMergeProposalNeedsReviewEmailJobSource,
IMergeProposalUpdatedEmailJobSource,
)
+from lp.code.model.branchmergeproposaljob import UpdatePreviewDiffJob
from lp.code.model.diff import PreviewDiff
from lp.code.tests.helpers import (
add_revision_to_branch,
@@ -89,7 +90,9 @@
PersonVisibility,
TeamMembershipPolicy,
)
+from lp.services.database.constants import UTC_NOW
from lp.services.features.testing import FeatureFixture
+from lp.services.job.interfaces.job import JobStatus
from lp.services.librarian.interfaces.client import LibrarianServerError
from lp.services.messages.model.message import MessageSet
from lp.services.timeout import TimeoutError
@@ -2147,6 +2150,33 @@
browser = self.getViewBrowser(comment.branch_merge_proposal)
self.assertIn('x y' * 100, browser.contents)
+ def test_show_rescan_link(self):
+ bmp = self.factory.makeBranchMergeProposal()
+ job = removeSecurityProxy(bmp.getLatestScanJob())
+ job.job._status = JobStatus.FAILED
+ view = create_initialized_view(bmp, '+index')
+ result = view.show_rescan_link
+ self.assertTrue(result)
+
+ def test_show_rescan_link_no_failures(self):
+ bmp = self.factory.makeBranchMergeProposal()
+ job = removeSecurityProxy(bmp.getLatestScanJob())
+ job.job._status = JobStatus.COMPLETED
+ job.job.date_finished = UTC_NOW
+ view = create_initialized_view(bmp, '+index')
+ result = view.show_rescan_link
+ self.assertFalse(result)
+
+ def test_show_rescan_link_latest_didnt_fail(self):
+ bmp = self.factory.makeBranchMergeProposal()
+ job = removeSecurityProxy(bmp.getLatestScanJob())
+ job.job._status = JobStatus.FAILED
+ job = UpdatePreviewDiffJob.create(bmp)
+ job.job._status = JobStatus.COMPLETED
+ view = create_initialized_view(bmp, '+index')
+ result = view.show_rescan_link
+ self.assertTrue(result)
+
class TestLatestProposalsForEachBranchMixin:
"""Confirm that the latest branch is returned."""
=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
--- lib/lp/code/interfaces/branchmergeproposal.py 2018-10-21 17:32:46 +0000
+++ lib/lp/code/interfaces/branchmergeproposal.py 2019-01-30 16:16:13 +0000
@@ -516,6 +516,11 @@
:param previewdiff_id: The ID of the target `PreviewDiff`.
"""
+ def getLatestScanJob():
+ """Return the latest IGenerateIncrementalDiffJob and
+ IUpdatePreviewDiffJob for this repository.
+ """
+
class IBranchMergeProposalEdit(Interface):
@@ -662,6 +667,14 @@
the current description).
"""
+ @export_write_operation()
+ @operation_for_version("devel")
+ def rescan():
+ """Force a rescan of the diff for this branch merge proposal.
+
+ Thus may be helpful in cases where a previous scan has crashed.
+ """
+
@operation_parameters(
reviewer=Reference(
title=_("A reviewer."), schema=IPerson),
=== modified file 'lib/lp/code/model/branchmergeproposal.py'
--- lib/lp/code/model/branchmergeproposal.py 2018-09-19 12:53:51 +0000
+++ lib/lp/code/model/branchmergeproposal.py 2019-01-30 16:16:13 +0000
@@ -1220,6 +1220,26 @@
if return_jobs:
return jobs
+ def rescan(self):
+ """See `IBranchMergeProposal`."""
+ self.scheduleDiffUpdates()
+
+ def getLatestScanJob(self):
+ """See `IBranchMergeProposal`."""
+ from lp.code.model.branchmergeproposaljob import (
+ BranchMergeProposalJob,
+ UpdatePreviewDiffJob,
+ )
+ diff_type = UpdatePreviewDiffJob.class_job_type
+ latest_preview = IStore(BranchMergeProposalJob).find(
+ BranchMergeProposalJob,
+ BranchMergeProposalJob.branch_merge_proposal == self,
+ BranchMergeProposalJob.job_type == diff_type,
+ ).order_by(Desc(Job.date_finished)).first()
+ if latest_preview is not None:
+ latest_preview = latest_preview.makeDerived()
+ return latest_preview
+
@property
def revision_end_date(self):
"""The cutoff date for showing revisions.
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py 2018-10-21 17:32:46 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2019-01-30 16:16:13 +0000
@@ -2222,6 +2222,41 @@
[job] = self.job_source.iterReady()
self.assertIsInstance(job, UpdatePreviewDiffJob)
+ def test_getLatestScanJob(self):
+ complete_date = datetime.now(UTC)
+
+ bmp = self.factory.makeBranchMergeProposal()
+ failed_job = removeSecurityProxy(bmp.getLatestScanJob())
+ failed_job.job._status = JobStatus.FAILED
+ failed_job.job.date_finished = complete_date
+ completed_job = UpdatePreviewDiffJob.create(bmp)
+ completed_job.job._status = JobStatus.COMPLETED
+ completed_job.job.date_finished = complete_date - timedelta(seconds=10)
+ result = removeSecurityProxy(bmp.getLatestScanJob())
+ self.assertEqual(failed_job.job_id, result.job_id)
+
+ def test_getLatestScanJob_correct_branch(self):
+ complete_date = datetime.now(UTC)
+
+ main_bmp = self.factory.makeBranchMergeProposal()
+ second_bmp = self.factory.makeBranchMergeProposal()
+ failed_job = removeSecurityProxy(second_bmp.getLatestScanJob())
+ failed_job.job._status = JobStatus.FAILED
+ failed_job.job.date_finished = complete_date
+ completed_job = removeSecurityProxy(main_bmp.getLatestScanJob())
+ completed_job.job._status = JobStatus.COMPLETED
+ completed_job.job.date_finished = complete_date - timedelta(seconds=10)
+ result = removeSecurityProxy(main_bmp.getLatestScanJob())
+ self.assertEqual(completed_job.job_id, result.job_id)
+
+ def test_getLatestScanJob_without_completion_date(self):
+ bmp = self.factory.makeBranchMergeProposal()
+ failed_job = removeSecurityProxy(bmp.getLatestScanJob())
+ failed_job.job._status = JobStatus.FAILED
+ result = bmp.getLatestScanJob()
+ self.assertTrue(result)
+ self.assertIsNone(result.job.date_finished)
+
class TestNextPreviewDiffJob(TestCaseWithFactory):
=== modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
--- lib/lp/code/templates/branchmergeproposal-index.pt 2018-04-25 12:01:33 +0000
+++ lib/lp/code/templates/branchmergeproposal-index.pt 2019-01-30 16:16:13 +0000
@@ -182,7 +182,7 @@
</div>
<div id="diff-area">
- <div class="yui-g" tal:condition="view/pending_diff">
+ <div class="yui-g" tal:condition="python: not view.show_rescan_link and view.pending_diff">
<div class="pending-update" id="diff-pending-update">
<h3>Updating diff...</h3>
<p tal:condition="not: features/longpoll.merge_proposals.enabled">
@@ -194,6 +194,20 @@
</p>
</div>
</div>
+ <div class="yui-g" tal:condition="view/show_rescan_link">
+ <div class="pending-update" id="diff-pending-update">
+ <h3>Diff calculation failed</h3>
+ <p>
+ Calculating the branch diff failed. You can manually rescan if required.
+ </p>
+ <p>
+ <form action="+rescan" name="launchpadform" method="post" enctype="multipart/form-data" accept-charset="UTF-8">
+ <input id="field.actions.rescan" class="button" type="submit"
+ name="field.actions.rescan" value="Rescan" />
+ </form>
+ </p>
+ </div>
+ </div>
<div id="review-diff" tal:condition="view/preview_diff">
<h2>Preview Diff </h2>
=== added file 'lib/lp/code/templates/branchmergeproposal-rescan.pt'
--- lib/lp/code/templates/branchmergeproposal-rescan.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/branchmergeproposal-rescan.pt 2019-01-30 16:16:13 +0000
@@ -0,0 +1,14 @@
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ metal:use-macro="view/macro:page/main_only"
+ i18n:domain="launchpad">
+ <body>
+ <div metal:fill-slot="main">
+ <p>You can schedule a rescan for this merge proposal if it appears the diff is out of date.</p>
+ <div metal:use-macro="context/@@launchpad_form/form" />
+ </div>
+ </body>
+</html>
Follow ups