Browse Source

fix: Add exact search to BitbucketAPI search function (#16530)

* fix: Add exact search to BitbucketAPI search function

* ref: Use OrderedSet to improve readability

* ref: exact_search for loop will iterate <= 1

* test: Bitbucket integration get_repositories

* ref: delete repeated logic
NisanthanNanthakumar 5 years ago
parent
commit
97767fc987

+ 17 - 5
src/sentry/integrations/bitbucket/integration.py

@@ -25,6 +25,8 @@ from .repository import BitbucketRepositoryProvider
 from .client import BitbucketApiClient
 from .issues import BitbucketIssueBasicMixin
 
+from django.utils.datastructures import OrderedSet
+
 DESCRIPTION = """
 Connect your Sentry organization to Bitbucket, enabling the following features:
 """
@@ -96,11 +98,21 @@ class BitbucketIntegration(IntegrationInstallation, BitbucketIssueBasicMixin, Re
                 for repo in resp.get("values", [])
             ]
 
-        full_query = (u'name~"%s"' % (query)).encode("utf-8")
-        resp = self.get_client().search_repositories(self.username, full_query)
-        return [
-            {"identifier": i["full_name"], "name": i["full_name"]} for i in resp.get("values", [])
-        ]
+        exact_query = (u'name="%s"' % (query)).encode("utf-8")
+        fuzzy_query = (u'name~"%s"' % (query)).encode("utf-8")
+
+        exact_search_resp = self.get_client().search_repositories(self.username, exact_query)
+        fuzzy_search_resp = self.get_client().search_repositories(self.username, fuzzy_query)
+
+        result = OrderedSet()
+
+        for j in exact_search_resp.get("values", []):
+            result.add(j["full_name"])
+
+        for i in fuzzy_search_resp.get("values", []):
+            result.add(i["full_name"])
+
+        return [{"identifier": full_name, "name": full_name} for full_name in result]
 
     def has_repo_access(self, repo):
         client = self.get_client()

+ 3 - 5
src/sentry/integrations/bitbucket/search.py

@@ -56,10 +56,8 @@ class BitbucketSearchEndpoint(IntegrationEndpoint):
             )
 
         if field == "repo":
-            full_query = (u'name~"%s"' % (query)).encode("utf-8")
-            resp = installation.get_client().search_repositories(installation.username, full_query)
-            return Response(
-                [{"label": i["full_name"], "value": i["full_name"]} for i in resp.get("values", [])]
-            )
+
+            result = installation.get_repositories(query)
+            return Response([{"label": i["name"], "value": i["name"]} for i in result])
 
         return Response(status=400)

+ 121 - 0
tests/sentry/integrations/bitbucket/test_integration.py

