Skip to content

Commit

Permalink
Implement CommitContextMixin
Browse files Browse the repository at this point in the history
  • Loading branch information
jianyuan committed Oct 15, 2023
1 parent b5f170e commit 89aa66a
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 3 deletions.
10 changes: 9 additions & 1 deletion src/sentry/integrations/github_enterprise/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@ class GitHubEnterpriseAppsClient(GitHubClientMixin):
integration_name = "github_enterprise"

def __init__(self, base_url, integration, app_id, private_key, verify_ssl):
self.base_url = f"https://{base_url}/api/v3"
self.base_url = f"https://{base_url}"
self.integration = integration
self.app_id = app_id
self.private_key = private_key
super().__init__(verify_ssl=verify_ssl)

def build_url(self, path: str) -> str:
if path.startswith("/"):
if path == "/graphql":
path = "/api/graphql"
else:
path = "/api/v3/{}".format(path.lstrip("/"))
return super().build_url(path)

def _get_installation_id(self) -> str:
return self.integration.metadata["installation_id"]

Expand Down
57 changes: 55 additions & 2 deletions src/sentry/integrations/github_enterprise/integration.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

from typing import Any
from datetime import timezone
from typing import Any, Mapping, Sequence
from urllib.parse import urlparse

from django import forms
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _
from isodate import parse_datetime
from rest_framework.request import Request

from sentry import http
Expand All @@ -21,6 +23,7 @@
from sentry.integrations.github.issues import GitHubIssueBasic
from sentry.integrations.github.utils import get_jwt
from sentry.integrations.mixins import RepositoryMixin
from sentry.integrations.mixins.commit_context import CommitContextMixin
from sentry.models.integrations.integration import Integration
from sentry.models.repository import Repository
from sentry.pipeline import NestedPipelineView, PipelineView
Expand Down Expand Up @@ -123,7 +126,9 @@
}


class GitHubEnterpriseIntegration(IntegrationInstallation, GitHubIssueBasic, RepositoryMixin):
class GitHubEnterpriseIntegration(
IntegrationInstallation, GitHubIssueBasic, RepositoryMixin, CommitContextMixin
):
repo_search = True
codeowners_locations = ["CODEOWNERS", ".github/CODEOWNERS", "docs/CODEOWNERS"]

Expand Down Expand Up @@ -183,6 +188,54 @@ def format_source_url(self, repo: Repository, filepath: str, branch: str) -> str
# "https://github.example.org/octokit/octokit.rb/blob/master/README.md"
return f"{repo.url}/blob/{branch}/{filepath}"

def get_commit_context(
self, repo: Repository, filepath: str, ref: str, event_frame: Mapping[str, Any]
) -> Mapping[str, str] | None:
lineno = event_frame.get("lineno", 0)
if not lineno:
return None
try:
blame_range: Sequence[Mapping[str, Any]] | None = self.get_blame_for_file(
repo, filepath, ref, lineno
)

if blame_range is None:
return None
except ApiError as e:
raise e

try:
commit: Mapping[str, Any] = max(
(
blame
for blame in blame_range
if blame.get("startingLine", 0) <= lineno <= blame.get("endingLine", 0)
and blame.get("commit", {}).get("committedDate")
),
key=lambda blame: parse_datetime(blame.get("commit", {}).get("committedDate")),
default={},
)
if not commit:
return None
except (ValueError, IndexError):
return None

commitInfo = commit.get("commit")
if not commitInfo:
return None
else:
committed_date = parse_datetime(commitInfo.get("committedDate")).astimezone(
timezone.utc
)

return {
"commitId": commitInfo.get("oid"),
"committedDate": committed_date,
"commitMessage": commitInfo.get("message"),
"commitAuthorName": commitInfo.get("author", {}).get("name"),
"commitAuthorEmail": commitInfo.get("author", {}).get("email"),
}


class InstallationForm(forms.Form):
url = forms.CharField(
Expand Down
107 changes: 107 additions & 0 deletions tests/sentry/integrations/github_enterprise/test_integration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from datetime import datetime, timedelta, timezone
from unittest.mock import patch
from urllib.parse import parse_qs, urlencode, urlparse

import responses
from isodate import parse_datetime

from sentry.integrations.github_enterprise import GitHubEnterpriseIntegrationProvider
from sentry.models.identity import Identity, IdentityProvider, IdentityStatus
Expand Down Expand Up @@ -312,3 +314,108 @@ def test_get_stacktrace_link_use_default_if_version_404(self, get_jwt, _):
result = installation.get_stacktrace_link(repo, path, default, version)

assert result == "https://github.example.org/Test-Organization/foo/blob/master/README.md"

@patch("sentry.integrations.github_enterprise.integration.get_jwt", return_value="jwt_token_1")
@patch("sentry.integrations.github_enterprise.client.get_jwt", return_value="jwt_token_1")
@responses.activate
def test_get_commit_context(self, get_jwt, _):
self.assert_setup_flow()
integration = Integration.objects.get(provider=self.provider.key)
with assume_test_silo_mode(SiloMode.REGION):
repo = Repository.objects.create(
organization_id=self.organization.id,
name="Test-Organization/foo",
url="https://github.example.org/Test-Organization/foo",
provider="integrations:github_enterprise",
external_id=123,
config={"name": "Test-Organization/foo"},
integration_id=integration.id,
)

installation = integration.get_installation(self.organization.id)

filepath = "sentry/tasks.py"
event_frame = {
"function": "handle_set_commits",
"abs_path": "/usr/src/sentry/src/sentry/tasks.py",
"module": "sentry.tasks",
"in_app": True,
"lineno": 30,
"filename": "sentry/tasks.py",
}
ref = "master"
query = f"""query {{
repository(name: "foo", owner: "Test-Organization") {{
ref(qualifiedName: "{ref}") {{
target {{
... on Commit {{
blame(path: "{filepath}") {{
ranges {{
commit {{
oid
author {{
name
email
}}
message
committedDate
}}
startingLine
endingLine
age
}}
}}
}}
}}
}}
}}
}}"""
commit_date = (datetime.now(tz=timezone.utc) - timedelta(days=4)).strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
responses.add(
method=responses.POST,
url="https://github.example.org/api/graphql",
json={
"query": query,
"data": {
"repository": {
"ref": {
"target": {
"blame": {
"ranges": [
{
"commit": {
"oid": "d42409d56517157c48bf3bd97d3f75974dde19fb",
"author": {
"date": commit_date,
"email": "nisanthan.nanthakumar@sentry.io",
"name": "Nisanthan Nanthakumar",
},
"message": "Add installation instructions",
"committedDate": commit_date,
},
"startingLine": 30,
"endingLine": 30,
"age": 3,
}
]
}
}
}
}
},
},
content_type="application/json",
)
commit_context = installation.get_commit_context(repo, filepath, ref, event_frame)

commit_context_expected = {
"commitId": "d42409d56517157c48bf3bd97d3f75974dde19fb",
"committedDate": parse_datetime(commit_date),
"commitMessage": "Add installation instructions",
"commitAuthorName": "Nisanthan Nanthakumar",
"commitAuthorEmail": "nisanthan.nanthakumar@sentry.io",
}

assert commit_context == commit_context_expected

0 comments on commit 89aa66a

Please sign in to comment.