← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~twom/launchpad/manually-rescan-git-link into lp:launchpad

 

Tom Wardill has proposed merging lp:~twom/launchpad/manually-rescan-git-link into lp:launchpad.

Commit message:
Add 'rescan' button if a GitRefScanJob has failed for a gitrepository

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1808320 in Launchpad itself: "Add a "manually rescan" link to MPs"
  https://bugs.launchpad.net/launchpad/+bug/1808320

For more details, see:
https://code.launchpad.net/~twom/launchpad/manually-rescan-git-link/+merge/362341
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~twom/launchpad/manually-rescan-git-link into lp:launchpad.
=== modified file 'lib/lp/buildmaster/tests/test_buildfarmjobbehaviour.py'
--- lib/lp/buildmaster/tests/test_buildfarmjobbehaviour.py	2019-01-11 13:49:13 +0000
+++ lib/lp/buildmaster/tests/test_buildfarmjobbehaviour.py	2019-01-28 17:30:49 +0000
@@ -76,8 +76,13 @@
 
 class FakeDistroArchSeries:
 
+<<<<<<< TREE
     def getChroot(self, pocket=None):
         return FakeLibraryFileAlias('chroot-fooix-bar-y86.tar.gz')
+=======
+    def getChroot(self, pocket=None):
+        return FakeLibraryFileAlias('chroot-fooix-bar-y86.tar.bz2')
+>>>>>>> MERGE-SOURCE
 
 
 class TestBuildFarmJobBehaviourBase(TestCaseWithFactory):

=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml	2019-01-23 13:20:48 +0000
+++ lib/lp/code/browser/configure.zcml	2019-01-28 17:30:49 +0000
@@ -864,7 +864,13 @@
         class="lp.code.browser.gitrepository.GitRepositoryEditView"
         permission="launchpad.Edit"
         name="+edit"
-        template="../templates/gitrepository-edit.pt"/>
+        template="../templates/gitrepository-rescan.pt"/>
+    <browser:page
+        for="lp.code.interfaces.gitrepository.IGitRepository"
+        class="lp.code.browser.gitrepository.GitRepositoryRescanView"
+        permission="launchpad.Edit"
+        name="+rescan"
+        template="../templates/gitrepository-rescan.pt"/>
     <browser:page
         for="lp.code.interfaces.gitrepository.IGitRepository"
         class="lp.code.browser.codeimport.CodeImportEditView"

=== modified file 'lib/lp/code/browser/gitrepository.py'
--- lib/lp/code/browser/gitrepository.py	2019-01-09 18:06:41 +0000
+++ lib/lp/code/browser/gitrepository.py	2019-01-28 17:30:49 +0000
@@ -108,6 +108,7 @@
 from lp.services.database.constants import UTC_NOW
 from lp.services.features import getFeatureFlag
 from lp.services.fields import UniqueField
+from lp.services.job.interfaces.job import JobStatus
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
     canonical_url,
@@ -441,6 +442,29 @@
             self.user, only_active=True)
         return latest_proposals_for_each_branch(targets)
 
+    @property
+    def show_rescan_link(self):
+        """Only show the rescan button if the latest scan has failed"""
+        scan_job = self.context.getLatestScanJob()
+        # If there are no jobs, we failed to create one for some reason,
+        # so we should allow a rescan
+        if not scan_job:
+            return True
+        return scan_job.job.status == JobStatus.FAILED
+
+
+class GitRepositoryRescanView(LaunchpadEditFormView):
+
+    schema = Interface
+
+    field_names = []
+
+    @action('Rescan', name='rescan')
+    def rescan(self, action, data):
+        self.context.rescan()
+        self.request.response.addNotification("Repository scan scheduled")
+        self.next_url = canonical_url(self.context)
+
 
 class GitRepositoryEditFormView(LaunchpadEditFormView):
     """Base class for forms that edit a Git repository."""