@@ -0,0 +1,121 @@
+from __future__ import absolute_import
+
+import responses
+
+from django.core.urlresolvers import reverse
+
+from sentry.models import Integration
+from sentry.testutils import APITestCase
+
+
+class BitbucketIntegrationTest(APITestCase):
+    def setUp(self):
+        self.base_url = "https://api.bitbucket.org"
+        self.shared_secret = "234567890"
+        self.subject = "connect:1234567"
+        self.integration = Integration.objects.create(
+            provider="bitbucket",
+            external_id=self.subject,
+            name="sentryuser",
+            metadata={
+                "base_url": self.base_url,
+                "shared_secret": self.shared_secret,
+                "subject": self.subject,
+            },
+        )
+        self.login_as(self.user)
+        self.integration.add_organization(self.organization, self.user)
+        self.path = reverse(
+            "sentry-extensions-bitbucket-search", args=[self.organization.slug, self.integration.id]
+        )
+
+    @responses.activate
+    def test_get_repositories_exact_match(self):
+        responses.add(
+            responses.GET,
+            "https://api.bitbucket.org/2.0/repositories/sentryuser?name=stuf",
+            json={"values": [{"full_name": "sentryuser/stuf"}]},
+        )
+
+        responses.add(
+            responses.GET,
+            "https://api.bitbucket.org/2.0/repositories/sentryuser?name~stuf",
+            json={
+                "values": [
+                    {"full_name": "sentryuser/stuff"},
+                    {"full_name": "sentryuser/stuff-2010"},
+                    {"full_name": "sentryuser/stuff-2011"},
+                    {"full_name": "sentryuser/stuff-2012"},
+                    {"full_name": "sentryuser/stuff-2013"},
+                    {"full_name": "sentryuser/stuff-2014"},
+                    {"full_name": "sentryuser/stuff-2015"},
+                    {"full_name": "sentryuser/stuff-2016"},
+                    {"full_name": "sentryuser/stuff-2016"},
+                    {"full_name": "sentryuser/stuff-2017"},
+                    {"full_name": "sentryuser/stuff-2018"},
+                    {"full_name": "sentryuser/stuff-2019"},
+                ]
+            },
+        )
+
+        installation = self.integration.get_installation(self.organization)
+        result = installation.get_repositories("stuf")
+        assert result == [
+            {"identifier": "sentryuser/stuf", "name": "sentryuser/stuf"},
+            {"identifier": "sentryuser/stuff", "name": "sentryuser/stuff"},
+            {"identifier": "sentryuser/stuff-2010", "name": "sentryuser/stuff-2010"},
+            {"identifier": "sentryuser/stuff-2011", "name": "sentryuser/stuff-2011"},
+            {"identifier": "sentryuser/stuff-2012", "name": "sentryuser/stuff-2012"},
+            {"identifier": "sentryuser/stuff-2013", "name": "sentryuser/stuff-2013"},
+            {"identifier": "sentryuser/stuff-2014", "name": "sentryuser/stuff-2014"},
+            {"identifier": "sentryuser/stuff-2015", "name": "sentryuser/stuff-2015"},
+            {"identifier": "sentryuser/stuff-2016", "name": "sentryuser/stuff-2016"},
+            {"identifier": "sentryuser/stuff-2017", "name": "sentryuser/stuff-2017"},
+            {"identifier": "sentryuser/stuff-2018", "name": "sentryuser/stuff-2018"},
+            {"identifier": "sentryuser/stuff-2019", "name": "sentryuser/stuff-2019"},
+        ]
+
+    @responses.activate
+    def test_get_repositories_no_exact_match(self):
+        responses.add(
+            responses.GET,
+            "https://api.bitbucket.org/2.0/repositories/sentryuser?name~stuf",
+            json={
+                "values": [
+                    {"full_name": "sentryuser/stuff"},
+                    {"full_name": "sentryuser/stuff-2010"},
+                    {"full_name": "sentryuser/stuff-2011"},
+                    {"full_name": "sentryuser/stuff-2012"},
+                    {"full_name": "sentryuser/stuff-2013"},
+                    {"full_name": "sentryuser/stuff-2014"},
+                    {"full_name": "sentryuser/stuff-2015"},
+                    {"full_name": "sentryuser/stuff-2016"},
+                    {"full_name": "sentryuser/stuff-2016"},
+                    {"full_name": "sentryuser/stuff-2017"},
+                    {"full_name": "sentryuser/stuff-2018"},
+                    {"full_name": "sentryuser/stuff-2019"},
+                ]
+            },
+        )
+
+        responses.add(
+            responses.GET,
+            "https://api.bitbucket.org/2.0/repositories/sentryuser?name=stuf",
+            json={"values": []},
+        )
+
+        installation = self.integration.get_installation(self.organization)
+        result = installation.get_repositories("stu")
+        assert result == [
+            {"identifier": "sentryuser/stuff", "name": "sentryuser/stuff"},
+            {"identifier": "sentryuser/stuff-2010", "name": "sentryuser/stuff-2010"},
+            {"identifier": "sentryuser/stuff-2011", "name": "sentryuser/stuff-2011"},
+            {"identifier": "sentryuser/stuff-2012", "name": "sentryuser/stuff-2012"},
+            {"identifier": "sentryuser/stuff-2013", "name": "sentryuser/stuff-2013"},
+            {"identifier": "sentryuser/stuff-2014", "name": "sentryuser/stuff-2014"},
+            {"identifier": "sentryuser/stuff-2015", "name": "sentryuser/stuff-2015"},
+            {"identifier": "sentryuser/stuff-2016", "name": "sentryuser/stuff-2016"},
+            {"identifier": "sentryuser/stuff-2017", "name": "sentryuser/stuff-2017"},
+            {"identifier": "sentryuser/stuff-2018", "name": "sentryuser/stuff-2018"},
+            {"identifier": "sentryuser/stuff-2019", "name": "sentryuser/stuff-2019"},
+        ]