launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23247
[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