port-ocean 0.18.1__tar.gz → 0.18.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of port-ocean might be problematic. Click here for more details.

Files changed (166) hide show
  1. {port_ocean-0.18.1 → port_ocean-0.18.3}/PKG-INFO +1 -1
  2. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Makefile +9 -1
  3. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/client.py +3 -0
  4. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/mixins/integrations.py +56 -4
  5. port_ocean-0.18.3/port_ocean/clients/port/mixins/organization.py +31 -0
  6. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/config/settings.py +17 -1
  7. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/defaults/initialize.py +56 -8
  8. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/sync_raw.py +8 -13
  9. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/models.py +6 -1
  10. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/port_defaults.py +10 -0
  11. port_ocean-0.18.3/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +27 -0
  12. {port_ocean-0.18.1 → port_ocean-0.18.3}/pyproject.toml +1 -1
  13. {port_ocean-0.18.1 → port_ocean-0.18.3}/LICENSE.md +0 -0
  14. {port_ocean-0.18.1 → port_ocean-0.18.3}/README.md +0 -0
  15. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Dockerfile.Deb +0 -0
  16. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Dockerfile.alpine +0 -0
  17. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Dockerfile.base.builder +0 -0
  18. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Dockerfile.base.runner +0 -0
  19. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/Dockerfile.dockerignore +0 -0
  20. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/grpcio.sh +0 -0
  21. {port_ocean-0.18.1 → port_ocean-0.18.3}/integrations/_infra/init.sh +0 -0
  22. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/__init__.py +0 -0
  23. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/bootstrap.py +0 -0
  24. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/__init__.py +0 -0
  25. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cli.py +0 -0
  26. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/__init__.py +0 -0
  27. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  28. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/defaults/clean.py +0 -0
  29. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/defaults/dock.py +0 -0
  30. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/defaults/group.py +0 -0
  31. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/list_integrations.py +0 -0
  32. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/main.py +0 -0
  33. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/new.py +0 -0
  34. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/pull.py +0 -0
  35. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/sail.py +0 -0
  36. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/commands/version.py +0 -0
  37. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  38. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  39. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  40. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  41. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  42. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  43. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  44. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  45. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  46. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  47. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  48. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  49. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  50. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  51. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  52. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  53. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  54. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  55. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  56. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  57. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  58. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/cli/utils.py +0 -0
  59. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/__init__.py +0 -0
  60. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/__init__.py +0 -0
  61. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/authentication.py +0 -0
  62. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/mixins/__init__.py +0 -0
  63. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  64. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/mixins/entities.py +0 -0
  65. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/mixins/migrations.py +0 -0
  66. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/retry_transport.py +0 -0
  67. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/types.py +0 -0
  68. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/clients/port/utils.py +0 -0
  69. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/config/__init__.py +0 -0
  70. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/config/base.py +0 -0
  71. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/config/dynamic.py +0 -0
  72. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/consumers/__init__.py +0 -0
  73. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/consumers/kafka_consumer.py +0 -0
  74. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/context/__init__.py +0 -0
  75. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/context/event.py +0 -0
  76. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/context/ocean.py +0 -0
  77. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/context/resource.py +0 -0
  78. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/__init__.py +0 -0
  79. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/defaults/__init__.py +0 -0
  80. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/defaults/clean.py +0 -0
  81. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/defaults/common.py +0 -0
  82. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/__init__.py +0 -0
  83. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/base.py +0 -0
  84. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/factory.py +0 -0
  85. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/http.py +0 -0
  86. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/kafka.py +0 -0
  87. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/once.py +0 -0
  88. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/polling.py +0 -0
  89. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  90. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/__init__.py +0 -0
  91. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/base.py +0 -0
  92. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  93. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  94. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  95. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  96. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  97. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  98. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  99. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  100. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  101. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  102. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  103. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  104. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  105. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  106. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  107. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/__init__.py +0 -0
  108. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/base.py +0 -0
  109. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  110. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/events.py +0 -0
  111. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/handler.py +0 -0
  112. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/sync.py +0 -0
  113. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/integrations/mixins/utils.py +0 -0
  114. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/ocean_types.py +0 -0
  115. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  116. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/core/utils/utils.py +0 -0
  117. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/debug_cli.py +0 -0
  118. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/__init__.py +0 -0
  119. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/api.py +0 -0
  120. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/base.py +0 -0
  121. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/clients.py +0 -0
  122. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/context.py +0 -0
  123. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/core.py +0 -0
  124. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/exceptions/utils.py +0 -0
  125. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/helpers/__init__.py +0 -0
  126. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/helpers/async_client.py +0 -0
  127. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/helpers/retry.py +0 -0
  128. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/log/__init__.py +0 -0
  129. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/log/handlers.py +0 -0
  130. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/log/logger_setup.py +0 -0
  131. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/log/sensetive.py +0 -0
  132. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/middlewares.py +0 -0
  133. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/ocean.py +0 -0
  134. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/py.typed +0 -0
  135. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/run.py +0 -0
  136. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/sonar-project.properties +0 -0
  137. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/__init__.py +0 -0
  138. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  139. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/conftest.py +0 -0
  140. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/defaults/test_common.py +0 -0
  141. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  142. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
  143. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/test_utils.py +0 -0
  144. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  145. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  146. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/__init__.py +0 -0
  147. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  148. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/fixtures.py +0 -0
  149. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/integration.py +0 -0
  150. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/ocean_app.py +0 -0
  151. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/port_client.py +0 -0
  152. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/helpers/smoke_test.py +0 -0
  153. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/log/test_handlers.py +0 -0
  154. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/test_smoke.py +0 -0
  155. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  156. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/tests/utils/test_cache.py +0 -0
  157. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/__init__.py +0 -0
  158. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/async_http.py +0 -0
  159. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/async_iterators.py +0 -0
  160. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/cache.py +0 -0
  161. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/misc.py +0 -0
  162. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/queue_utils.py +0 -0
  163. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/repeat.py +0 -0
  164. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/signal.py +0 -0
  165. {port_ocean-0.18.1 → port_ocean-0.18.3}/port_ocean/utils/time.py +0 -0
  166. {port_ocean-0.18.1 → port_ocean-0.18.3}/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.1