=== modified file 'lib/lp/code/browser/tests/test_gitrepository.py'
--- lib/lp/code/browser/tests/test_gitrepository.py	2019-01-10 10:23:56 +0000
+++ lib/lp/code/browser/tests/test_gitrepository.py	2019-01-28 17:30:49 +0000
@@ -50,6 +50,7 @@
     GitRepositoryType,
     )
 from lp.code.interfaces.revision import IRevisionSet
+from lp.code.model.gitjob import GitRefScanJob
 from lp.code.tests.helpers import GitHostingFixture
 from lp.registry.enums import (
     BranchSharingPolicy,
@@ -63,6 +64,7 @@
 from lp.services.beautifulsoup import BeautifulSoup
 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.webapp.publisher import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
@@ -422,6 +424,39 @@
             view.render()
         self.assertThat(recorder, HasQueryCount(Equals(6)))
 
+    def test_show_rescan_link(self):
+        repository = self.factory.makeGitRepository()
+        job = GitRefScanJob.create(repository)
+        job.job._status = JobStatus.FAILED
+        view = create_initialized_view(repository, '+index')
+        result = view.show_rescan_link
+        self.assertTrue(result)
+
+    def test_show_rescan_link_no_failures(self):
+        repository = self.factory.makeGitRepository()
+        job = GitRefScanJob.create(repository)
+        job.job._status = JobStatus.COMPLETED
+        job.job.date_finished = UTC_NOW
+        view = create_initialized_view(repository, '+index')
+        result = view.show_rescan_link
+        self.assertFalse(result)
+
+    def test_show_rescan_link_no_scan_jobs(self):
+        repository = self.factory.makeGitRepository()
+        view = create_initialized_view(repository, '+index')
+        result = view.show_rescan_link
+        self.assertTrue(result)
+
+    def test_show_rescan_link_latest_didnt_fail(self):
+        repository = self.factory.makeGitRepository()
+        job = GitRefScanJob.create(repository)
+        job.job._status = JobStatus.FAILED
+        job = GitRefScanJob.create(repository)
+        job.job._status = JobStatus.COMPLETED
+        view = create_initialized_view(repository, '+index')
+        result = view.show_rescan_link
+        self.assertTrue(result)
+
 
 class TestGitRepositoryViewPrivateArtifacts(BrowserTestCase):
     """Tests that Git repositories with private team artifacts can be viewed.

=== modified file 'lib/lp/code/interfaces/gitrepository.py'
--- lib/lp/code/interfaces/gitrepository.py	2019-01-09 10:50:40 +0000
+++ lib/lp/code/interfaces/gitrepository.py	2019-01-28 17:30:49 +0000
@@ -366,6 +366,9 @@
     def getCodebrowseUrlForRevision(commit):
         """The URL to the commit of the merge to the target branch"""
 
+    def getLatestScanJob():
+        """Return the last IGitRefScanJobSource for this repository"""
+
     def visibleByUser(user):
         """Can the specified user see this repository?"""
 

=== modified file 'lib/lp/code/model/gitrepository.py'
--- lib/lp/code/model/gitrepository.py	2019-01-09 13:07:24 +0000
+++ lib/lp/code/model/gitrepository.py	2019-01-28 17:30:49 +0000
@@ -746,6 +746,17 @@
         """
         return set()
 
+    def getLatestScanJob(self):
+        """See `IGitRepository`."""
+        from lp.code.model.gitjob import GitJob, GitRefScanJob
+        latest_job = IStore(GitJob).find(
+            GitJob,
+            GitJob.repository == self,
+            Job.date_finished != None,
+            GitJob.job_type == GitRefScanJob.class_job_type).order_by(
+                Desc(Job.date_finished)).first()
+        return latest_job
+
     def visibleByUser(self, user):
         """See `IGitRepository`."""
         if self.information_type in PUBLIC_INFORMATION_TYPES:

=== modified file 'lib/lp/code/model/tests/test_gitrepository.py'
--- lib/lp/code/model/tests/test_gitrepository.py	2019-01-09 13:07:24 +0000
+++ lib/lp/code/model/tests/test_gitrepository.py	2019-01-28 17:30:49 +0000
@@ -7,7 +7,10 @@
 
 __metaclass__ = type
 
-from datetime import datetime
+from datetime import (
+    datetime,
+    timedelta,
+    )
 import email
 from functools import partial
 import hashlib
@@ -96,6 +99,7 @@
 from lp.code.model.gitjob import (
     GitJob,
     GitJobType,
+    GitRefScanJob,
     ReclaimGitRepositorySpaceJob,
     )
 from lp.code.model.gitrepository import (
@@ -2193,6 +2197,45 @@
         [job] = list(job_source.iterReady())
         self.assertEqual(repository, job.repository)
 
+    def test_getLatestScanJob(self):
+        complete_date = datetime.now(pytz.UTC)
+
+        repository = self.factory.makeGitRepository()
+        failed_job = GitRefScanJob.create(repository)
+        failed_job.job._status = JobStatus.FAILED
+        failed_job.job.date_finished = complete_date
+        completed_job = GitRefScanJob.create(repository)
+        completed_job.job._status = JobStatus.COMPLETED
+        completed_job.job.date_finished = complete_date - timedelta(seconds=10)
+        result = removeSecurityProxy(repository.getLatestScanJob())
+        self.assertEqual(failed_job.job_id, result.job_id)
+
+    def test_getLatestScanJob_no_scans(self):
+        repository = self.factory.makeGitRepository()
+        result = repository.getLatestScanJob()
+        self.assertIsNone(result)
+
+    def test_getLatestScanJob_correct_branch(self):
+        complete_date = datetime.now(pytz.UTC)
+
+        main_repository = self.factory.makeGitRepository()
+        second_repository = self.factory.makeGitRepository()
+        failed_job = GitRefScanJob.create(second_repository)
+        failed_job.job._status = JobStatus.FAILED
+        failed_job.job.date_finished = complete_date
+        completed_job = GitRefScanJob.create(main_repository)
+        completed_job.job._status = JobStatus.COMPLETED
+        completed_job.job.date_finished = complete_date - timedelta(seconds=10)
+        result = removeSecurityProxy(main_repository.getLatestScanJob())
+        self.assertEqual(completed_job.job_id, result.job_id)
+
+    def test_getLatestScanJob_without_completion_date(self):
+        repository = self.factory.makeGitRepository()
+        failed_job = GitRefScanJob.create(repository)
+        failed_job.job._status = JobStatus.FAILED
+        result = repository.getLatestScanJob()
+        self.assertFalse(result)
+
 
 class TestGitRepositoryUpdateMergeCommitIDs(TestCaseWithFactory):
 

=== modified file 'lib/lp/code/templates/gitrepository-index.pt'
--- lib/lp/code/templates/gitrepository-index.pt	2018-08-31 06:29:29 +0000
+++ lib/lp/code/templates/gitrepository-index.pt	2019-01-28 17:30:49 +0000
@@ -71,7 +71,7 @@
     </div>
   </div>
 
-  <div class="yui-g" tal:condition="context/pending_updates">
+  <div class="yui-g" tal:condition="python: not view.show_rescan_link and context.pending_updates">
     <div class="portlet">
       <div id="repository-pending-updates" class="pending-update">
         <h3>Updating repository...</h3>
@@ -83,6 +83,23 @@
     </div>
   </div>
 
+  <div class="yui-g" tal:condition="view/show_rescan_link">
+    <div class="portlet">
+      <div id="branch-scan-failed" class="pending-update">
+        <h3>Repository scan failed</h3>
+        <p>
+          Scanning this repository for changes 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>
+
   <div class="yui-g">
     <div id="repository-branches" class="portlet"
          tal:define="branches view/branches">

=== added file 'lib/lp/code/templates/gitrepository-rescan.pt'
--- lib/lp/code/templates/gitrepository-rescan.pt	1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/gitrepository-rescan.pt	2019-01-28 17:30:49 +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 repository if it appears the repository is out of date.</p>
+      <div metal:use-macro="context/@@launchpad_form/form" />
+    </div>
+  </body>
+</html>

=== modified file 'lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py'
=== modified file 'lib/lp/soyuz/model/distroarchseries.py'

Follow ups