← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~ilasc/launchpad:revision-status-retrieval-api into launchpad:master

 

Ioana Lasc has proposed merging ~ilasc/launchpad:revision-status-retrieval-api into launchpad:master with ~ilasc/launchpad:revision-status-submission-api as a prerequisite.

Commit message:
Add retrieval API for revision status reports.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~ilasc/launchpad/+git/launchpad/+merge/412513
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilasc/launchpad:revision-status-retrieval-api into launchpad:master.
diff --git a/lib/lp/_schema_circular_imports.py b/lib/lp/_schema_circular_imports.py
index 5ac46de..e512526 100644
--- a/lib/lp/_schema_circular_imports.py
+++ b/lib/lp/_schema_circular_imports.py
@@ -66,7 +66,6 @@ from lp.code.interfaces.diff import IPreviewDiff
 from lp.code.interfaces.gitref import IGitRef
 from lp.code.interfaces.gitrepository import (
     IGitRepository,
-    IRevisionStatusArtifact,
     IRevisionStatusReport,
     )
 from lp.code.interfaces.gitrule import (
@@ -521,6 +520,8 @@ patch_entry_return_type(IGitRepository, 'subscribe', IGitSubscription)
 patch_entry_return_type(IGitRepository, 'getSubscription', IGitSubscription)
 patch_reference_property(IGitRepository, 'code_import', ICodeImport)
 patch_entry_return_type(IGitRepository, 'getRefByPath', IGitRef)
+patch_collection_return_type(
+    IGitRepository, 'getStatusReports', IRevisionStatusReport)
 patch_collection_property(
     IGitRepository, '_api_landing_targets', IBranchMergeProposal)
 patch_collection_property(
diff --git a/lib/lp/code/interfaces/gitrepository.py b/lib/lp/code/interfaces/gitrepository.py
index 074e868..9543dc6 100644
--- a/lib/lp/code/interfaces/gitrepository.py
+++ b/lib/lp/code/interfaces/gitrepository.py
@@ -833,7 +833,7 @@ class RevisionStatusReportsFeatureDisabled(Unauthorized):
 
     def __init__(self):
         super(RevisionStatusReportsFeatureDisabled, self).__init__(
-            "You do not have permission to create revision status reports")
+            "You do not have permission to create/view status reports.")
 
 
 class IRevisionStatusReportView(Interface):
@@ -933,10 +933,13 @@ class IRevisionStatusReportSet(Interface):
         """
 
     def findRevisionStatusReportByID(id):
-        """Returns the RevisionStatusReport for a given ID."""
+        """Returns the `RevisionStatusReport` for a given ID."""
 
     def findRevisionStatusReportByCreator(creator):
-        """Returns the RevisionStatusReport for a creator."""
+        """Returns the `RevisionStatusReport` for a creator."""
+
+    def findRevisionStatusReportsByCommit(commmit_sha1):
+        """Returns the list of `RevisionStatusReport` for a commit."""
 
 
 class IRevisionStatusArtifactSet(Interface):
@@ -1194,6 +1197,18 @@ class IGitRepositoryEdit(IWebhookTarget, IAccessTokenTarget):
         :param result: The result of the new report.
         """
 
+    @operation_parameters(
+        commit_sha1=TextLine(title=_("The commit sha1 of the status report.")))
+    @scoped(AccessTokenScope.REPOSITORY_BUILD_STATUS.title)
+    @operation_returns_collection_of(Interface)
+    @export_read_operation()
+    @operation_for_version("devel")
+    def getStatusReports(commit_sha1):
+        """Retrieves the list of reports that exist for the sha1 commit.
+
+        :param commit_sha1: The commit sha1 for the report.
+        """
+
 
 # XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
 # generation working.  Individual attributes must set their version to
diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
index 3d78862..539bae1 100644
--- a/lib/lp/code/model/gitrepository.py
+++ b/lib/lp/code/model/gitrepository.py
@@ -85,9 +85,9 @@ from lp.app.enums import (
     PUBLIC_INFORMATION_TYPES,
     )
 from lp.app.errors import (
+    NotFoundError,
     SubscriptionPrivacyViolation,
     UserCannotUnsubscribePerson,
-    NotFoundError,
     )
 from lp.app.interfaces.informationtype import IInformationType
 from lp.app.interfaces.launchpad import (
@@ -186,11 +186,6 @@ from lp.registry.model.accesspolicy import (
     )
 from lp.registry.model.person import Person
 from lp.registry.model.teammembership import TeamParticipation
-from lp.services.webapp import (
-    Navigation,
-    stepthrough,
-    )
-
 from lp.services.auth.interfaces import IAccessTokenSet
 from lp.services.auth.model import AccessTokenTargetMixin
 from lp.services.auth.utils import create_access_token_secret
@@ -227,12 +222,17 @@ from lp.services.propertycache import (
     cachedproperty,
     get_property_cache,
     )
+from lp.services.webapp import (
+    Navigation,
+    stepthrough,
+    )
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.interfaces import ILaunchBag
 from lp.services.webhooks.interfaces import IWebhookSet
 from lp.services.webhooks.model import WebhookTargetMixin
 from lp.snappy.interfaces.snap import ISnapSet
 
+
 REVISION_STATUS_REPORT_ALLOW_CREATE = 'revision_status_report.allow_create'
 
 logger = logging.getLogger(__name__)
@@ -381,7 +381,9 @@ class RevisionStatusReportNavigation(Navigation):
             report_id = int(id)
         except ValueError:
             raise NotFoundError(id)
-        report = IStore(RevisionStatusReport).find(RevisionStatusReport, id=report_id).one()
+        report = IStore(
+            RevisionStatusReport).find(
+            RevisionStatusReport, id=report_id).one()
         if report is None:
             raise NotFoundError(id)
         return report
@@ -410,6 +412,12 @@ class RevisionStatusReportSet:
             RevisionStatusReport,
             creator=creator)
 
+    def findRevisionStatusReportsByCommit(self, commit_sha1):
+        """Returns a list of `RevisionStatusReport` for a commit."""
+        return IStore(RevisionStatusReport).find(
+            RevisionStatusReport,
+            commit_sha1=commit_sha1)
+
 
 class RevisionStatusArtifact(StormBase):
     __storm_table__ = 'RevisionStatusArtifact'
@@ -672,6 +680,17 @@ class GitRepository(StormBase, WebhookTargetMixin, AccessTokenTargetMixin,
                                       url, result_summary, result)
         return report
 
+    def getStatusReports(self, commit_sha1):
+
+        if not getFeatureFlag(REVISION_STATUS_REPORT_ALLOW_CREATE):
+            raise RevisionStatusReportsFeatureDisabled()
+
+        reports = getUtility(
+                IRevisionStatusReportSet).findRevisionStatusReportsByCommit(
+                commit_sha1)
+        return reports
+
+
     @property
     def namespace(self):
         """See `IGitRepository`."""
diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
index cb100d5..5368614 100644
--- a/lib/lp/code/model/tests/test_gitrepository.py
+++ b/lib/lp/code/model/tests/test_gitrepository.py
@@ -580,7 +580,6 @@ class TestGitRepository(TestCaseWithFactory):
         repository = removeSecurityProxy(self.factory.makeGitRepository())
         title = self.factory.getUniqueUnicode('report-title')
         commit_sha1 = hashlib.sha1(b"Some content").hexdigest()
-        lfa = self.factory.makeLibraryFileAlias(db_only=True)
         result_summary = "120/120 tests passed"
 
         report = self.factory.makeRevisionStatusReport(
@@ -4288,7 +4287,7 @@ class TestGitRepositoryWebservice(TestCaseWithFactory):
 
         self.assertEqual(401, response.status)
         self.assertIn(
-            b'You do not have permission to create revision status reports',
+            b'You do not have permission to create/view status reports',
             response.body)
 
     def test_newRevisionStatusReport(self):
@@ -4327,6 +4326,52 @@ class TestGitRepositoryWebservice(TestCaseWithFactory):
                     report.id)),
                 response.getHeader("Location"))
 