3
+ Version: 0.18.3
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
@@ -41,7 +41,7 @@ define deactivate_virtualenv
41
41
  fi
42
42
  endef
43
43
 
44
- .SILENT: install install/prod install/local-core lint lint/fix run test clean
44
+ .SILENT: install install/prod install/local-core lint lint/fix run test clean seed
45
45
 
46
46
  install:
47
47
  $(call deactivate_virtualenv) && \
@@ -85,3 +85,11 @@ clean:
85
85
  rm -rf .tox/
86
86
  rm -rf docs/_build
87
87
  rm -rf dist/
88
+
89
+ seed:
90
+ @if [ -f "tests/seed_data.py" ]; then \
91
+ $(ACTIVATE) && python tests/seed_data.py; \
92
+ else \
93
+ echo "No seeding script found. Create tests/seed_data.py for this integration if needed."; \
94
+ exit 0; \
95
+ fi
@@ -5,6 +5,7 @@ from port_ocean.clients.port.mixins.blueprints import BlueprintClientMixin
5
5
  from port_ocean.clients.port.mixins.entities import EntityClientMixin
6
6
  from port_ocean.clients.port.mixins.integrations import IntegrationClientMixin
7
7
  from port_ocean.clients.port.mixins.migrations import MigrationClientMixin
8
+ from port_ocean.clients.port.mixins.organization import OrganizationClientMixin
8
9
  from port_ocean.clients.port.types import (
9
10
  KafkaCreds,
10
11
  )
@@ -21,6 +22,7 @@ class PortClient(
21
22
  IntegrationClientMixin,
22
23
  BlueprintClientMixin,
23
24
  MigrationClientMixin,
25
+ OrganizationClientMixin,
24
26
  ):
25
27
  def __init__(
26
28
  self,
@@ -48,6 +50,7 @@ class PortClient(
48
50
  )
49
51
  BlueprintClientMixin.__init__(self, self.auth, self.client)
50
52
  MigrationClientMixin.__init__(self, self.auth, self.client)
53
+ OrganizationClientMixin.__init__(self, self.auth, self.client)
51
54
 
52
55
  async def get_kafka_creds(self) -> KafkaCreds:
53
56
  logger.info("Fetching organization kafka credentials")
@@ -1,16 +1,25 @@
1
- from typing import Any, TYPE_CHECKING, Optional, TypedDict
1
+ import asyncio
2
+ from typing import Any, Dict, TYPE_CHECKING, Optional, TypedDict
2
3
  from urllib.parse import quote_plus
3
4
 
4
5
  import httpx
5
6
  from loguru import logger
6
7
  from port_ocean.clients.port.authentication import PortAuthentication
7
8
  from port_ocean.clients.port.utils import handle_status_code
9
+ from port_ocean.exceptions.port_defaults import DefaultsProvisionFailed
8
10
  from port_ocean.log.sensetive import sensitive_log_filter
9
11
 
10
12
  if TYPE_CHECKING:
11
13
  from port_ocean.core.handlers.port_app_config.models import PortAppConfig
12
14
 
13
15
 
16
+ INTEGRATION_POLLING_INTERVAL_INITIAL_SECONDS = 3
17
+ INTEGRATION_POLLING_INTERVAL_BACKOFF_FACTOR = 1.15
18
+ INTEGRATION_POLLING_RETRY_LIMIT = 30
19
+ CREATE_RESOURCES_PARAM_NAME = "integration_modes"
20
+ CREATE_RESOURCES_PARAM_VALUE = ["create_resources"]
21
+
22
+
14
23
  class LogAttributes(TypedDict):
15
24
  ingestUrl: str
16
25
 
@@ -50,12 +59,41 @@ class IntegrationClientMixin:
50
59
  self._log_attributes = response["logAttributes"]
51
60
  return self._log_attributes
52
61
 
62
+ async def _poll_integration_until_default_provisioning_is_complete(
63
+ self,
64
+ ) -> Dict[str, Any]:
65
+ attempts = 0
66
+ current_interval_seconds = INTEGRATION_POLLING_INTERVAL_INITIAL_SECONDS
67
+
68
+ while attempts < INTEGRATION_POLLING_RETRY_LIMIT:
69
+ logger.info(
70
+ f"Fetching created integration and validating config, attempt {attempts+1}/{INTEGRATION_POLLING_RETRY_LIMIT}",
71
+ attempt=attempts,
72
+ )
73
+ response = await self._get_current_integration()
74
+ integration_json = response.json()
75
+ if integration_json.get("integration", {}).get("config", {}):
76
+ return integration_json
77
+
78
+ logger.info(
79
+ f"Integration config is still being provisioned, retrying in {current_interval_seconds} seconds"
80
+ )
81
+ await asyncio.sleep(current_interval_seconds)
82
+
83
+ attempts += 1
84
+ current_interval_seconds = int(
85
+ current_interval_seconds * INTEGRATION_POLLING_INTERVAL_BACKOFF_FACTOR
86
+ )
87
+
88
+ raise DefaultsProvisionFailed(INTEGRATION_POLLING_RETRY_LIMIT)
89
+
53
90
  async def create_integration(
54
91
  self,
55
92
  _type: str,
56
93
  changelog_destination: dict[str, Any],
57
94
  port_app_config: Optional["PortAppConfig"] = None,
58
- ) -> dict:
95
+ create_port_resources_origin_in_port: Optional[bool] = False,
96
+ ) -> Dict[str, Any]:
59
97
  logger.info(f"Creating integration with id: {self.integration_identifier}")
60
98
  headers = await self.auth.headers()
61
99
  json = {
@@ -65,12 +103,26 @@ class IntegrationClientMixin:
65
103
  "changelogDestination": changelog_destination,
66
104
  "config": {},
67
105
  }
68
- if port_app_config:
106
+
107
+ query_params = {}
108
+
109
+ if create_port_resources_origin_in_port:
110
+ query_params[CREATE_RESOURCES_PARAM_NAME] = CREATE_RESOURCES_PARAM_VALUE
111
+
112
+ if port_app_config and not create_port_resources_origin_in_port:
69
113
  json["config"] = port_app_config.to_request()
70
114
  response = await self.client.post(
71
- f"{self.auth.api_url}/integration", headers=headers, json=json
115
+ f"{self.auth.api_url}/integration",
116
+ headers=headers,
117
+ json=json,
118
+ params=query_params,
72
119
  )
73
120
  handle_status_code(response)
121
+ if create_port_resources_origin_in_port:
122
+ result = (
123
+ await self._poll_integration_until_default_provisioning_is_complete()
124
+ )
125
+ return result["integration"]
74
126
  return response.json()["integration"]
75
127
 
76
128
  async def patch_integration(
@@ -0,0 +1,31 @@
1
+ from typing import List
2
+ import httpx
3
+ from loguru import logger
4
+ from port_ocean.clients.port.authentication import PortAuthentication
5
+ from port_ocean.clients.port.utils import handle_status_code
6
+
7
+
8
+ class OrganizationClientMixin:
9
+ def __init__(
10
+ self,
11
+ auth: PortAuthentication,
12
+ client: httpx.AsyncClient,
13
+ ):
14
+ self.auth = auth
15
+ self.client = client
16
+
17
+ async def _get_organization_feature_flags(self) -> httpx.Response:
18
+ logger.info("Fetching organization feature flags")
19
+
20
+ response = await self.client.get(
21
+ f"{self.auth.api_url}/organization",
22
+ headers=await self.auth.headers(),
23
+ )
24
+ return response
25
+
26
+ async def get_organization_feature_flags(
27
+ self, should_raise: bool = True, should_log: bool = True
28
+ ) -> List[str]:
29
+ response = await self._get_organization_feature_flags()
30
+ handle_status_code(response, should_raise, should_log)
31
+ return response.json().get("organization", {}).get("featureFlags", [])
@@ -8,7 +8,7 @@ from pydantic.main import BaseModel
8
8
 
9
9
  from port_ocean.config.base import BaseOceanSettings, BaseOceanModel
10
10
  from port_ocean.core.event_listener import EventListenerSettingsType
11
- from port_ocean.core.models import Runtime
11
+ from port_ocean.core.models import CreatePortResourcesOrigin, Runtime
12
12
  from port_ocean.utils.misc import get_integration_name, get_spec_file
13
13
 
14
14
  LogLevelType = Literal["ERROR", "WARNING", "INFO", "DEBUG", "CRITICAL"]
@@ -68,6 +68,8 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
68
68
  initialize_port_resources: bool = True
69
69
  scheduled_resync_interval: int | None = None
70
70
  client_timeout: int = 60
71
+ # Determines if Port should generate resources such as blueprints and pages instead of ocean
72
+ create_port_resources_origin: CreatePortResourcesOrigin | None = None
71
73
  send_raw_data_examples: bool = True
72
74
  port: PortSettings
73
75
  event_listener: EventListenerSettingsType = Field(
@@ -101,6 +103,20 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
101
103
 
102
104
  return values
103
105
 
106
+ @validator("create_port_resources_origin")
107
+ def validate_create_port_resources_origin(
108
+ cls, create_port_resources_origin: CreatePortResourcesOrigin | None
109
+ ) -> CreatePortResourcesOrigin | None:
110
+ spec = get_spec_file()
111
+ if spec and spec.get("create_port_resources_origin", None):
112
+ spec_create_port_resources_origin = spec.get("create_port_resources_origin")
113
+ if spec_create_port_resources_origin in [
114
+ CreatePortResourcesOrigin.Port,
115
+ CreatePortResourcesOrigin.Ocean,
116
+ ]:
117
+ return CreatePortResourcesOrigin(spec_create_port_resources_origin)
118
+ return create_port_resources_origin
119
+
104
120
  @validator("runtime")
105
121
  def validate_runtime(cls, runtime: Runtime) -> Runtime:
106
122
  if runtime.is_saas_runtime:
@@ -13,12 +13,14 @@ from port_ocean.core.defaults.common import (
13
13
  get_port_integration_defaults,
14
14
  )
15
15
  from port_ocean.core.handlers.port_app_config.models import PortAppConfig
16
- from port_ocean.core.models import Blueprint
16
+ from port_ocean.core.models import Blueprint, CreatePortResourcesOrigin
17
17
  from port_ocean.core.utils.utils import gather_and_split_errors_from_results
18
18
  from port_ocean.exceptions.port_defaults import (
19
19
  AbortDefaultCreationError,
20
20
  )
21
21
 
22
+ ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG = "USE_PROVISIONED_DEFAULTS"
23
+
22
24
 
23
25
  def deconstruct_blueprints_to_creation_steps(
24
26
  raw_blueprints: list[dict[str, Any]],
@@ -54,8 +56,8 @@ def deconstruct_blueprints_to_creation_steps(
54
56
 
55
57
  async def _initialize_required_integration_settings(
56
58
  port_client: PortClient,
57
- default_mapping: PortAppConfig,
58
59
  integration_config: IntegrationConfiguration,
60
+ default_mapping: PortAppConfig | None = None,
59
61
  ) -> None:
60
62
  try:
61
63
  logger.info("Initializing integration at port")
@@ -70,6 +72,8 @@ async def _initialize_required_integration_settings(
70
72
  integration_config.integration.type,
71
73
  integration_config.event_listener.get_changelog_destination_details(),
72
74
  port_app_config=default_mapping,
75
+ create_port_resources_origin_in_port=integration_config.create_port_resources_origin
76
+ == CreatePortResourcesOrigin.Port,
73
77
  )
74
78
  elif not integration.get("config"):
75
79
  logger.info(
@@ -102,8 +106,10 @@ async def _initialize_required_integration_settings(
102
106
 
103
107
  async def _create_resources(
104
108
  port_client: PortClient,
105
- defaults: Defaults,
109
+ defaults: Defaults | None = None,
106
110
  ) -> None:
111
+ if not defaults:
112
+ return
107
113
  creation_stage, *blueprint_patches = deconstruct_blueprints_to_creation_steps(
108
114
  defaults.blueprints
109
115
  )
@@ -199,22 +205,64 @@ async def _create_resources(
199
205
  async def _initialize_defaults(
200
206
  config_class: Type[PortAppConfig], integration_config: IntegrationConfiguration
201
207
  ) -> None:
208
+ if not integration_config.initialize_port_resources:
209
+ return
210
+
202
211
  port_client = ocean.port_client
203
212
  defaults = get_port_integration_defaults(
204
213
  config_class, integration_config.resources_path
205
214
  )
206
- if not defaults:
215
+
216
+ if (
217
+ not integration_config.create_port_resources_origin
218
+ and integration_config.runtime.is_saas_runtime
219
+ ):
220
+ logger.info("Setting resources origin to be Port")
221
+ integration_config.create_port_resources_origin = CreatePortResourcesOrigin.Port
222
+
223
+ if (
224
+ integration_config.create_port_resources_origin
225
+ == CreatePortResourcesOrigin.Port
226
+ ):
227
+ logger.info(
228
+ "Resources origin is set to be Port, verifying integration is supported"
229
+ )
230
+ org_feature_flags = await port_client.get_organization_feature_flags()
231
+ if ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG not in org_feature_flags:
232
+ logger.info(
233
+ "Port origin for Integration is not supported, changing resources origin to use Ocean"
234
+ )
235
+ integration_config.create_port_resources_origin = (
236
+ CreatePortResourcesOrigin.Ocean
237
+ )
238
+
239
+ if (
240
+ integration_config.create_port_resources_origin
241
+ != CreatePortResourcesOrigin.Port
242
+ and not defaults
243
+ ):
207
244
  logger.warning("No defaults found. Skipping initialization...")
208
245
  return None
209
246
 
210
- if defaults.port_app_config:
247
+ if (
248
+ (defaults and defaults.port_app_config)
249
+ or integration_config.create_port_resources_origin
250
+ == CreatePortResourcesOrigin.Port
251
+ ):
211
252
  await _initialize_required_integration_settings(
212
- port_client, defaults.port_app_config, integration_config
253
+ port_client,
254
+ integration_config,
255
+ defaults.port_app_config if defaults else None,
213
256
  )
214
257
 
215
- if not integration_config.initialize_port_resources:
258
+ if (
259
+ integration_config.create_port_resources_origin
260
+ == CreatePortResourcesOrigin.Port
261
+ ):
262
+ logger.info(
263
+ "Skipping creating defaults resources due to `create_port_resources_origin` being `Port`"
264
+ )
216
265
  return
217
-
218
266
  try:
219
267
  logger.info("Found default resources, starting creation process")
220
268
  await _create_resources(port_client, defaults)
@@ -143,19 +143,14 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
143
143
  "combinator": "and",
144
144
  "rules": [
145
145
  {
146
- "combinator": "or",
147
- "rules": [
148
- {
149
- "property": "$identifier",
150
- "operator": "in",
151
- "value": [entity.identifier for entity in entities],
152
- },
153
- {
154
- "property": "$blueprint",
155
- "operator": "=",
156
- "value": entities[0].blueprint,
157
- }
158
- ]
146
+ "property": "$identifier",
147
+ "operator": "in",
148
+ "value": [entity.identifier for entity in entities]
149
+ },
150
+ {
151
+ "property": "$blueprint",
152
+ "operator": "=",
153
+ "value": entities[0].blueprint
159
154
  }
160
155
  ]
161
156
  }
@@ -1,11 +1,16 @@
1
1
  from dataclasses import dataclass, field
2
- from enum import Enum
2
+ from enum import Enum, StrEnum
3
3
  from typing import Any
4
4
 
5
5
  from pydantic import BaseModel
6
6
  from pydantic.fields import Field
7
7
 
8
8
 
9
+ class CreatePortResourcesOrigin(StrEnum):
10
+ Ocean = "Ocean"
11
+ Port = "Port"
12
+
13
+
9
14
  class Runtime(Enum):
10
15
  Saas = "Saas"
11
16
  OnPrem = "OnPrem"
@@ -14,3 +14,13 @@ class AbortDefaultCreationError(BaseOceanException):
14
14
 
15
15
  class UnsupportedDefaultFileType(BaseOceanException):
16
16
  pass
17
+
18
+
19
+ class DefaultsProvisionFailed(BaseOceanException):
20
+ def __init__(
21
+ self,
22
+ retries: int,
23
+ ):
24
+ super().__init__(
25
+ f"Failed to retrieve integration config after {retries} attempts"
26
+ )
@@ -0,0 +1,27 @@
1
+ import pytest
2
+ from unittest.mock import MagicMock, AsyncMock
3
+
4
+ from port_ocean.clients.port.mixins.organization import OrganizationClientMixin
5
+
6
+
7
+ @pytest.fixture
8
+ async def mocked_org_mixin() -> OrganizationClientMixin:
9
+ auth = MagicMock()
10
+ auth.headers = AsyncMock()
11
+ auth.headers.return_value = {"auth": "enticated"}
12
+ client = MagicMock()
13
+ client.get = AsyncMock()
14
+ client.get.return_value = MagicMock()
15
+ client.get.return_value.json = MagicMock()
16
+ client.get.return_value.json.return_value = {
17
+ "organization": {"featureFlags": ["aa", "bb"]}
18
+ }
19
+ return OrganizationClientMixin(auth=auth, client=client)
20
+
21
+
22
+ async def test_org_feature_flags_should_fetch_proper_json_path(
23
+ mocked_org_mixin: OrganizationClientMixin,
24
+ ) -> None:
25
+ result = await mocked_org_mixin.get_organization_feature_flags()
26
+
27
+ assert result == ["aa", "bb"]
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.18.1"
3
+ version = "0.18.3"
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