Skip to content

Commit

Permalink
fix: Move call to GitHub integration tasks out from trigger_feature_s…
Browse files Browse the repository at this point in the history
…tate_change_webhooks (#3905)
  • Loading branch information
novakzaballa committed May 10, 2024
1 parent e5b4313 commit dec9afa
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 55 deletions.
46 changes: 46 additions & 0 deletions api/features/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import typing
import uuid
from copy import deepcopy
from dataclasses import asdict

from core.models import (
AbstractBaseExportableModel,
Expand All @@ -22,6 +23,7 @@
from django.utils.translation import ugettext_lazy as _
from django_lifecycle import (
AFTER_CREATE,
AFTER_SAVE,
BEFORE_CREATE,
BEFORE_SAVE,
LifecycleModelMixin,
Expand Down Expand Up @@ -72,6 +74,7 @@
STRING,
)
from features.versioning.models import EnvironmentFeatureVersion
from integrations.github.models import GithubConfiguration
from projects.models import Project
from projects.tags.models import Tag

Expand Down Expand Up @@ -989,6 +992,49 @@ def copy_identity_feature_states(
# Save changes to target feature_state
target_feature_state.save()

@hook(AFTER_SAVE)
def create_github_comment(self) -> None:
from integrations.github.github import GithubData, generate_data
from integrations.github.tasks import (
call_github_app_webhook_for_feature_state,
)
from webhooks.webhooks import WebhookEventType

if (
not self.identity_id
and not self.feature_segment
and self.feature.external_resources.exists()
and self.environment.project.github_project.exists()
and self.environment.project.organisation.github_config.exists()
):
github_configuration = GithubConfiguration.objects.get(
organisation_id=self.environment.project.organisation_id
)
feature_states = []
feature_states.append(self)

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),),
)


class FeatureStateValue(
AbstractBaseFeatureValueModel,
Expand Down
37 changes: 0 additions & 37 deletions api/features/tasks.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import logging
from dataclasses import asdict

from environments.models import Webhook
from features.models import Feature, FeatureState
from integrations.github.github import GithubData, generate_data
from integrations.github.tasks import call_github_app_webhook_for_feature_state
from organisations.models import Organisation
from task_processor.decorators import register_task_handler
from webhooks.constants import WEBHOOK_DATETIME_FORMAT
from webhooks.webhooks import (
Expand Down Expand Up @@ -59,39 +55,6 @@ def trigger_feature_state_change_webhooks(
)
)

if (
not instance.identity_id
and not instance.feature_segment
and instance.feature.external_resources.exists()
and instance.environment.project.github_project.exists()
and hasattr(instance.environment.project.organisation, "github_config")
):
github_configuration = (
Organisation.objects.prefetch_related("github_config")
.get(id=instance.environment.project.organisationn_id)
.github_config.first()
)
feature_state = {
"environment_name": new_state["environment"]["name"],
"feature_value": new_state["enabled"],
}
feature_states = []
feature_states.append(instance)

feature_data: GithubData = generate_data(
github_configuration=github_configuration,
feature_id=history_instance.feature.id,
feature_name=history_instance.feature.name,
type=WebhookEventType.FLAG_UPDATED.value,
feature_states=feature_states,
)

feature_data.feature_states.append(feature_state)

call_github_app_webhook_for_feature_state.delay(
args=(asdict(feature_data),),
)


def _get_previous_state(
instance: FeatureState,
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"
6 changes: 5 additions & 1 deletion 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 @@ -55,7 +56,7 @@ def post_comment_to_github(
url, json=payload, headers=headers, timeout=10
)

return response.json() if response.status_code == 200 else None
return response.json() if response.status_code == 201 else None
except requests.RequestException as e:
logger.error(f" {e}")
return None
Expand All @@ -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,)

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(
FeatureExternalResource.objects.filter(
feature_id=github_event_data.feature_id
)
)
data = CallGithubData(
event_type=github_event_data.type,
github_data=github_event_data,
feature_external_resources=feature_external_resources,
)
send_post_request(data)
return

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

0 comments on commit dec9afa

Please sign in to comment.