+    def test_getRevisionStatusReports(self):
+        repository = self.factory.makeGitRepository()
+        requester = repository.owner
+        title = self.factory.getUniqueUnicode('report-title')
+        result_summary = "120/120 tests passed"
+        commit_sha1 = hashlib.sha1(b"First she").hexdigest()
+
+        result_summary2 = "Lint"
+        title2 = "Invalid import in test_file.py"
+
+        report1 = self.factory.makeRevisionStatusReport(
+            user=repository.owner, git_repository=repository,
+            title=title, commit_sha1=commit_sha1,
+            result_summary=result_summary,
+            result=RevisionStatusResult.SUCCEEDED)
+
+        report2 = self.factory.makeRevisionStatusReport(
+            user=repository.owner, git_repository=repository,
+            title=title2, commit_sha1=commit_sha1,
+            result_summary=result_summary2,
+            result=RevisionStatusResult.FAILED)
+
+        webservice = webservice_for_person(None, default_api_version="devel")
+        with person_logged_in(requester):
+            repository_url = api_url(repository)
+
+            secret, _ = self.factory.makeAccessToken(
+                owner=requester, target=repository,
+                scopes=[AccessTokenScope.REPOSITORY_BUILD_STATUS])
+            header = {'Authorization': 'Token %s' % secret}
+
+        self.useFixture(FeatureFixture(
+            {REVISION_STATUS_REPORT_ALLOW_CREATE: "on"}))
+
+        response = webservice.named_get(
+            repository_url, "getStatusReports",
+            headers=header,
+            commit_sha1=commit_sha1)
+        self.assertEqual(200, response.status)
+        with person_logged_in(requester):
+            result = getUtility(
+                IRevisionStatusReportSet).findRevisionStatusReportsByCommit(
+                commit_sha1)
+
+        self.assertEqual(list(result), [report1, report2])
+
     def test_set_target(self):
         # The repository owner can move the repository to another target;
         # this redirects to the new location.