port-ocean 0.18.4__tar.gz → 0.18.5__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. {port_ocean-0.18.4 → port_ocean-0.18.5}/PKG-INFO +1 -1
  2. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/context/event.py +8 -1
  3. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/api.py +4 -1
  4. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/api.py +7 -0
  5. port_ocean-0.18.5/port_ocean/tests/core/handlers/port_app_config/test_api.py +67 -0
  6. port_ocean-0.18.5/port_ocean/tests/core/handlers/port_app_config/test_base.py +197 -0
  7. {port_ocean-0.18.4 → port_ocean-0.18.5}/pyproject.toml +1 -1
  8. {port_ocean-0.18.4 → port_ocean-0.18.5}/LICENSE.md +0 -0
  9. {port_ocean-0.18.4 → port_ocean-0.18.5}/README.md +0 -0
  10. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.Deb +0 -0
  11. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.alpine +0 -0
  12. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.base.builder +0 -0
  13. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.base.runner +0 -0
  14. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.dockerignore +0 -0
  15. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/Makefile +0 -0
  16. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/grpcio.sh +0 -0
  17. {port_ocean-0.18.4 → port_ocean-0.18.5}/integrations/_infra/init.sh +0 -0
  18. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/__init__.py +0 -0
  19. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/bootstrap.py +0 -0
  20. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/__init__.py +0 -0
  21. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cli.py +0 -0
  22. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/__init__.py +0 -0
  23. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  24. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/clean.py +0 -0
  25. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/dock.py +0 -0
  26. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/group.py +0 -0
  27. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/list_integrations.py +0 -0
  28. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/main.py +0 -0
  29. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/new.py +0 -0
  30. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/pull.py +0 -0
  31. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/sail.py +0 -0
  32. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/commands/version.py +0 -0
  33. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  34. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  35. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  36. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  37. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  38. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  39. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  40. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  41. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  42. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  43. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  44. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  45. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  46. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  47. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  48. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  49. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  50. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  51. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  52. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  53. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  54. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/cli/utils.py +0 -0
  55. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/__init__.py +0 -0
  56. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/__init__.py +0 -0
  57. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/authentication.py +0 -0
  58. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/client.py +0 -0
  59. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/__init__.py +0 -0
  60. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  61. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/entities.py +0 -0
  62. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/integrations.py +0 -0
  63. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/migrations.py +0 -0
  64. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/organization.py +0 -0
  65. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/retry_transport.py +0 -0
  66. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/types.py +0 -0
  67. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/clients/port/utils.py +0 -0
  68. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/config/__init__.py +0 -0
  69. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/config/base.py +0 -0
  70. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/config/dynamic.py +0 -0
  71. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/config/settings.py +0 -0
  72. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/consumers/__init__.py +0 -0
  73. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/consumers/kafka_consumer.py +0 -0
  74. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/context/__init__.py +0 -0
  75. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/context/ocean.py +0 -0
  76. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/context/resource.py +0 -0
  77. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/__init__.py +0 -0
  78. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/defaults/__init__.py +0 -0
  79. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/defaults/clean.py +0 -0
  80. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/defaults/common.py +0 -0
  81. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/defaults/initialize.py +0 -0
  82. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/__init__.py +0 -0
  83. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/base.py +0 -0
  84. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/factory.py +0 -0
  85. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/http.py +0 -0
  86. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/kafka.py +0 -0
  87. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/once.py +0 -0
  88. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/polling.py +0 -0
  89. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  90. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/__init__.py +0 -0
  91. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/base.py +0 -0
  92. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  93. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  94. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  95. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  96. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  97. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  98. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  99. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  100. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  101. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  102. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  103. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  104. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  105. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  106. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/__init__.py +0 -0
  107. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/base.py +0 -0
  108. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  109. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/events.py +0 -0
  110. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/handler.py +0 -0
  111. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/sync.py +0 -0
  112. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
  113. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/utils.py +0 -0
  114. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/models.py +0 -0
  115. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/ocean_types.py +0 -0
  116. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  117. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/core/utils/utils.py +0 -0
  118. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/debug_cli.py +0 -0
  119. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/__init__.py +0 -0
  120. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/base.py +0 -0
  121. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/clients.py +0 -0
  122. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/context.py +0 -0
  123. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/core.py +0 -0
  124. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/port_defaults.py +0 -0
  125. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/exceptions/utils.py +0 -0
  126. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/helpers/__init__.py +0 -0
  127. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/helpers/async_client.py +0 -0
  128. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/helpers/retry.py +0 -0
  129. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/log/__init__.py +0 -0
  130. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/log/handlers.py +0 -0
  131. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/log/logger_setup.py +0 -0
  132. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/log/sensetive.py +0 -0
  133. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/middlewares.py +0 -0
  134. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/ocean.py +0 -0
  135. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/py.typed +0 -0
  136. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/run.py +0 -0
  137. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/sonar-project.properties +0 -0
  138. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/__init__.py +0 -0
  139. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  140. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
  141. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/conftest.py +0 -0
  142. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/defaults/test_common.py +0 -0
  143. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  144. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
  145. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/test_utils.py +0 -0
  146. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  147. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  148. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/__init__.py +0 -0
  149. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  150. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/fixtures.py +0 -0
  151. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/integration.py +0 -0
  152. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/ocean_app.py +0 -0
  153. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/port_client.py +0 -0
  154. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/helpers/smoke_test.py +0 -0
  155. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/log/test_handlers.py +0 -0
  156. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/test_smoke.py +0 -0
  157. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  158. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/tests/utils/test_cache.py +0 -0
  159. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/__init__.py +0 -0
  160. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/async_http.py +0 -0
  161. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/async_iterators.py +0 -0
  162. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/cache.py +0 -0
  163. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/misc.py +0 -0
  164. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/queue_utils.py +0 -0
  165. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/repeat.py +0 -0
  166. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/signal.py +0 -0
  167. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/utils/time.py +0 -0
  168. {port_ocean-0.18.4 → port_ocean-0.18.5}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.18.4
