From e3c8f58a47b90bf423f40a3ce0a4fb0abd1b0d97 Mon Sep 17 00:00:00 2001 From: Jaroslav Sevcik Date: Tue, 13 Jul 2021 22:00:18 +0200 Subject: [PATCH] chore(entity): graphql api update --- .../query/snapshots/snap_test_entity_links.py | 76 ++++++ ..._service_links.py => test_entity_links.py} | 35 +-- test/api/query/test_node.py | 2 +- test/api/query/test_service_environments.py | 2 +- test/api/query/test_services.py | 14 +- test/entities/test_objects_to_yaml.py | 7 +- test/entities/test_yaml_to_objects.py | 216 ++++++++++++++++-- zoo/api/query.py | 71 ++++++ zoo/api/schema.py | 3 + zoo/api/types.py | 147 +++++++++++- zoo/entities/builder.py | 18 +- .../migrations/0004_auto_20210713_1003.py | 29 +++ zoo/factories.py | 8 +- 13 files changed, 566 insertions(+), 62 deletions(-) create mode 100644 test/api/query/snapshots/snap_test_entity_links.py rename test/api/query/{test_service_links.py => test_entity_links.py} (81%) create mode 100644 zoo/entities/migrations/0004_auto_20210713_1003.py diff --git a/test/api/query/snapshots/snap_test_entity_links.py b/test/api/query/snapshots/snap_test_entity_links.py new file mode 100644 index 00000000..1a838dca --- /dev/null +++ b/test/api/query/snapshots/snap_test_entity_links.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# snapshottest: v1 - https://goo.gl/zC4yUc +from __future__ import unicode_literals + +from snapshottest import Snapshot + + +snapshots = Snapshot() + +snapshots['test_all 1'] = { + 'data': { + 'allEntities': None + }, + 'errors': [ + { + 'locations': [ + { + 'column': 7, + 'line': 3 + } + ], + 'message': 'Resolved value from the connection field have to be iterable or instance of EntityConnection. Received "None"', + 'path': [ + 'allEntities' + ] + } + ] +} + +snapshots['test_empty 1'] = { + 'errors': [ + { + 'locations': [ + { + 'column': 7, + 'line': 3 + } + ], + 'message': 'Cannot query field "allEntities" on type "Query". Did you mean "allEntities", "allServices", "allLibraries" or "allRepositories"?' + } + ] +} + +snapshots['test_first 1'] = { + 'data': { + 'allEntities': None + }, + 'errors': [ + { + 'locations': [ + { + 'column': 7, + 'line': 3 + } + ], + 'message': 'Resolved value from the connection field have to be iterable or instance of EntityConnection. Received "None"', + 'path': [ + 'allEntities' + ] + } + ] +} + +snapshots['test_last 1'] = { + 'errors': [ + { + 'locations': [ + { + 'column': 13, + 'line': 7 + } + ], + 'message': 'Cannot query field "allEnvironments" on type "Entity".' + } + ] +} diff --git a/test/api/query/test_service_links.py b/test/api/query/test_entity_links.py similarity index 81% rename from test/api/query/test_service_links.py rename to test/api/query/test_entity_links.py index a25c1576..77afd0f6 100644 --- a/test/api/query/test_service_links.py +++ b/test/api/query/test_entity_links.py @@ -4,27 +4,32 @@ @pytest.fixture -def generate_links(service_factory, link_factory): - service = service_factory( +def generate_links(link_factory, component_base_factory): + component = component_base_factory( id=1, - name="martinez", - owner="michaelbennett", - impact="profit", - docs_url="https://docsurl", - pagerduty_service="sales/P019873X9", - slack_channel="https://slackchannel", - status="fixed", + name="base", + type="database", + description="This is my fancy component", + kind="component", + owner="platform", + service=None, + library=None, + source__id=1, + source__remote_id=1, + source__owner="jasckson", + source__name="thiwer", + source__url="https://gitlab.com/thiwer/thiwer", ) link_factory( id=1, - content_object=service, + entity=component, name="Datadog", url="https://datadog.com", icon="datadog", ) link_factory( id=2, - content_object=service, + entity=component, name="Sentry", url="https://sentry.com", icon="sentry", @@ -34,7 +39,7 @@ def generate_links(service_factory, link_factory): def test_empty(snapshot, call_api): query = """ query { - allServices { + allEntities { totalCount edges { node { @@ -58,7 +63,7 @@ def test_empty(snapshot, call_api): def test_all(snapshot, call_api, generate_links): query = """ query { - allServices { + allEntities { totalCount edges { node { @@ -91,7 +96,7 @@ def test_all(snapshot, call_api, generate_links): def test_first(snapshot, call_api, generate_links): query = """ query { - allServices { + allEntities { totalCount edges { node { @@ -124,7 +129,7 @@ def test_first(snapshot, call_api, generate_links): def test_last(snapshot, call_api, generate_links): query = """ query { - allServices { + allEntities { totalCount edges { node { diff --git a/test/api/query/test_node.py b/test/api/query/test_node.py index f89a8319..1885353b 100644 --- a/test/api/query/test_node.py +++ b/test/api/query/test_node.py @@ -9,7 +9,7 @@ def test_service(snapshot, call_api, service_factory): id=10, owner="bradltwat", name="allen-nobles", - status="fixed", + lifecycle="fixed", impact="sales", slack_channel="https://gitlab.slack", pagerduty_service="sales/P019873X9", diff --git a/test/api/query/test_service_environments.py b/test/api/query/test_service_environments.py index 668ef21e..5bc17159 100644 --- a/test/api/query/test_service_environments.py +++ b/test/api/query/test_service_environments.py @@ -16,7 +16,7 @@ def generate_environments(service_factory, environment_factory): docs_url="https://docsurl", pagerduty_service="sales/P019873X9", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", ) environment_factory( id=1, diff --git a/test/api/query/test_services.py b/test/api/query/test_services.py index ab3b9747..4a0ebf79 100644 --- a/test/api/query/test_services.py +++ b/test/api/query/test_services.py @@ -16,7 +16,7 @@ def generate_services(service_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=78, repository__remote_id=239, repository__owner="jasckson", @@ -31,7 +31,7 @@ def generate_services(service_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=48, repository__remote_id=99, repository__owner="colisn", @@ -46,7 +46,7 @@ def generate_services(service_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=234, repository__remote_id=9234, repository__owner="Daniel", @@ -61,7 +61,7 @@ def generate_services(service_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=3434, repository__remote_id=349, repository__owner="josh", @@ -77,7 +77,7 @@ def generate_services(service_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=4543, repository__remote_id=990, repository__owner="imosley", @@ -96,7 +96,7 @@ def generate_services_with_environments(service_factory, environment_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=78, repository__remote_id=239, repository__owner="jasckson", @@ -131,7 +131,7 @@ def generate_services_with_links(service_factory, link_factory): docs_url="https://docsurl", pagerduty_service="/services", slack_channel="https://slackchannel", - status="fixed", + lifecycle="fixed", repository__id=78, repository__remote_id=239, repository__owner="jasckson", diff --git a/test/entities/test_objects_to_yaml.py b/test/entities/test_objects_to_yaml.py index 9c5f0b35..4b4c6505 100644 --- a/test/entities/test_objects_to_yaml.py +++ b/test/entities/test_objects_to_yaml.py @@ -10,8 +10,6 @@ @pytest.fixture def generate_base_component(component_base_factory, link_factory, group_factory): - group = group_factory(id=1, product_owner="john", project_owner="doe") - group.save() component = component_base_factory( id=1, name="base", @@ -26,9 +24,12 @@ def generate_base_component(component_base_factory, link_factory, group_factory) source__owner="jasckson", source__name="thiwer", source__url="https://gitlab.com/thiwer/thiwer", - group=group, ) component.save() + + group = group_factory(id=1, product_owner="john", project_owner="doe", entity=component) + group.save() + link_factory( id=1, name="Datadog", diff --git a/test/entities/test_yaml_to_objects.py b/test/entities/test_yaml_to_objects.py index a461ac7a..2ba654dd 100644 --- a/test/entities/test_yaml_to_objects.py +++ b/test/entities/test_yaml_to_objects.py @@ -8,6 +8,54 @@ pytestmark = pytest.mark.django_db +@pytest.fixture +def create_component_and_service(component_base_factory, repository_factory, link_factory, group_factory, service_factory): + repository = repository_factory( + id=1, + remote_id=11, + name="test_proj1", + owner="john_doe1", + url="https://github.co m/john_doe1/test_proj1", + provider="github", + ) + service = service_factory( + id=1, + name="service", + owner="platform", + impact="profit", + pagerduty_service="sales/P019873X9", + slack_channel="https://slackchannel", + lifecycle="fixed", + description="original description", + ) + + component = component_base_factory( + id=1, + name="original", + type="database", + description="original description", + kind="component", + owner="platform", + tags=["python", "service"], + service=service, + library=None, + source=repository + ) + group = group_factory(id=1, product_owner="john", project_owner="doe", entity=component) + link_factory( + id=1, + name="Datadog", + url="https://dashboard.datadog.com", + icon="poop", + entity=component, + ) + link_factory( + id=2, + name="Sentry", + url="https://sentry.skypicker.com", + entity=component, + ) + def test_create_base_component(mocker, repository_factory): repository = repository_factory( id=1, @@ -52,7 +100,7 @@ def test_create_base_component(mocker, repository_factory): assert component_entity.library is None assert component_entity.type == "database" assert component_entity.links.all().count() == 2 - assert component_entity.group + assert component_entity.groups.all().count() == 1 def test_create_base_component_and_service(mocker, repository_factory): @@ -117,7 +165,7 @@ def test_create_base_component_and_service(mocker, repository_factory): assert component_entity.library is None assert component_entity.type == "service" assert component_entity.links.all().count() == 2 - assert component_entity.group + assert component_entity.groups.all().count() == 1 assert component_entity.service is not None assert component_entity.service.environments.all().count() == 2 @@ -171,12 +219,12 @@ def test_create_base_component_and_library(mocker, repository_factory): assert component_entity.owner == "platform" assert component_entity.type == "library" assert component_entity.links.all().count() == 2 - assert component_entity.group + assert component_entity.groups.all().count() == 1 assert component_entity.service is None assert component_entity.library is not None -def test_create_multiple_components(mocker, repository_factory): +def test_create_multiple_components_one_service(mocker, repository_factory): multiple_components = """ - apiVersion: v1alpha1 kind_: component @@ -248,15 +296,157 @@ def test_create_multiple_components(mocker, repository_factory): "zoo.repos.tasks.get_entity_file_content", return_value=multiple_components ) uut.update_project_from_entity_file(proj=repository_dict) - component_entity = Entity.objects.first() assert Entity.objects.all().count() == 2 assert Service.objects.all().count() == 1 - # assert component_entity.kind == "component" - # assert component_entity.name == "base_lib" - # assert component_entity.owner == "platform" - # assert component_entity.type == "library" - # assert component_entity.links.all().count() == 2 - # assert component_entity.group - # assert component_entity.service is None - # assert component_entity.library is not None +def test_create_multiple_components_multiple_services(mocker, repository_factory): + multiple_components = """ +- apiVersion: v1alpha1 + kind_: component + metadata: + name: base + owner: platform + group: + product_owner: john + project_owner: doe + maintainers: [] + description: This is my fancy component + tags: [] + links: + - name: Datadog + url: https://dashboard.datadog.com + icon: poop + - name: Sentry + url: https://sentry.skypicker.com + spec: + type_: database +--- +- apiVersion: v1alpha1 + kind_: component + metadata: + name: service + owner: platform + group: + product_owner: john + project_owner: doe + maintainers: [] + description: This is my fancy component + tags: [] + links: + - name: Datadog + url: https://service.dashboard.datadog.com + icon: poop + - name: Sentry + url: https://service..skypicker.com + spec: + type_: service + environments: + - name: production + dashboard_url: https://dashboard.datadog.com + health_check_url: https://dashboard.datadog.com + service_urls: + - https://service.prod.com + - name: sandbox + dashboard_url: https://dashboard.datadog.sandbox.com + health_check_url: https://dashboard.datadog.sandbox.com + service_urls: + - https://service.sandbox.com + impact: profit + integrations: + pagerduty_service: pagerduty_service1234 + sentry_project: sentry project 15234 + lifecycle: production +--- +- apiVersion: v1alpha1 + kind_: component + metadata: + name: service the second + owner: platform software + group: + product_owner: john the first + project_owner: doe the second + maintainers: [john, doe] + description: This is my fancy second service + tags: [fancy, service, python] + links: + - name: Datadog + url: https://service-second.dashboard.datadog.com + icon: poop + - name: Sentry + url: https://service.second.skypicker.com + spec: + type_: service + environments: + - name: production + dashboard_url: https://dashboard.second.datadog.com + health_check_url: https://dashboard.second.datadog.com + service_urls: + - https://service.second.prod.com + - name: sandbox + dashboard_url: https://dashboard.datadog.second.sandbox.com + health_check_url: https://dashboard.datadog.second.sandbox.com + service_urls: + - https://service.second.sandbox.com + impact: profit + integrations: + pagerduty_service: pagerduty_service1234_second + sentry_project: sentry project 15234 second + lifecycle: deprecated +""" + + repository = repository_factory( + id=1, + remote_id=11, + name="test_proj1", + owner="john_doe1", + url="https://github.com/john_doe1/test_proj1", + provider="github", + ) + repository_dict = {"id": repository.remote_id, "provider": repository.provider} + mocker.patch( + "zoo.repos.tasks.get_entity_file_content", return_value=multiple_components + ) + uut.update_project_from_entity_file(proj=repository_dict) + assert Entity.objects.all().count() == 3 + assert Service.objects.all().count() == 2 + + +def test_update_service(mocker, create_component_and_service): + + service_component = """ +- apiVersion: v1alpha1 + kind_: component + metadata: + name: service + owner: platform + group: + product_owner: john + project_owner: doe + maintainers: [] + description: This is my fancy component + tags: [] + links: + - name: Datadog + url: https://service.dashboard.datadog.com + icon: poop + - name: Sentry + url: https://service..skypicker.com + spec: + type_: service + environments: + - name: production + dashboard_url: https://dashboard.datadog.com + health_check_url: https://dashboard.datadog.com + service_urls: + - https://service.prod.com + - name: sandbox + dashboard_url: https://dashboard.datadog.sandbox.com + health_check_url: https://dashboard.datadog.sandbox.com + service_urls: + - https://service.sandbox.com + impact: profit + integrations: + pagerduty_service: pagerduty_service1234 + sentry_project: sentry project 15234 + lifecycle: production +""" diff --git a/zoo/api/query.py b/zoo/api/query.py index 32b734f0..fd1a1819 100644 --- a/zoo/api/query.py +++ b/zoo/api/query.py @@ -6,8 +6,10 @@ from ..analytics.models import Dependency, DependencyType, DependencyUsage from ..auditing.models import Issue +from ..entities.models import Link, Entity from ..globalsearch.indexer import IndexType from ..globalsearch.meili_client import meili_client +from ..libraries.models import Library from ..repos.models import Repository from ..services.models import Service from . import types @@ -48,6 +50,18 @@ class Query(graphene.ObjectType): search_query=graphene.String(), search_type=SearchTypeEnum(), ) + all_entities = relay.ConnectionField( + types.EntityConnection, + description="List of entities. Returns first 10 nodes if pagination is not specified.", + ) + all_libraries = relay.ConnectionField( + types.LibraryConnection, + description="List of libraries. Returns first 10 nodes if pagination is not specified.", + ) + all_links = relay.ConnectionField( + types.LinkConnection, + description="List of links. Returns first 10 nodes if pagination is not specified.", + ) def resolve_all_issues(self, info, **kwargs): paginator = Paginator(**kwargs) @@ -156,6 +170,63 @@ def resolve_all_dependency_usages(self, info, **kwargs): page_info=page_info, edges=edges, total_count=total ) + def resolve_all_entites(self, info, **kwargs): + paginator = Paginator(**kwargs) + total = Entity.objects.all().count() + page_info = paginator.get_page_info(total) + edges = [] + + for i, entity in enumerate( + Entity.objects.all()[ + paginator.slice_from : paginator.slice_to # Ignore PEP8Bear + ] + ): + cursor = paginator.get_edge_cursor(i + 1) + node = types.Entity.from_db(entity) + edges.append(types.EntityConnection.Edge(node=node, cursor=cursor)) + + return types.EntityConnection( + page_info=page_info, edges=edges, total_count=total + ) + + def resolve_all_links(self, info, **kwargs): + paginator = Paginator(**kwargs) + total = Link.objects.all().count() + page_info = paginator.get_page_info(total) + edges = [] + + for i, link in enumerate( + Link.objects.all()[ + paginator.slice_from : paginator.slice_to # Ignore PEP8Bear + ] + ): + cursor = paginator.get_edge_cursor(i + 1) + node = types.Link.from_db(link) + edges.append(types.LinkConnection.Edge(node=node, cursor=cursor)) + + return types.LinkConnection( + page_info=page_info, edges=edges, total_count=total + ) + + def resolve_all_libraries(self, info, **kwargs): + paginator = Paginator(**kwargs) + total = Library.objects.all().count() + page_info = paginator.get_page_info(total) + edges = [] + + for i, library in enumerate( + Library.objects.all()[ + paginator.slice_from : paginator.slice_to # Ignore PEP8Bear + ] + ): + cursor = paginator.get_edge_cursor(i + 1) + node = types.Library.from_db(library) + edges.append(types.LibraryConnection.Edge(node=node, cursor=cursor)) + + return types.LibraryConnection( + page_info=page_info, edges=edges, total_count=total + ) + def resolve_all_search_results(self, info, **kwargs): paginator = Paginator(**kwargs) query_param = kwargs.get("search_query", "") diff --git a/zoo/api/schema.py b/zoo/api/schema.py index 34d353e3..74b083cf 100644 --- a/zoo/api/schema.py +++ b/zoo/api/schema.py @@ -20,7 +20,10 @@ class Mutation(ZooMutation, graphene.ObjectType): types.CheckResult, types.Dependency, types.DependencyUsage, + types.Entity, types.Issue, + types.Library, + types.Link, types.Repository, types.Service, ], diff --git a/zoo/api/types.py b/zoo/api/types.py index 4b31e3ab..3b948d56 100644 --- a/zoo/api/types.py +++ b/zoo/api/types.py @@ -6,6 +6,8 @@ from ..analytics import models as analytics_models from ..auditing import check_discovery from ..auditing import models as auditing_models +from ..entities import models as entities_models +from ..libraries import models as libraries_models from ..repos import models as repos_models from ..services import models as services_models from .paginator import Paginator @@ -95,11 +97,63 @@ class Meta: interfaces = (relay.Node,) +class Library(graphene.ObjectType): + owner = graphene.String() + name = graphene.String() + lifecycle = graphene.String() + impact = graphene.String() + slack_channel = graphene.String() + sonarqube_project = graphene.String() + repository = graphene.Field(lambda: Repository) + docs_url = graphene.String() + library_url = graphene.String() + + @classmethod + def from_db(cls, library): + return cls( + owner= library.owner, + name = library.name, + lifecycle = library.lifecycle, + impact = library.impact, + slack_channel = library.slack_channel, + sonarqube_project = library.sonarqube_project, + repository = library.repository_id, + docs_url = library.docs_url, + library_url = library.library_url, + ) + + @classmethod + def get_node(cls, info, library_id): + try: + library = libraries_models.Library.objects.get(id=library_id) + return cls.from_db(library) + except ObjectDoesNotExist: + return None + + def resolve_repository(self, info): + try: + return Repository.from_db( + repos_models.Repository.objects.get(id=self.repository) + ) + except ObjectDoesNotExist: + return None + + class Meta: + interfaces = (relay.Node,) + + +class LibraryConnection(relay.Connection): + total_count = graphene.Int() + + class Meta: + node = Library + + class Link(graphene.ObjectType): name = graphene.String() url = graphene.List(graphene.String) icon = graphene.String() - service = graphene.Field(lambda: Service) + entity = graphene.Field(lambda: Entity) @classmethod def from_db(cls, link): @@ -108,52 +162,125 @@ def from_db(cls, link): name=link.name, url=link.url, icon=link.icon, - service=link.service_id, + entity=link.entity_id, ) @classmethod def get_node(cls, info, link_id): try: - link = services_models.Link.objects.get(id=link_id) + link = entities_models.Link.objects.get(id=link_id) return cls.from_db(link) except ObjectDoesNotExist: return None + def resolve_entity(self, info): + try: + return Entity.from_db(entities_models.Entity.objects.get(id=self.entity)) + except ObjectDoesNotExist: + return None + + class Meta: + interfaces = (relay.Node,) + + +class LinkConnection(relay.Connection): + total_count = graphene.Int() + + class Meta: + node = Link + +class Entity(graphene.ObjectType): + name = graphene.String() + type = graphene.String() + description = graphene.String() + kind = graphene.String() + owner = graphene.String() + source = graphene.Field(lambda: Repository) + service = graphene.Field(lambda: Service) + library = graphene.Field(lambda: Library) + all_links = relay.ConnectionField(LinkConnection) + + @classmethod + def from_db(cls, environment): + return cls( + id=environment.id, + name=environment.name, + service_urls=environment.service_urls, + dashboard_url=environment.dashboard_url, + health_check_url=environment.health_check_url, + service=environment.service_id, + ) + + @classmethod + def get_node(cls, info, environment_id): + try: + environment = services_models.Environment.objects.get(id=environment_id) + return cls.from_db(environment) + except ObjectDoesNotExist: + return None + def resolve_service(self, info): try: return Service.from_db(services_models.Service.objects.get(id=self.service)) except ObjectDoesNotExist: return None + def resolve_library(self, info): + try: + return Library.from_db(libraries_models.Library.objects.get(id=self.library)) + except ObjectDoesNotExist: + return None + + def resolve_all_links(self, info, **kwargs): + paginator = Paginator(**kwargs) + edges = [] + filtered_links = entities_models.Link.objects.filter( + entity_id=self.id + ) + total = filtered_links.count() + page_info = paginator.get_page_info(total) + + for i, issue in enumerate( + filtered_links[ + paginator.slice_from: paginator.slice_to # Ignore PEP8Bear + ] + ): + cursor = paginator.get_edge_cursor(i + 1) + node = Link.from_db(issue) + edges.append(LinkConnection.Edge(node=node, cursor=cursor)) + + return LinkConnection( + page_info=page_info, edges=edges, total_count=total + ) + class Meta: interfaces = (relay.Node,) -class EnvironmentConnection(relay.Connection): +class EntityConnection(relay.Connection): total_count = graphene.Int() class Meta: - node = Environment + node = Entity -class LinkConnection(relay.Connection): +class EnvironmentConnection(relay.Connection): total_count = graphene.Int() class Meta: - node = Link + node = Environment class Service(graphene.ObjectType): owner = graphene.String() name = graphene.String() - status = graphene.String() + lifecycle = graphene.String() impact = graphene.String() repository = graphene.Field(lambda: Repository) slack_channel = graphene.String() pagerduty_service = graphene.String() docs_url = graphene.String() all_environments = relay.ConnectionField(EnvironmentConnection) - all_links = relay.ConnectionField(LinkConnection) @classmethod def from_db(cls, service): @@ -161,7 +288,7 @@ def from_db(cls, service): id=service.id, owner=service.owner, name=service.name, - status=service.status, + lifecycle=service.lifecycle, impact=service.impact, slack_channel=service.slack_channel, pagerduty_service=service.pagerduty_service, diff --git a/zoo/entities/builder.py b/zoo/entities/builder.py index 8f14aaed..6f663208 100644 --- a/zoo/entities/builder.py +++ b/zoo/entities/builder.py @@ -16,25 +16,27 @@ def create_entity(self, data, repository): @staticmethod def _build_base_component(data, repository): - group, _ = Group.objects.update_or_create( - product_owner=data["metadata"]["group"]["product_owner"], - project_owner=data["metadata"]["group"]["project_owner"], - maintainers=data["metadata"]["group"]["maintainers"], - ) - obj, _ = Entity.objects.update_or_create( name=data["metadata"]["name"], kind=data["kind_"], - owner=data["metadata"]["owner"], type=data["spec"]["type_"], source=repository, defaults={ - "group": group, + "owner": data["metadata"]["owner"], "description": data["metadata"]["description"], "tags": data["metadata"]["tags"], }, ) + group, _ = Group.objects.update_or_create( + entity=obj, + defaults={ + "product_owner": data["metadata"]["group"]["product_owner"], + "project_owner": data["metadata"]["group"]["project_owner"], + "maintainers": data["metadata"]["group"]["maintainers"] + } + ) + for link in data["metadata"]["links"]: l, _ = Link.objects.update_or_create( url=link["url"], diff --git a/zoo/entities/migrations/0004_auto_20210713_1003.py b/zoo/entities/migrations/0004_auto_20210713_1003.py new file mode 100644 index 00000000..be6aa4a6 --- /dev/null +++ b/zoo/entities/migrations/0004_auto_20210713_1003.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.19 on 2021-07-13 10:03 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('entities', '0003_auto_20210708_1154'), + ] + + operations = [ + migrations.RemoveField( + model_name='entity', + name='group', + ), + migrations.AddField( + model_name='group', + name='entity', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='groups', related_query_name='group', to='entities.Entity'), + preserve_default=False, + ), + migrations.AlterField( + model_name='link', + name='entity', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='links', related_query_name='link', to='entities.Entity'), + ), + ] diff --git a/zoo/factories.py b/zoo/factories.py index 223eaf21..12688c43 100644 --- a/zoo/factories.py +++ b/zoo/factories.py @@ -167,7 +167,7 @@ class Meta: project_owner = Faker("user_name") -class LibraryFactory(Factory): +class LibraryFactory(DjangoModelFactory): class Meta: model = Library @@ -182,7 +182,7 @@ class Meta: repository = SubFactory(RepositoryFactory) -class ComponentBaseFactory(Factory): +class ComponentBaseFactory(DjangoModelFactory): class Meta: model = Entity @@ -197,7 +197,7 @@ class Meta: group = SubFactory(GroupFactory) -class ComponentServiceFactory(Factory): +class ComponentServiceFactory(DjangoModelFactory): class Meta: model = Entity @@ -212,7 +212,7 @@ class Meta: group = SubFactory(GroupFactory) -class ComponentLibraryFactory(Factory): +class ComponentLibraryFactory(DjangoModelFactory): class Meta: model = Entity