Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(scm): search endpoint abstraction #76627

Merged
merged 5 commits into from
Sep 5, 2024

Conversation

cathteng
Copy link
Member

@cathteng cathteng commented Aug 27, 2024

Search endpoints do two things: search issues and search repositories (optional; not used in VSTS).

The shared logic for all SCMs is the following:

  1. Find the integration (also using a specific provider string for everything except GH/GH Enterprise)
  2. Validate the incoming payload
    1. field (str)
    2. query (str)
  3. Get integration installation, assert the type
  4. If field == “externalIssue”, search for the repo field in request.GET
    1. Search issues for the installation with the query and the repo
    2. Note: there is some variation in this due to the response from the specific integration
  5. If field == the repo field (usually repo, but Gitlab uses project)
    1. Search repos for the installation with the query
    2. Note: there is some variation in this due to the response from the specific integration

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Aug 27, 2024
src/sentry/integrations/gitlab/search.py Fixed Show fixed Hide fixed
try:
response = installation.search_projects(query)
except ApiError as e:
return Response({"detail": str(e)}, status=400)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
Copy link

codecov bot commented Aug 27, 2024

Codecov Report

Attention: Patch coverage is 95.37572% with 8 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/sentry/integrations/vsts/search.py 62.50% 6 Missing ⚠️
...ntry/integrations/source_code_management/search.py 96.66% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #76627       +/-   ##
===========================================
+ Coverage   56.72%   78.20%   +21.47%     
===========================================
  Files        6887     6902       +15     
  Lines      306241   306801      +560     
  Branches    50220    50288       +68     
===========================================
+ Hits       173710   239924    +66214     
+ Misses     127918    60469    -67449     
- Partials     4613     6408     +1795     

try:
response = installation.search_issues(query=full_query, project_id=repo, iids=iids)
except ApiError as e:
return Response({"detail": str(e)}, status=400)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

@abstractmethod
def handle_search_issues(
self, installation: IntegrationInstallation, query: str, repo: str
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would love to be able to type installation as type self.installation_class, but i haven't been able to successfully do so

Copy link
Member

@RyanSkonnord RyanSkonnord Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good thinking. Something roughly like this should work:

I = TypeVar("I", bound=IntegrationInstallation)

class SourceCodeSearchEndpoint(IntegrationEndpoint, Generic[I], ABC):
    @property
    @abstractmethod
    def installation_class(self) -> type[I]: ...

    @abstractmethod
    def handle_search_issues(self, installation: I, query: str, repo: str): ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that did it! thank you

@cathteng cathteng marked this pull request as ready for review August 27, 2024 23:08
@cathteng cathteng requested a review from a team as a code owner August 27, 2024 23:08
return Response({"detail": "query is a required parameter"}, status=400)
@property
def installation_class(self):
return (GitHubIntegration, GitHubEnterpriseIntegration)
Copy link
Member

@RyanSkonnord RyanSkonnord Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would simplify things to remove the tuple return type from the parent class. We could do that if there were a base class that GitHubIntegration and GitHubEnterpriseIntegration shared (and only them). Could you create a small one, just for this purpose? (Maybe "GenericGitHubIntegration", unless you want to rename "GitHubIntegration" and use that as the name for the base class.)

@RyanSkonnord
Copy link
Member

Looks good so far! I think your instincts are correct that parametrizing the IntegrationInstallation type would help and would encourage you to make a pass. Feel free to reach out for help if there's trouble with that. Otherwise I think this looks good to go.

from sentry.shared_integrations.exceptions import ApiError

logger = logging.getLogger("sentry.integrations.bitbucket")

T = TypeVar("T", bound=SourceCodeIssueIntegration)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure if we prefer these to be single letter -- in the code we have many examples of T being used. T appears to be okay, but my IDE complains that I is too vague lol

installation = integration.get_installation(organization.id)
if not isinstance(installation, self.installation_class):
integration_provider = (
self.integration_provider if self.integration_provider else "github"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How could this scenario happen? Seems weird that we'd want to default this to github in the base endpoint class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think i wanted self.integration_provider to be defined to raise the NotFound, but it would be better to error that the abstract property doesn't exist before doing that. thanks!

if self.repository_field and field == self.repository_field:
return self.handle_search_repositories(integration, installation, query)

return Response(status=400)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to respond with some additional info here about field being invalid.

Copy link
Member

@GabeVillalobos GabeVillalobos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!


return Response(status=400)
# TODO: somehow type installation with installation_class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need this comment, or did the generic change cover it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oopsie

@cathteng cathteng enabled auto-merge (squash) September 5, 2024 17:22
@cathteng cathteng merged commit 4634141 into master Sep 5, 2024
49 checks passed
@cathteng cathteng deleted the cathy/scm/search-endpoint-abstraction branch September 5, 2024 18:00
Copy link

sentry-io bot commented Sep 5, 2024

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

  • ‼️ NotImplementedError /extensions/vsts/search/{organization_id_or_slu... View Issue

Did you find this useful? React with a 👍 or 👎

@cathteng cathteng added the Trigger: Revert add to a merged PR to revert it (skips CI) label Sep 5, 2024
@getsentry-bot
Copy link
Contributor

PR reverted: cb5d129

getsentry-bot added a commit that referenced this pull request Sep 5, 2024
This reverts commit 4634141.

Co-authored-by: cathteng <70817427+cathteng@users.noreply.github.com>
c298lee pushed a commit that referenced this pull request Sep 10, 2024
This reverts commit 4634141.

Co-authored-by: cathteng <70817427+cathteng@users.noreply.github.com>
@github-actions github-actions bot locked and limited conversation to collaborators Sep 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components Trigger: Revert add to a merged PR to revert it (skips CI)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants