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

feat(feature flags): add endpoint for copying a flag to multiple projects #18421

Merged
merged 26 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
690833e
fix feature flags filters dropdown width
jurajmajerik Oct 31, 2023
8bbdfd5
add plain UI
jurajmajerik Nov 1, 2023
26b87c6
Update frontend/src/scenes/feature-flags/FeatureFlagProjects.tsx
jurajmajerik Nov 1, 2023
8b4eddc
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 1, 2023
b292f82
move copy form out of the modal
jurajmajerik Nov 2, 2023
71d499e
move copy form out of the modal
jurajmajerik Nov 2, 2023
7f2409d
Merge branch 'fix/feature-flags-filters' of https://github.com/PostHo…
jurajmajerik Nov 2, 2023
bf314d4
add endpoint and tests
jurajmajerik Nov 3, 2023
25cc27f
Merge branch 'master' of https://github.com/PostHog/posthog into fix/…
jurajmajerik Nov 3, 2023
f443386
fix validation error msg
jurajmajerik Nov 3, 2023
3fba00f
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 3, 2023
2af4360
use ViewSet instead of APIView
jurajmajerik Nov 3, 2023
26f35c1
Merge branch 'fix/feature-flags-filters' of https://github.com/PostHo…
jurajmajerik Nov 3, 2023
aaf60a9
change lookup field from pk to feature_flag_key
jurajmajerik Nov 6, 2023
c98781f
add bulk copy endpoint
jurajmajerik Nov 6, 2023
5753263
resolve conflicts
jurajmajerik Nov 6, 2023
fa378bf
address feedback
jurajmajerik Nov 7, 2023
09f7c47
add snapshots
jurajmajerik Nov 7, 2023
567d5ad
Update query snapshots
github-actions[bot] Nov 7, 2023
91db420
Update query snapshots
github-actions[bot] Nov 7, 2023
fa5a029
snapshot
neilkakkar Nov 7, 2023
fe14a41
Update query snapshots
github-actions[bot] Nov 7, 2023
81b5328
adjust test_copy_feature_flag_create_new
jurajmajerik Nov 7, 2023
9b0b415
add test_copy_feature_flag_update_existing
jurajmajerik Nov 7, 2023
b9e0e65
clean up
jurajmajerik Nov 7, 2023
d61a86f
add typing for data in test_copy_feature_flag_missing_fields
jurajmajerik Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 90 additions & 3 deletions posthog/api/organization_feature_flag.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from posthog.api.routing import StructuredViewSetMixin
from posthog.models import FeatureFlag
from posthog.api.feature_flag import FeatureFlagSerializer
from posthog.models import FeatureFlag, Team
from posthog.permissions import OrganizationMemberPermissions
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import action
from rest_framework import (
mixins,
viewsets,
status,
)


Expand All @@ -26,7 +30,90 @@ def retrieve(self, request, *args, **kwargs):

teams = self.organization.teams.all()

flags = FeatureFlag.objects.filter(key=feature_flag_key, team_id__in=[team.id for team in teams])
flags_data = [{"team_id": flag.team_id, "active": flag.active} for flag in flags]
flags = FeatureFlag.objects.filter(
key=feature_flag_key,
team_id__in=[team.id for team in teams],
deleted=False,
)
flags_data = [
{
"flag_id": flag.id,
"team_id": flag.team_id,
"active": flag.active,
}
for flag in flags
]

return Response(flags_data)

@action(detail=False, methods=["post"], url_path="copy_flags")
def copy_flags(self, request, *args, **kwargs):
body = request.data
feature_flag_key = body.get("feature_flag_key")
from_project = body.get("from_project")
target_project_ids = body.get("target_project_ids")

if not feature_flag_key or not from_project or not target_project_ids:
return Response({"error": "Missing required fields"}, status=status.HTTP_400_BAD_REQUEST)

try:
flag_to_copy = FeatureFlag.objects.get(key=feature_flag_key, team_id=from_project)
except FeatureFlag.DoesNotExist:
return Response({"error": "Feature flag to copy does not exist."}, status=status.HTTP_400_BAD_REQUEST)

successful_projects = []
failed_projects = []

for target_project_id in target_project_ids:
# Target project does not exist
try:
Team.objects.get(id=target_project_id)
except ObjectDoesNotExist:
failed_projects.append(
{
"project_id": target_project_id,
"errors": "Target project does not exist.",
}
)
continue

context = {
"request": request,
"team_id": target_project_id,
}
flag_data = {
"key": flag_to_copy.key,
"name": flag_to_copy.name,
"filters": flag_to_copy.filters,
jurajmajerik marked this conversation as resolved.
Show resolved Hide resolved
"active": flag_to_copy.active,
"rollout_percentage": flag_to_copy.rollout_percentage,
"ensure_experience_continuity": flag_to_copy.ensure_experience_continuity,
"deleted": False,
}

existing_flag = FeatureFlag.objects.filter(key=feature_flag_key, team_id=target_project_id).first()
# Update existing flag
if existing_flag:
feature_flag_serializer = FeatureFlagSerializer(
existing_flag, data=flag_data, partial=True, context=context
)
# Create new flag
else:
feature_flag_serializer = FeatureFlagSerializer(data=flag_data, context=context)

try:
feature_flag_serializer.is_valid(raise_exception=True)
feature_flag_serializer.save(team_id=target_project_id)
successful_projects.append(feature_flag_serializer.data)
except Exception as e:
failed_projects.append(
{
"project_id": target_project_id,
"errors": str(e) if not feature_flag_serializer.errors else feature_flag_serializer.errors,
}
)

return Response(
{"success": successful_projects, "failed": failed_projects},
status=status.HTTP_200_OK,
)
Loading
Loading