3
+ Version: 0.18.5
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -19,6 +19,7 @@ from pydispatch import dispatcher # type: ignore
19
19
  from werkzeug.local import LocalStack, LocalProxy
20
20
 
21
21
  from port_ocean.context.resource import resource
22
+ from port_ocean.exceptions.api import EmptyPortAppConfigError
22
23
  from port_ocean.exceptions.context import (
23
24
  EventContextNotFoundError,
24
25
  ResourceContextNotFoundError,
@@ -176,8 +177,14 @@ async def event_context(
176
177
  logger.info("Event started")
177
178
  try:
178
179
  yield event
179
- except:
180
+ except EmptyPortAppConfigError as e:
181
+ logger.error(
182
+ f"Skipping resync due to empty mapping: {str(e)}", exc_info=True
183
+ )
184
+ raise
185
+ except Exception as e:
180
186
  success = False
187
+ logger.error(f"Event failed with error: {str(e)}", exc_info=True)
181
188
  raise
182
189
  else:
183
190
  success = True
@@ -3,6 +3,7 @@ from typing import Any
3
3
  from loguru import logger
4
4
 
5
5
  from port_ocean.core.handlers.port_app_config.base import BasePortAppConfig
6
+ from port_ocean.exceptions.api import EmptyPortAppConfigError
6
7
 
7
8
 
8
9
  class APIPortAppConfig(BasePortAppConfig):
@@ -20,7 +21,9 @@ class APIPortAppConfig(BasePortAppConfig):
20
21
  if not config:
21
22
  logger.error(
22
23
  "The integration port app config is empty. "
24
+ f"Integration: {integration}, "
25
+ f"Config: {config}. "
23
26
  "Please make sure to configure your port app config using Port's API."
24
27
  )
25
-
28
+ raise EmptyPortAppConfigError()
26
29
  return config
@@ -13,3 +13,10 @@ class BaseAPIException(BaseOceanException, abc.ABC):
13
13
  class InternalServerException(BaseAPIException):
14
14
  def response(self) -> Response:
15
15
  return PlainTextResponse(content="Internal server error", status_code=500)
16
+
17
+
18
+ class EmptyPortAppConfigError(Exception):
19
+ """Exception raised when the Port app configuration is empty."""
20
+
21
+ def __init__(self, message: str = "Port app config is empty") -> None:
22
+ super().__init__(message)
@@ -0,0 +1,67 @@
1
+ import pytest
2
+ from unittest.mock import AsyncMock
3
+
4
+ from port_ocean.core.handlers.port_app_config.api import APIPortAppConfig
5
+ from port_ocean.exceptions.api import EmptyPortAppConfigError
6
+
7
+
8
+ @pytest.fixture
9
+ def mock_context() -> AsyncMock:
10
+ context = AsyncMock()
11
+ context.port_client.get_current_integration = AsyncMock()
12
+ return context
13
+
14
+
15
+ @pytest.fixture
16
+ def api_config(mock_context: AsyncMock) -> APIPortAppConfig:
17
+ return APIPortAppConfig(mock_context)
18
+
19
+
20
+ async def test_get_port_app_config_valid_config_returns_config(
21
+ api_config: APIPortAppConfig, mock_context: AsyncMock
22
+ ) -> None:
23
+ # Arrange
24
+ expected_config = {"key": "value"}
25
+ mock_context.port_client.get_current_integration.return_value = {
26
+ "config": expected_config
27
+ }
28
+
29
+ # Act
30
+ result = await api_config._get_port_app_config()
31
+
32
+ # Assert
33
+ assert result == expected_config
34
+ mock_context.port_client.get_current_integration.assert_called_once()
35
+
36
+
37
+ async def test_get_port_app_config_empty_config_raises_value_error(
38
+ api_config: APIPortAppConfig, mock_context: AsyncMock
39
+ ) -> None:
40
+ # Arrange
41
+ mock_context.port_client.get_current_integration.return_value = {"config": {}}
42
+
43
+ # Act & Assert
44
+ with pytest.raises(EmptyPortAppConfigError, match="Port app config is empty"):
45
+ await api_config._get_port_app_config()
46
+
47
+
48
+ async def test_get_port_app_config_missing_config_key_raises_key_error(
49
+ api_config: APIPortAppConfig, mock_context: AsyncMock
50
+ ) -> None:
51
+ # Arrange
52
+ mock_context.port_client.get_current_integration.return_value = {}
53
+
54
+ # Act & Assert
55
+ with pytest.raises(KeyError):
56
+ await api_config._get_port_app_config()
57
+
58
+
59
+ async def test_get_port_app_config_empty_integration_raises_key_error(
60
+ api_config: APIPortAppConfig, mock_context: AsyncMock
61
+ ) -> None:
62
+ # Arrange
63
+ mock_context.port_client.get_current_integration.return_value = {}
64
+
65
+ # Act & Assert
66
+ with pytest.raises(KeyError):
67
+ await api_config._get_port_app_config()
@@ -0,0 +1,197 @@
1
+ import pytest
2
+ from unittest.mock import MagicMock
3
+ from pydantic import ValidationError
4
+ from typing import Any, Dict
5
+
6
+ from port_ocean.context.ocean import PortOceanContext
7
+ from port_ocean.core.handlers.port_app_config.base import BasePortAppConfig
8
+ from port_ocean.core.handlers.port_app_config.models import PortAppConfig
9
+ from port_ocean.context.event import EventType, event_context
10
+ from port_ocean.exceptions.api import EmptyPortAppConfigError
11
+
12
+
13
+ class TestPortAppConfig(BasePortAppConfig):
14
+ mock_get_port_app_config: Any
15
+
16
+ async def _get_port_app_config(self) -> Dict[str, Any]:
17
+ return self.mock_get_port_app_config()
18
+
19
+
20
+ @pytest.fixture
21
+ def mock_context() -> PortOceanContext:
22
+ context = MagicMock(spec=PortOceanContext)
23
+ context.config.port.port_app_config_cache_ttl = 300 # 5 minutes
24
+ return context
25
+
26
+
27
+ @pytest.fixture
28
+ def port_app_config_handler(mock_context: PortOceanContext) -> TestPortAppConfig:
29
+ handler = TestPortAppConfig(mock_context)
30
+ handler.mock_get_port_app_config = MagicMock()
31
+ return handler
32
+
33
+
34
+ @pytest.mark.asyncio
35
+ async def test_get_port_app_config_success(
36
+ port_app_config_handler: TestPortAppConfig,
37
+ ) -> None:
38
+ # Arrange
39
+ valid_config = {
40
+ "resources": [
41
+ {
42
+ "kind": "repository",
43
+ "selector": {"query": "true"},
44
+ "port": {
45
+ "entity": {
46
+ "mappings": {
47
+ "identifier": ".name",
48
+ "title": ".name",
49
+ "blueprint": '"service"',
50
+ "properties": {
51
+ "description": ".description",
52
+ "url": ".html_url",
53
+ "defaultBranch": ".default_branch",
54
+ },
55
+ }
56
+ }
57
+ },
58
+ }
59
+ ]
60
+ }
61
+ port_app_config_handler.mock_get_port_app_config.return_value = valid_config
62
+
63
+ # Act
64
+ async with event_context(EventType.RESYNC, trigger_type="machine"):
65
+ result = await port_app_config_handler.get_port_app_config()
66
+
67
+ # Assert
68
+ assert isinstance(result, PortAppConfig)
69
+ assert result.resources[0].port.entity.mappings.title == ".name"
70
+ assert result.resources[0].port.entity.mappings.identifier == ".name"
71
+ assert result.resources[0].port.entity.mappings.blueprint == '"service"'
72
+ assert (
73
+ result.resources[0].port.entity.mappings.properties["description"]
74
+ == ".description"
75
+ )
76
+ assert result.resources[0].port.entity.mappings.properties["url"] == ".html_url"
77
+ assert (
78
+ result.resources[0].port.entity.mappings.properties["defaultBranch"]
79
+ == ".default_branch"
80
+ )
81
+ port_app_config_handler.mock_get_port_app_config.assert_called_once()
82
+
83
+
84
+ @pytest.mark.asyncio
85
+ async def test_get_port_app_config_uses_cache(
86
+ port_app_config_handler: TestPortAppConfig,
87
+ ) -> None:
88
+ # Arrange
89
+ valid_config = {
90
+ "resources": [
91
+ {
92
+ "kind": "repository",
93
+ "selector": {"query": "true"},
94
+ "port": {
95
+ "entity": {
96
+ "mappings": {
97
+ "identifier": ".name",
98
+ "title": ".name",
99
+ "blueprint": '"service"',
100
+ "properties": {
101
+ "description": ".description",
102
+ "url": ".html_url",
103
+ "defaultBranch": ".default_branch",
104
+ },
105
+ }
106
+ }
107
+ },
108
+ }
109
+ ]
110
+ }
111
+ port_app_config_handler.mock_get_port_app_config.return_value = valid_config
112
+
113
+ # Act
114
+ async with event_context(EventType.RESYNC, trigger_type="machine"):
115
+ result1 = await port_app_config_handler.get_port_app_config()
116
+ result2 = await port_app_config_handler.get_port_app_config()
117
+
118
+ # Assert
119
+ assert result1 == result2
120
+ port_app_config_handler.mock_get_port_app_config.assert_called_once() # Called only once due to caching
121
+
122
+
123
+ @pytest.mark.asyncio
124
+ async def test_get_port_app_config_bypass_cache(
125
+ port_app_config_handler: TestPortAppConfig,
126
+ ) -> None:
127
+ # Arrange
128
+ valid_config = {
129
+ "resources": [
130
+ {
131
+ "kind": "repository",
132
+ "selector": {"query": "true"},
133
+ "port": {
134
+ "entity": {
135
+ "mappings": {
136
+ "identifier": ".name",
137
+ "title": ".name",
138
+ "blueprint": '"service"',
139
+ "properties": {
140
+ "description": ".description",
141
+ "url": ".html_url",
142
+ "defaultBranch": ".default_branch",
143
+ },
144
+ }
145
+ }
146
+ },
147
+ }
148
+ ]
149
+ }
150
+ port_app_config_handler.mock_get_port_app_config.return_value = valid_config
151
+
152
+ # Act
153
+ async with event_context(EventType.RESYNC, trigger_type="machine"):
154
+ result1 = await port_app_config_handler.get_port_app_config()
155
+ result2 = await port_app_config_handler.get_port_app_config(use_cache=False)
156
+
157
+ # Assert
158
+ assert result1 == result2
159
+ assert (
160
+ port_app_config_handler.mock_get_port_app_config.call_count == 2
161
+ ) # Called twice due to cache bypass
162
+
163
+
164
+ @pytest.mark.asyncio
165
+ async def test_get_port_app_config_validation_error(
166
+ port_app_config_handler: TestPortAppConfig, monkeypatch: pytest.MonkeyPatch
167
+ ) -> None:
168
+ # Arrange
169
+ invalid_config = {"invalid_field": "invalid_value"}
170
+ port_app_config_handler.mock_get_port_app_config.return_value = invalid_config
171
+
172
+ def mock_parse_obj(*args: Any, **kwargs: Any) -> None:
173
+ raise ValidationError(errors=[], model=PortAppConfig)
174
+
175
+ monkeypatch.setattr(
176
+ port_app_config_handler.CONFIG_CLASS, "parse_obj", mock_parse_obj
177
+ )
178
+
179
+ # Act & Assert
180
+ with pytest.raises(ValidationError):
181
+ async with event_context(EventType.RESYNC, trigger_type="machine"):
182
+ await port_app_config_handler.get_port_app_config()
183
+
184
+
185
+ @pytest.mark.asyncio
186
+ async def test_get_port_app_config_fetch_error(
187
+ port_app_config_handler: TestPortAppConfig,
188
+ ) -> None:
189
+ # Arrange
190
+ port_app_config_handler.mock_get_port_app_config.side_effect = (
191
+ EmptyPortAppConfigError("Port app config is empty")
192
+ )
193
+
194
+ # Act & Assert
195
+ async with event_context(EventType.RESYNC, trigger_type="machine"):
196
+ with pytest.raises(EmptyPortAppConfigError, match="Port app config is empty"):
197
+ await port_app_config_handler.get_port_app_config()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.18.4"
3
+ version = "0.18.5"
4
4
  description = "Port Ocean is a CLI tool for managing your Port projects."
5
5
  readme = "README.md"
6
6
  homepage = "https://app.getport.io"
File without changes
File without changes