launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26907
[Merge] ~pappacena/launchpad:gitref-and-mp-pages-without-oops-on-failure into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:gitref-and-mp-pages-without-oops-on-failure into launchpad:master.
Commit message:
Avoiding crashes on MP and gitrefs pages when something goes wrong on git code hosting
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1923895 in Launchpad itself: "OOPS on MP pages when Turnip is not fully available"
https://bugs.launchpad.net/launchpad/+bug/1923895
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/401248
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:gitref-and-mp-pages-without-oops-on-failure into launchpad:master.
diff --git a/lib/lp/code/browser/branchmergeproposal.py b/lib/lp/code/browser/branchmergeproposal.py
index 1662539..659a5c9 100644
--- a/lib/lp/code/browser/branchmergeproposal.py
+++ b/lib/lp/code/browser/branchmergeproposal.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Views, navigation and actions for BranchMergeProposals."""
@@ -88,6 +88,7 @@ from lp.code.errors import (
BranchMergeProposalExists,
ClaimReviewFailed,
DiffNotFound,
+ GitRepositoryScanFault,
InvalidBranchMergeProposal,
WrongBranchMergeProposal,
)
@@ -133,6 +134,12 @@ from lp.services.webapp.interfaces import ILaunchBag
from lp.services.webapp.menu import NavigationMenu
+GIT_HOSTING_ERROR_MSG = (
+ "There was an error fetching revisions from git servers. "
+ "Please, try again in some minutes. If the problem persists, "
+ "contact Launchpad support.")
+
+
def latest_proposals_for_each_branch(proposals):
"""Returns the most recent merge proposals for any particular branch.
@@ -359,10 +366,14 @@ class BranchMergeProposalActionNavigationMenu(NavigationMenu,
class UnmergedRevisionsMixin:
"""Provides the methods needed to show unmerged revisions."""
+ # This is set at self.unlanded_revisions, and should be used at view level
+ # as self.commit_infos_message (see git-macros.pt).
+ _unlanded_revisions_message = None
@cachedproperty
def unlanded_revisions(self):
"""Return the unlanded revisions from the source branch."""
+ self._unlanded_revisions_message = ''
with reduced_timeout(1.0, webapp_max=5.0):
try:
return self.context.getUnlandedSourceBranchRevisions()
@@ -374,6 +385,16 @@ class UnmergedRevisionsMixin:
self.context.merge_source.identity,
self.context.merge_target.identity))
return []
+ except GitRepositoryScanFault as e:
+ log.exception("Error scanning git repository: %s" % e)
+ self._unlanded_revisions_message = GIT_HOSTING_ERROR_MSG
+ return []
+
+ @property
+ def commit_infos_message(self):
+ if self._unlanded_revisions_message is None:
+ self.unlanded_revisions
+ return self._unlanded_revisions_message
@property
def pending_updates(self):
@@ -664,6 +685,7 @@ class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin,
merge_proposal = self.context
with reduced_timeout(1.0, webapp_max=5.0):
try:
+ self._conversation_message = ''
groups = list(merge_proposal.getRevisionsSinceReviewStart())
except TimeoutError:
log.exception(
@@ -673,6 +695,10 @@ class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin,
merge_proposal.merge_source.identity,
merge_proposal.merge_target.identity))
groups = []
+ except GitRepositoryScanFault as e:
+ log.exception("Error scanning git repository: %s" % e)
+ self._conversation_message = GIT_HOSTING_ERROR_MSG
+ groups = []
source = merge_proposal.merge_source
if IBranch.providedBy(source):
source = DecoratedBranch(source)
@@ -710,6 +736,12 @@ class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin,
self._populate_previewdiffs(comments)
return CodeReviewConversation(comments)
+ @property
+ def conversation_message(self):
+ if self._conversation_message is None:
+ self.conversation
+ return self._conversation_message
+
def _populate_previewdiffs(self, comments):
"""Lookup and populate caches for 'previewdiff_id'.
diff --git a/lib/lp/code/browser/gitref.py b/lib/lp/code/browser/gitref.py
index ff01a72..89577c9 100644
--- a/lib/lp/code/browser/gitref.py
+++ b/lib/lp/code/browser/gitref.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Git reference views."""
@@ -41,7 +41,10 @@ from lp.code.browser.branchmergeproposal import (
from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
from lp.code.browser.widgets.gitref import GitRefWidget
from lp.code.enums import GitRepositoryType
-from lp.code.errors import InvalidBranchMergeProposal
+from lp.code.errors import (
+ GitRepositoryScanFault,
+ InvalidBranchMergeProposal,
+ )
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
from lp.code.interfaces.gitref import IGitRef
@@ -110,6 +113,10 @@ class GitRefContextMenu(ContextMenu, HasRecipesMenuMixin, HasSnapsMenuMixin):
class GitRefView(LaunchpadView, HasSnapsViewMixin):
+ # This is set at self.commit_infos, and should be accessed by the view
+ # as self.commit_info_message.
+ _commit_info_message = None
+
@property
def label(self):
return self.context.display_name
@@ -219,9 +226,27 @@ class GitRefView(LaunchpadView, HasSnapsViewMixin):
@cachedproperty
def commit_infos(self):
- return self.context.getLatestCommits(
- extended_details=True, user=self.user, handle_timeout=True,
- logger=log)
+ try:
+ self._commit_info_message = ''
+ return self.context.getLatestCommits(
+ extended_details=True, user=self.user, handle_timeout=True,
+ logger=log)
+ except GitRepositoryScanFault as e:
+ log.error("There was an error fetching git commit info: %s" % e)
+ self._commit_info_message = (
+ "There was an error while fetching commit information from "
+ "code hosting service. Please, try again in some minutes. "
+ "If the problem persists, contact Launchpad support.")
+ return []
+ except Exception as e:
+ log.error("There was an error scanning %s: (%s) %s" %
+ (self.context, e.__class__, e))
+ raise
+
+ def commit_infos_message(self):
+ if self._commit_info_message is None:
+ self.commit_infos
+ return self._commit_info_message
@property
def recipes_link(self):
diff --git a/lib/lp/code/browser/tests/test_branchmergeproposal.py b/lib/lp/code/browser/tests/test_branchmergeproposal.py
index 7e9e308..c320022 100644
--- a/lib/lp/code/browser/tests/test_branchmergeproposal.py
+++ b/lib/lp/code/browser/tests/test_branchmergeproposal.py
@@ -2,7 +2,7 @@
# NOTE: The first line above must stay first; do not move the copyright
# notice to the top. See http://www.python.org/dev/peps/pep-0263/.
#
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Unit tests for BranchMergeProposals."""
@@ -75,7 +75,10 @@ from lp.code.enums import (
BranchMergeProposalStatus,
CodeReviewVote,
)
-from lp.code.errors import InvalidBranchMergeProposal
+from lp.code.errors import (
+ GitRepositoryScanFault,
+ InvalidBranchMergeProposal,
+ )
from lp.code.interfaces.branchjob import IBranchScanJobSource
from lp.code.interfaces.branchmergeproposal import (
IBranchMergeProposal,
@@ -154,7 +157,7 @@ class GitHostingClientMixin:
def setUp(self):
super(GitHostingClientMixin, self).setUp()
- self.useFixture(GitHostingFixture())
+ self.git_hosting_fixture = self.useFixture(GitHostingFixture())
class TestBranchMergeProposalContextMenu(TestCaseWithFactory):
@@ -293,6 +296,23 @@ class TestBranchMergeProposalMergedViewGit(
def getBranchRevisionValues(self, branch):
return {'merged_revision_id': branch.commit_sha1}
+ def test_mp_page_with_git_hosting_issues(self):
+ mp = self.makeBranchMergeProposal()
+ self.git_hosting_fixture.getLog.result = None
+ self.git_hosting_fixture.getLog.failure = GitRepositoryScanFault(":-(")
+
+ canonical_url(mp)
+ browser = self.getUserBrowser(canonical_url(mp))
+ error_msg = (
+ "There was an error fetching revisions from git servers. "
+ "Please, try again in some minutes. If the problem persists, "
+ "contact Launchpad support.")
+ self.assertThat(
+ browser.contents, HTMLContains(Tag(
+ 'error msg', "div",
+ text=error_msg,
+ attrs={'class': "pending-update"})))
+
class TestBranchMergeProposalAddVoteView(TestCaseWithFactory):
"""Test the AddVote view."""
@@ -1956,7 +1976,7 @@ class TestBranchMergeProposalBrowserView(BrowserTestCase):
# There is of course the permissions aspect involved here that you can
# do a local merge using only read permissions on the source branch.
team = self.factory.makeTeam()
- source_owner = self.factory.makePerson()
+ self.factory.makePerson()
other_user = self.factory.makePerson()
fooix = self.factory.makeProduct(name="fooix")
repository = self.factory.makeGitRepository(
diff --git a/lib/lp/code/browser/tests/test_gitref.py b/lib/lp/code/browser/tests/test_gitref.py
index d49b343..6c25673 100644
--- a/lib/lp/code/browser/tests/test_gitref.py
+++ b/lib/lp/code/browser/tests/test_gitref.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Unit tests for GitRefView."""
@@ -23,6 +23,7 @@ from testtools.matchers import (
from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy
+from lp.code.errors import GitRepositoryScanFault
from lp.code.interfaces.gitjob import IGitRefScanJobSource
from lp.code.interfaces.gitrepository import IGitRepositorySet
from lp.code.tests.helpers import GitHostingFixture
@@ -40,6 +41,7 @@ from lp.testing import (
TestCaseWithFactory,
)
from lp.testing.dbuser import dbuser
+from lp.testing.fakemethod import FakeMethod
from lp.testing.layers import (
DatabaseFunctionalLayer,
LaunchpadFunctionalLayer,
@@ -149,6 +151,37 @@ class TestGitRefView(BrowserTestCase):
def test_rendering_non_ascii(self):
self._test_rendering("\N{SNOWMAN}")
+ def test_rendering_githost_failure(self):
+ [ref] = self.factory.makeGitRefs(paths=["refs/heads/branch"])
+ log = self.makeCommitLog()
+ self.hosting_fixture.getLog.result = list(reversed(log))
+ self.scanRef(ref, log[-1])
+
+ # Make code hosting fail.
+ self.hosting_fixture.getLog = FakeMethod(
+ failure=GitRepositoryScanFault(":-("))
+ with admin_logged_in():
+ url = canonical_url(ref)
+ # Visiting ref page should not crash, and we should be able to see
+ # the error message telling us that git hosting is having problems.
+ browser = self.getUserBrowser(url, ref.owner)
+
+ recent_commits_tag = soupmatchers.Tag(
+ "recent commits", "div", attrs={"id": "recent-commits"})
+ error_msg = (
+ "There was an error while fetching commit information from code "
+ "hosting service. Please, try again in some minutes. If the "
+ "problem persists, contact Launchpad support.")
+ self.assertThat(
+ browser.contents,
+ soupmatchers.HTMLContains(
+ soupmatchers.Within(
+ recent_commits_tag,
+ soupmatchers.Tag(
+ 'error msg', "div",
+ text=error_msg,
+ attrs={'class': "pending-update"}))))
+
def test_clone_instructions(self):
[ref] = self.factory.makeGitRefs(paths=["refs/heads/branch"])
username = ref.owner.name
diff --git a/lib/lp/code/templates/branchmergeproposal-index.pt b/lib/lp/code/templates/branchmergeproposal-index.pt
index d8eb68f..551ab1c 100644
--- a/lib/lp/code/templates/branchmergeproposal-index.pt
+++ b/lib/lp/code/templates/branchmergeproposal-index.pt
@@ -132,6 +132,9 @@
<div id="conversation"
tal:content="structure view/conversation/@@+render"/>
+ <div tal:condition="view/conversation_message" class="pending-update">
+ <p tal:content="view/conversation_message" />
+ </div>
</div>
<tal:logged-in condition="view/user">
diff --git a/lib/lp/code/templates/git-macros.pt b/lib/lp/code/templates/git-macros.pt
index 0c93657..c080c1a 100644
--- a/lib/lp/code/templates/git-macros.pt
+++ b/lib/lp/code/templates/git-macros.pt
@@ -144,6 +144,9 @@
}
</style>
<dl class="commit">
+ <div tal:condition="view/commit_infos_message" class="pending-update">
+ <p tal:content="view/commit_infos_message" />
+ </div>
<tal:commit repeat="commit_info commit_infos">
<metal:commit-text use-macro="ref/@@+macros/commit-text"/>
</tal:commit>
Follow ups