Skip to content

Commit

Permalink
Add Comment when feature was Deleted, and the test for cover it
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa committed May 9, 2024
1 parent 255dc45 commit c470f19
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 42 deletions.
24 changes: 17 additions & 7 deletions api/features/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,13 +1013,23 @@ def create_github_comment(self) -> None:
feature_states = []
feature_states.append(self)

feature_data: GithubData = generate_data(
github_configuration=github_configuration,
feature_id=self.feature.id,
feature_name=self.feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=feature_states,
)
if self.deleted_at is None:
feature_data: GithubData = generate_data(
github_configuration=github_configuration,
feature_id=self.feature.id,
feature_name=self.feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=feature_states,
)

if self.deleted_at is not None:
feature_data: GithubData = generate_data(
github_configuration=github_configuration,
feature_id=self.feature.id,
feature_name=self.feature.name,
type=WebhookEventType.FLAG_DELETED.value,
feature_states=feature_states,
)

call_github_app_webhook_for_feature_state.delay(
args=(asdict(feature_data),),
Expand Down
7 changes: 4 additions & 3 deletions api/integrations/github/constants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
GITHUB_API_URL = "https://api.github.com/"
GITHUB_API_VERSION = "2022-11-28"

LINK_FEATURE_TEXT = "### This pull request is linked to a Flagsmith Feature (%s):\n"
UNLINKED_FEATURE_TEXT = "### The feature flag %s was unlinked from the issue/PR"
UPDATED_FEATURE_TEXT = "### The Flagsmith Feature %s was updated in the environment "
LINK_FEATURE_TEXT = "### This pull request is linked to a Flagsmith Feature (`%s`):\n"
UNLINKED_FEATURE_TEXT = "### The feature flag `%s` was unlinked from the issue/PR"
UPDATED_FEATURE_TEXT = "### The Flagsmith Feature `%s` was updated in the environment "
LAST_UPDATED_FEATURE_TEXT = "Last Updated %s"
DELETED_FEATURE_TEXT = "### The Feature Flag `%s` was deleted"
4 changes: 4 additions & 0 deletions api/integrations/github/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from features.models import FeatureState, FeatureStateValue
from integrations.github.client import generate_token
from integrations.github.constants import (
DELETED_FEATURE_TEXT,
GITHUB_API_URL,
LAST_UPDATED_FEATURE_TEXT,
LINK_FEATURE_TEXT,
Expand Down Expand Up @@ -71,6 +72,9 @@ def generate_body_comment(
is_removed = event_type == WebhookEventType.FEATURE_EXTERNAL_RESOURCE_REMOVED.value
delete_text = UNLINKED_FEATURE_TEXT % (name,)

if event_type == WebhookEventType.FLAG_DELETED.value:
return DELETED_FEATURE_TEXT % (name,)

Check warning on line 76 in api/integrations/github/github.py

View check run for this annotation

Codecov / codecov/patch

api/integrations/github/github.py#L76

Added line #L76 was not covered by tests

if is_removed:
return delete_text

Expand Down
45 changes: 36 additions & 9 deletions api/integrations/github/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ def send_post_request(data: CallGithubData) -> None:
installation_id = data.github_data.installation_id
body = generate_body_comment(feature_name, event_type, feature_states)

if event_type == WebhookEventType.FLAG_UPDATED.value:
if (
event_type == WebhookEventType.FLAG_UPDATED.value
or event_type == WebhookEventType.FLAG_DELETED.value
):
for resource in data.feature_external_resources:
url = resource.get("url")
pathname = urlparse(url).path
Expand Down Expand Up @@ -61,8 +64,37 @@ def send_post_request(data: CallGithubData) -> None:
@register_task_handler()
def call_github_app_webhook_for_feature_state(event_data: dict[str, Any]) -> None:

from features.feature_external_resources.models import (
FeatureExternalResource,
)

github_event_data = GithubData.from_dict(event_data)

def generate_feature_external_resources(
feature_external_resources: FeatureExternalResource,
) -> list[dict[str, Any]]:
return [
{
"type": resource.type,
"url": resource.url,
}
for resource in feature_external_resources
]

if github_event_data.type == WebhookEventType.FLAG_DELETED.value:
feature_external_resources = generate_feature_external_resources(

Check warning on line 85 in api/integrations/github/tasks.py

View check run for this annotation

Codecov / codecov/patch

api/integrations/github/tasks.py#L85

Added line #L85 was not covered by tests
FeatureExternalResource.objects.filter(
feature_id=github_event_data.feature_id
)
)
data = CallGithubData(

Check warning on line 90 in api/integrations/github/tasks.py

View check run for this annotation

Codecov / codecov/patch

api/integrations/github/tasks.py#L90

Added line #L90 was not covered by tests
event_type=github_event_data.type,
github_data=github_event_data,
feature_external_resources=feature_external_resources,
)
send_post_request(data)
return

Check warning on line 96 in api/integrations/github/tasks.py

View check run for this annotation

Codecov / codecov/patch

api/integrations/github/tasks.py#L95-L96

Added lines #L95 - L96 were not covered by tests

if (
github_event_data.type
== WebhookEventType.FEATURE_EXTERNAL_RESOURCE_REMOVED.value
Expand All @@ -76,14 +108,9 @@ def call_github_app_webhook_for_feature_state(event_data: dict[str, Any]) -> Non
return

feature = Feature.objects.get(id=github_event_data.feature_id)
feature_external_resources = feature.external_resources.all()
feature_external_resources = [
{
"type": resource.type,
"url": resource.url,
}
for resource in feature_external_resources
]
feature_external_resources = generate_feature_external_resources(
feature.external_resources.all()
)
data = CallGithubData(
event_type=github_event_data.type,
github_data=github_event_data,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import datetime
from unittest.mock import ANY

import pytest
import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder
from django.urls import reverse
Expand Down Expand Up @@ -77,7 +77,7 @@ def test_create_feature_external_resource(
github_request_mock.assert_called_with(
"https://api.github.com/repos/repoowner/repo-name/issues/35/comments",
json={
"body": f"### This pull request is linked to a Flagsmith Feature (feature_with_value):\n**Test Environment**\n- [ ] Disabled\nunicode\n```value```\n\nLast Updated {datetime_now.strftime('%dth %b %Y %I:%M%p')}" # noqa E501
"body": f"### This pull request is linked to a Flagsmith Feature (`feature_with_value`):\n**Test Environment**\n- [ ] Disabled\nunicode\n```value```\n\nLast Updated {datetime_now.strftime('%dth %b %Y %I:%M%p')}" # noqa E501
},
headers={
"Accept": "application/vnd.github.v3+json",
Expand Down Expand Up @@ -249,7 +249,7 @@ def test_delete_feature_external_resource(
github_request_mock.assert_called_with(
"https://api.github.com/repos/userexample/example-project-repo/issues/11/comments",
json={
"body": "### The feature flag Test Feature1 was unlinked from the issue/PR"
"body": "### The feature flag `Test Feature1` was unlinked from the issue/PR"
},
headers={
"Accept": "application/vnd.github.v3+json",
Expand Down Expand Up @@ -308,16 +308,23 @@ def test_get_feature_external_resource(
assert response.data["url"] == feature_external_resource.url


def test_create_github_comment_on_feature_state_updated(
@pytest.mark.parametrize(
"event_type",
[
("update"),
("delete"),
],
)
def test_create_github_comment_on_feature_state_updated( # noqa: C901
staff_client: APIClient,
with_environment_permissions: WithEnvironmentPermissionsCallable,
feature_external_resource: FeatureExternalResource,
feature: Feature,
project: Project,
github_configuration: GithubConfiguration,
github_repository: GithubRepository,
mocker,
environment: Environment,
event_type: str,
) -> None:
# Given
with_environment_permissions([UPDATE_FEATURE_STATE])
Expand All @@ -332,6 +339,15 @@ def test_create_github_comment_on_feature_state_updated(
"requests.post", side_effect=mocked_requests_post
)

mock_generate_body_comment = mocker.patch(
"integrations.github.tasks.generate_body_comment",
)

if event_type == "update":
mock_generate_body_comment.return_value = "Flag updated"
elif event_type == "delete":
mock_generate_body_comment.return_value = "Flag deleted"

feature_state_value = feature_state.get_feature_state_value()
feature_env_data = {}
feature_env_data["feature_state_value"] = feature_state_value
Expand Down Expand Up @@ -362,23 +378,51 @@ def test_create_github_comment_on_feature_state_updated(
)

# When
response = staff_client.put(path=url, data=payload, format="json")
if event_type == "update":
response = staff_client.put(path=url, data=payload, format="json")
elif event_type == "delete":
response = staff_client.delete(path=url)

# Then
assert response.status_code == status.HTTP_200_OK
github_request_mock.assert_called_with(
"https://api.github.com/repos/userexample/example-project-repo/issues/11/comments",
json=ANY,
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": "Bearer mocked_token",
},
timeout=10,
)
mock_generate_data.assert_called_with(
github_configuration=github_configuration,
feature_id=feature.id,
feature_name=feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=[feature_state],
)
if event_type == "update":
assert response.status_code == status.HTTP_200_OK
elif event_type == "delete":
assert response.status_code == status.HTTP_204_NO_CONTENT

if event_type == "update":
github_request_mock.assert_called_with(
"https://api.github.com/repos/userexample/example-project-repo/issues/11/comments",
json={"body": "Flag updated"},
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": "Bearer mocked_token",
},
timeout=10,
)
elif event_type == "delete":
github_request_mock.assert_called_with(
"https://api.github.com/repos/userexample/example-project-repo/issues/11/comments",
json={"body": "Flag deleted"},
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": "Bearer mocked_token",
},
timeout=10,
)
if event_type == "update":
mock_generate_data.assert_called_with(

Check warning on line 413 in api/tests/unit/features/test_unit_feature_external_resources_views.py

View check run for this annotation

Codecov / codecov/patch

api/tests/unit/features/test_unit_feature_external_resources_views.py#L413

Added line #L413 was not covered by tests
github_configuration=github_configuration,
feature_id=feature.id,
feature_name=feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=[feature_state],
)

elif event_type == "update":
mock_generate_data.assert_called_with(

Check warning on line 422 in api/tests/unit/features/test_unit_feature_external_resources_views.py

View check run for this annotation

Codecov / codecov/patch

api/tests/unit/features/test_unit_feature_external_resources_views.py#L422

Added line #L422 was not covered by tests
github_configuration=github_configuration,
feature_id=feature.id,
feature_name=feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=[feature_state],
)

0 comments on commit c470f19

Please sign in to comment.