port-ocean 0.28.19__tar.gz → 0.29.1__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.
- {port_ocean-0.28.19 → port_ocean-0.29.1}/PKG-INFO +3 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/authentication.py +19 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/client.py +3 -0
- port_ocean-0.29.1/port_ocean/clients/port/mixins/actions.py +93 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/blueprints.py +0 -12
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/integrations.py +5 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/config/settings.py +35 -3
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/context/ocean.py +7 -5
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/defaults/initialize.py +12 -5
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/__init__.py +7 -0
- port_ocean-0.29.1/port_ocean/core/event_listener/actions_only.py +42 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/base.py +4 -1
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/factory.py +18 -9
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/http.py +4 -3
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/kafka.py +3 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/once.py +5 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/polling.py +4 -3
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/event_listener/webhooks_only.py +3 -2
- port_ocean-0.29.1/port_ocean/core/handlers/actions/__init__.py +7 -0
- port_ocean-0.29.1/port_ocean/core/handlers/actions/abstract_executor.py +150 -0
- port_ocean-0.29.1/port_ocean/core/handlers/actions/execution_manager.py +434 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +16 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/webhook/processor_manager.py +30 -12
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/sync_raw.py +2 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/models.py +35 -2
- port_ocean-0.29.1/port_ocean/exceptions/execution_manager.py +22 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/ocean.py +30 -4
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/event_listener/test_kafka.py +14 -7
- port_ocean-0.29.1/port_ocean/tests/core/handlers/actions/test_execution_manager.py +837 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +3 -1
- {port_ocean-0.28.19 → port_ocean-0.29.1}/pyproject.toml +3 -2
- {port_ocean-0.28.19 → port_ocean-0.29.1}/LICENSE.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/README.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.Deb +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.alpine +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.base.builder +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.base.runner +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.dockerignore +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Dockerfile.local +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/Makefile +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/README.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/entry_local.sh +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/grpcio.sh +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/integrations/_infra/init.sh +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cache/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cache/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cache/disk.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cache/errors.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cache/memory.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/auth/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/auth/auth_client.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/auth/oauth_client.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/entities.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/mixins/organization.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/retry_transport.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/clients/port/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/config/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/config/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/consumers/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/context/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/context/event.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/context/metric_resource.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/entity_processor/jq_input_evaluator.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/queue/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/queue/group_queue.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/queue/local_queue.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/webhook/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/live_events.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/integrations/mixins/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/core/utils/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/debug_cli.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/exceptions/webhook_processor.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/async_client.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/metric/metric.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/metric/utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/retry.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/helpers/stream.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/log/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/log/handlers.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/log/logger_setup.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/py.typed +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/run.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/cache/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/cache/test_disk_cache.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/cache/test_memory_cache.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/oauth/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/port/mixins/test_integrations.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/config/test_config.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/conftest.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/conftest.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/defaults/test_common.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/entity_processor/test_jq_input_evaluator.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/mixins/test_live_events.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/queue/test_group_queue.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/test_utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/utils/test_get_port_diff.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/fake_port_api.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/fixtures.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/integration.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/ocean_app.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/port_client.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/smoke_test.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/helpers/test_retry.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/log/test_handlers.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/test_metric.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/test_ocean.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/test_smoke.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/utils/test_async_iterators.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/tests/utils/test_cache.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/async_http.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/async_iterators.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/cache.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/ipc.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/misc.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/queue_utils.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/signal.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/utils/time.py +0 -0
- {port_ocean-0.28.19 → port_ocean-0.29.1}/port_ocean/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: port-ocean
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.29.1
|
|
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
|
|
@@ -28,7 +28,7 @@ Requires-Dist: click (>=8.1.3,<9.0.0) ; extra == "cli"
|
|
|
28
28
|
Requires-Dist: confluent-kafka (>=2.10.1,<3.0.0)
|
|
29
29
|
Requires-Dist: cookiecutter (>=2.1.1,<3.0.0) ; extra == "cli"
|
|
30
30
|
Requires-Dist: cryptography (>=44.0.1,<45.0.0)
|
|
31
|
-
Requires-Dist: fastapi (>=0.
|
|
31
|
+
Requires-Dist: fastapi (>=0.121.0,<0.122.0)
|
|
32
32
|
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
33
33
|
Requires-Dist: ijson (>=3.4.0,<4.0.0)
|
|
34
34
|
Requires-Dist: jinja2 (>=3.1.6)
|
|
@@ -39,6 +39,7 @@ Requires-Dist: prometheus-client (>=0.21.1,<0.22.0)
|
|
|
39
39
|
Requires-Dist: pydantic[dotenv] (>=1.10.8,<2.0.0)
|
|
40
40
|
Requires-Dist: pydispatcher (>=2.0.7,<3.0.0)
|
|
41
41
|
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
42
|
+
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
|
|
42
43
|
Requires-Dist: pytest-cov (>=6.0.0,<7.0.0)
|
|
43
44
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
44
45
|
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import jwt
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
5
|
import httpx
|
|
@@ -90,6 +91,24 @@ class PortAuthentication:
|
|
|
90
91
|
)
|
|
91
92
|
return self.last_token_object.full_token
|
|
92
93
|
|
|
94
|
+
async def is_machine_user(self) -> bool:
|
|
95
|
+
# Ensure self.last_token_object is populated
|
|
96
|
+
await self.token
|
|
97
|
+
if not self.last_token_object:
|
|
98
|
+
raise ValueError("No token found")
|
|
99
|
+
|
|
100
|
+
payload: dict[str, Any] = jwt.decode(
|
|
101
|
+
self.last_token_object.access_token, options={"verify_signature": False}
|
|
102
|
+
)
|
|
103
|
+
is_machine_user = payload.get("isMachine")
|
|
104
|
+
if is_machine_user is None:
|
|
105
|
+
logger.warning(
|
|
106
|
+
"Can not determine if the user is a machine user directly, checking for personal token usage instead"
|
|
107
|
+
)
|
|
108
|
+
return not payload.get("personalToken", True)
|
|
109
|
+
|
|
110
|
+
return is_machine_user
|
|
111
|
+
|
|
93
112
|
@staticmethod
|
|
94
113
|
def _is_personal_token(client_id: str) -> bool:
|
|
95
114
|
email_regex = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
|
|
@@ -3,6 +3,7 @@ from typing import Any
|
|
|
3
3
|
from loguru import logger
|
|
4
4
|
|
|
5
5
|
from port_ocean.clients.port.authentication import PortAuthentication
|
|
6
|
+
from port_ocean.clients.port.mixins.actions import ActionsClientMixin
|
|
6
7
|
from port_ocean.clients.port.mixins.blueprints import BlueprintClientMixin
|
|
7
8
|
from port_ocean.clients.port.mixins.entities import EntityClientMixin
|
|
8
9
|
from port_ocean.clients.port.mixins.integrations import IntegrationClientMixin
|
|
@@ -24,6 +25,7 @@ class PortClient(
|
|
|
24
25
|
BlueprintClientMixin,
|
|
25
26
|
MigrationClientMixin,
|
|
26
27
|
OrganizationClientMixin,
|
|
28
|
+
ActionsClientMixin,
|
|
27
29
|
):
|
|
28
30
|
def __init__(
|
|
29
31
|
self,
|
|
@@ -54,6 +56,7 @@ class PortClient(
|
|
|
54
56
|
BlueprintClientMixin.__init__(self, self.auth, self.client)
|
|
55
57
|
MigrationClientMixin.__init__(self, self.auth, self.client)
|
|
56
58
|
OrganizationClientMixin.__init__(self, self.auth, self.client)
|
|
59
|
+
ActionsClientMixin.__init__(self, self.auth, self.client)
|
|
57
60
|
|
|
58
61
|
async def get_kafka_creds(self) -> KafkaCreds:
|
|
59
62
|
logger.info("Fetching organization kafka credentials")
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from typing import Any
|
|
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_port_status_code
|
|
6
|
+
from port_ocean.core.models import (
|
|
7
|
+
ActionRun,
|
|
8
|
+
)
|
|
9
|
+
from port_ocean.exceptions.execution_manager import RunAlreadyAcknowledgedError
|
|
10
|
+
|
|
11
|
+
INTERNAL_ACTIONS_CLIENT_HEADER = {"x-port-automation-client": "true"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ActionsClientMixin:
|
|
15
|
+
def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
|
|
16
|
+
self.auth = auth
|
|
17
|
+
self.client = client
|
|
18
|
+
|
|
19
|
+
async def create_action(
|
|
20
|
+
self, action: dict[str, Any], should_log: bool = True
|
|
21
|
+
) -> None:
|
|
22
|
+
logger.info(f"Creating action: {action}")
|
|
23
|
+
response = await self.client.post(
|
|
24
|
+
f"{self.auth.api_url}/actions",
|
|
25
|
+
json=action,
|
|
26
|
+
headers=await self.auth.headers(),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
handle_port_status_code(response, should_log=should_log)
|
|
30
|
+
|
|
31
|
+
async def claim_pending_runs(
|
|
32
|
+
self, limit: int, visibility_timeout_ms: int
|
|
33
|
+
) -> list[ActionRun]:
|
|
34
|
+
response = await self.client.post(
|
|
35
|
+
f"{self.auth.api_url}/actions/runs/claim-pending",
|
|
36
|
+
headers={**(await self.auth.headers()), **INTERNAL_ACTIONS_CLIENT_HEADER},
|
|
37
|
+
json={
|
|
38
|
+
"installationId": self.auth.integration_identifier,
|
|
39
|
+
"limit": limit,
|
|
40
|
+
"visibilityTimeoutMs": visibility_timeout_ms,
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
if response.is_error:
|
|
44
|
+
logger.error("Error claiming pending runs", error=response.text)
|
|
45
|
+
return []
|
|
46
|
+
|
|
47
|
+
return [ActionRun.parse_obj(run) for run in response.json().get("runs", [])]
|
|
48
|
+
|
|
49
|
+
async def get_run_by_external_id(self, external_id: str) -> ActionRun | None:
|
|
50
|
+
response = await self.client.get(
|
|
51
|
+
f"{self.auth.api_url}/actions/runs?version=v2&external_run_id={external_id}",
|
|
52
|
+
headers=await self.auth.headers(),
|
|
53
|
+
)
|
|
54
|
+
handle_port_status_code(response)
|
|
55
|
+
runs = response.json().get("runs", [])
|
|
56
|
+
return None if not len(runs) else ActionRun.parse_obj(runs[0])
|
|
57
|
+
|
|
58
|
+
async def patch_run(
|
|
59
|
+
self,
|
|
60
|
+
run_id: str,
|
|
61
|
+
run: ActionRun | dict[str, Any],
|
|
62
|
+
should_raise: bool = True,
|
|
63
|
+
) -> None:
|
|
64
|
+
response = await self.client.patch(
|
|
65
|
+
f"{self.auth.api_url}/actions/runs/{run_id}",
|
|
66
|
+
headers=await self.auth.headers(),
|
|
67
|
+
json=run.dict() if isinstance(run, ActionRun) else run,
|
|
68
|
+
)
|
|
69
|
+
handle_port_status_code(response, should_raise=should_raise)
|
|
70
|
+
|
|
71
|
+
async def acknowledge_run(self, run_id: str) -> None:
|
|
72
|
+
try:
|
|
73
|
+
response = await self.client.patch(
|
|
74
|
+
f"{self.auth.api_url}/actions/runs/ack",
|
|
75
|
+
headers={
|
|
76
|
+
**(await self.auth.headers()),
|
|
77
|
+
**INTERNAL_ACTIONS_CLIENT_HEADER,
|
|
78
|
+
},
|
|
79
|
+
json={"runId": run_id},
|
|
80
|
+
)
|
|
81
|
+
handle_port_status_code(response)
|
|
82
|
+
except httpx.HTTPStatusError as e:
|
|
83
|
+
if e.response.status_code == 409:
|
|
84
|
+
raise RunAlreadyAcknowledgedError()
|
|
85
|
+
raise
|
|
86
|
+
|
|
87
|
+
async def post_run_log(self, run_id: str, message: str) -> None:
|
|
88
|
+
response = await self.client.post(
|
|
89
|
+
f"{self.auth.api_url}/actions/runs/{run_id}/logs",
|
|
90
|
+
headers=await self.auth.headers(),
|
|
91
|
+
json={"message": message},
|
|
92
|
+
)
|
|
93
|
+
handle_port_status_code(response, should_raise=False)
|
|
@@ -81,18 +81,6 @@ class BlueprintClientMixin:
|
|
|
81
81
|
handle_port_status_code(response, should_raise)
|
|
82
82
|
return response.json().get("migrationId", "")
|
|
83
83
|
|
|
84
|
-
async def create_action(
|
|
85
|
-
self, action: dict[str, Any], should_log: bool = True
|
|
86
|
-
) -> None:
|
|
87
|
-
logger.info(f"Creating action: {action}")
|
|
88
|
-
response = await self.client.post(
|
|
89
|
-
f"{self.auth.api_url}/actions",
|
|
90
|
-
json=action,
|
|
91
|
-
headers=await self.auth.headers(),
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
handle_port_status_code(response, should_log=should_log)
|
|
95
|
-
|
|
96
84
|
async def create_scorecard(
|
|
97
85
|
self,
|
|
98
86
|
blueprint_identifier: str,
|
|
@@ -14,8 +14,6 @@ from port_ocean.log.sensetive import sensitive_log_filter
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from port_ocean.core.handlers.port_app_config.models import PortAppConfig
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG = "USE_PROVISIONED_DEFAULTS"
|
|
19
17
|
INTEGRATION_POLLING_INTERVAL_INITIAL_SECONDS = 3
|
|
20
18
|
INTEGRATION_POLLING_INTERVAL_BACKOFF_FACTOR = 1.55
|
|
21
19
|
INTEGRATION_POLLING_RETRY_LIMIT = 30
|
|
@@ -153,6 +151,7 @@ class IntegrationClientMixin:
|
|
|
153
151
|
changelog_destination: dict[str, Any],
|
|
154
152
|
port_app_config: Optional["PortAppConfig"] = None,
|
|
155
153
|
create_port_resources_origin_in_port: Optional[bool] = False,
|
|
154
|
+
actions_processing_enabled: Optional[bool] = False,
|
|
156
155
|
) -> Dict[str, Any]:
|
|
157
156
|
logger.info(f"Creating integration with id: {self.integration_identifier}")
|
|
158
157
|
headers = await self.auth.headers()
|
|
@@ -162,6 +161,7 @@ class IntegrationClientMixin:
|
|
|
162
161
|
"version": self.integration_version,
|
|
163
162
|
"changelogDestination": changelog_destination,
|
|
164
163
|
"config": {},
|
|
164
|
+
"actionsProcessingEnabled": actions_processing_enabled,
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
query_params = {}
|
|
@@ -190,6 +190,7 @@ class IntegrationClientMixin:
|
|
|
190
190
|
_type: str | None = None,
|
|
191
191
|
changelog_destination: dict[str, Any] | None = None,
|
|
192
192
|
port_app_config: Optional["PortAppConfig"] = None,
|
|
193
|
+
actions_processing_enabled: Optional[bool] = False,
|
|
193
194
|
) -> dict:
|
|
194
195
|
logger.info(f"Updating integration with id: {self.integration_identifier}")
|
|
195
196
|
headers = await self.auth.headers()
|
|
@@ -200,6 +201,8 @@ class IntegrationClientMixin:
|
|
|
200
201
|
json["changelogDestination"] = changelog_destination
|
|
201
202
|
if port_app_config:
|
|
202
203
|
json["config"] = port_app_config.to_request()
|
|
204
|
+
|
|
205
|
+
json["actionsProcessingEnabled"] = actions_processing_enabled
|
|
203
206
|
json["version"] = self.integration_version
|
|
204
207
|
|
|
205
208
|
response = await self.client.patch(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import platform
|
|
2
|
-
from typing import Any, Literal, Optional, Type
|
|
2
|
+
from typing import Any, Literal, Optional, Type
|
|
3
3
|
|
|
4
4
|
from pydantic import AnyHttpUrl, Extra, parse_obj_as, parse_raw_as
|
|
5
5
|
from pydantic.class_validators import root_validator, validator
|
|
@@ -8,10 +8,14 @@ from pydantic.fields import Field
|
|
|
8
8
|
from pydantic.main import BaseModel
|
|
9
9
|
|
|
10
10
|
from port_ocean.config.base import BaseOceanModel, BaseOceanSettings
|
|
11
|
-
from port_ocean.core.event_listener import
|
|
11
|
+
from port_ocean.core.event_listener import (
|
|
12
|
+
EventListenerSettingsType,
|
|
13
|
+
PollingEventListenerSettings,
|
|
14
|
+
)
|
|
12
15
|
from port_ocean.core.models import (
|
|
13
16
|
CachingStorageMode,
|
|
14
17
|
CreatePortResourcesOrigin,
|
|
18
|
+
EventListenerType,
|
|
15
19
|
ProcessExecutionMode,
|
|
16
20
|
Runtime,
|
|
17
21
|
)
|
|
@@ -80,6 +84,14 @@ class StreamingSettings(BaseOceanModel, extra=Extra.allow):
|
|
|
80
84
|
location: str = Field(default="/tmp/ocean/streaming")
|
|
81
85
|
|
|
82
86
|
|
|
87
|
+
class ActionsProcessorSettings(BaseOceanModel, extra=Extra.allow):
|
|
88
|
+
enabled: bool = Field(default=False)
|
|
89
|
+
runs_buffer_high_watermark: int = Field(default=100)
|
|
90
|
+
visibility_timeout_ms: int = Field(default=30000)
|
|
91
|
+
poll_check_interval_seconds: int = Field(default=10)
|
|
92
|
+
workers_count: int = Field(default=1)
|
|
93
|
+
|
|
94
|
+
|
|
83
95
|
class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
|
|
84
96
|
_integration_config_model: BaseModel | None = None
|
|
85
97
|
|
|
@@ -94,7 +106,9 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
|
|
|
94
106
|
base_url: str | None = None
|
|
95
107
|
port: PortSettings
|
|
96
108
|
event_listener: EventListenerSettingsType = Field(
|
|
97
|
-
|
|
109
|
+
default_factory=lambda: PollingEventListenerSettings(
|
|
110
|
+
type=EventListenerType.POLLING
|
|
111
|
+
)
|
|
98
112
|
)
|
|
99
113
|
event_workers_count: int = 1
|
|
100
114
|
# If an identifier or type is not provided, it will be generated based on the integration name
|
|
@@ -122,6 +136,9 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
|
|
|
122
136
|
yield_items_to_parse_batch_size: int = 10
|
|
123
137
|
|
|
124
138
|
streaming: StreamingSettings = Field(default_factory=lambda: StreamingSettings())
|
|
139
|
+
actions_processor: ActionsProcessorSettings = Field(
|
|
140
|
+
default_factory=lambda: ActionsProcessorSettings()
|
|
141
|
+
)
|
|
125
142
|
|
|
126
143
|
@validator("process_execution_mode")
|
|
127
144
|
def validate_process_execution_mode(
|
|
@@ -197,3 +214,18 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
|
|
|
197
214
|
raise ValueError("This integration can't be ran as Saas")
|
|
198
215
|
|
|
199
216
|
return runtime
|
|
217
|
+
|
|
218
|
+
@validator("actions_processor")
|
|
219
|
+
def validate_actions_processor(
|
|
220
|
+
cls, actions_processor: ActionsProcessorSettings
|
|
221
|
+
) -> ActionsProcessorSettings:
|
|
222
|
+
if not actions_processor.enabled:
|
|
223
|
+
return actions_processor
|
|
224
|
+
|
|
225
|
+
spec = get_spec_file()
|
|
226
|
+
if not (spec and spec.get("actionsProcessingEnabled", False)):
|
|
227
|
+
raise ValueError(
|
|
228
|
+
"Serving as an actions processor is not currently supported for this integration."
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return actions_processor
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Callable, TYPE_CHECKING, Any,
|
|
1
|
+
from typing import Callable, TYPE_CHECKING, Any, Union
|
|
2
2
|
|
|
3
3
|
from fastapi import APIRouter
|
|
4
4
|
from port_ocean.helpers.metric.metric import Metrics
|
|
@@ -7,7 +7,7 @@ from werkzeug.local import LocalProxy
|
|
|
7
7
|
|
|
8
8
|
from port_ocean.clients.port.types import UserAgentType
|
|
9
9
|
|
|
10
|
-
from port_ocean.core.models import Entity
|
|
10
|
+
from port_ocean.core.models import Entity, EventListenerType
|
|
11
11
|
from port_ocean.core.ocean_types import (
|
|
12
12
|
RESYNC_EVENT_LISTENER,
|
|
13
13
|
START_EVENT_LISTENER,
|
|
@@ -26,6 +26,7 @@ if TYPE_CHECKING:
|
|
|
26
26
|
from port_ocean.core.integrations.base import BaseIntegration
|
|
27
27
|
from port_ocean.ocean import Ocean
|
|
28
28
|
from port_ocean.clients.port.client import PortClient
|
|
29
|
+
from port_ocean.core.handlers.actions.abstract_executor import AbstractExecutor
|
|
29
30
|
|
|
30
31
|
from loguru import logger
|
|
31
32
|
|
|
@@ -73,9 +74,7 @@ class PortOceanContext:
|
|
|
73
74
|
return self.app.port_client
|
|
74
75
|
|
|
75
76
|
@property
|
|
76
|
-
def event_listener_type(
|
|
77
|
-
self,
|
|
78
|
-
) -> Literal["WEBHOOK", "KAFKA", "POLLING", "ONCE", "WEBHOOKS_ONLY"]:
|
|
77
|
+
def event_listener_type(self) -> EventListenerType:
|
|
79
78
|
return self.app.config.event_listener.type
|
|
80
79
|
|
|
81
80
|
def on_resync(
|
|
@@ -213,6 +212,9 @@ class PortOceanContext:
|
|
|
213
212
|
"""
|
|
214
213
|
self.app.webhook_manager.register_processor(path, processor)
|
|
215
214
|
|
|
215
|
+
def register_action_executor(self, executor: "AbstractExecutor") -> None:
|
|
216
|
+
self.app.execution_manager.register_executor(executor)
|
|
217
|
+
|
|
216
218
|
|
|
217
219
|
_port_ocean: PortOceanContext = PortOceanContext(None)
|
|
218
220
|
|
|
@@ -13,14 +13,16 @@ 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
|
|
16
|
+
from port_ocean.core.models import (
|
|
17
|
+
Blueprint,
|
|
18
|
+
CreatePortResourcesOrigin,
|
|
19
|
+
IntegrationFeatureFlag,
|
|
20
|
+
)
|
|
17
21
|
from port_ocean.core.utils.utils import gather_and_split_errors_from_results
|
|
18
22
|
from port_ocean.exceptions.port_defaults import (
|
|
19
23
|
AbortDefaultCreationError,
|
|
20
24
|
)
|
|
21
25
|
|
|
22
|
-
ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG = "USE_PROVISIONED_DEFAULTS"
|
|
23
|
-
|
|
24
26
|
|
|
25
27
|
def deconstruct_blueprints_to_creation_steps(
|
|
26
28
|
raw_blueprints: list[dict[str, Any]],
|
|
@@ -75,6 +77,7 @@ async def _initialize_required_integration_settings(
|
|
|
75
77
|
integration_config.integration.type,
|
|
76
78
|
integration_config.event_listener.get_changelog_destination_details(),
|
|
77
79
|
port_app_config=default_mapping,
|
|
80
|
+
actions_processing_enabled=integration_config.actions_processor.enabled,
|
|
78
81
|
create_port_resources_origin_in_port=integration_config.create_port_resources_origin
|
|
79
82
|
== CreatePortResourcesOrigin.Port,
|
|
80
83
|
)
|
|
@@ -101,9 +104,13 @@ async def _initialize_required_integration_settings(
|
|
|
101
104
|
integration.get("changelogDestination") != changelog_destination
|
|
102
105
|
or integration.get("installationAppType") != integration_config.integration.type
|
|
103
106
|
or integration.get("version") != port_client.integration_version
|
|
107
|
+
or integration.get("actionsProcessingEnabled")
|
|
108
|
+
!= integration_config.actions_processor.enabled
|
|
104
109
|
):
|
|
105
110
|
await port_client.patch_integration(
|
|
106
|
-
integration_config.integration.type,
|
|
111
|
+
_type=integration_config.integration.type,
|
|
112
|
+
changelog_destination=changelog_destination,
|
|
113
|
+
actions_processing_enabled=integration_config.actions_processor.enabled,
|
|
107
114
|
)
|
|
108
115
|
|
|
109
116
|
|
|
@@ -219,7 +226,7 @@ async def _initialize_defaults(
|
|
|
219
226
|
)
|
|
220
227
|
)
|
|
221
228
|
|
|
222
|
-
has_provision_feature_flag =
|
|
229
|
+
has_provision_feature_flag = IntegrationFeatureFlag.USE_PROVISIONED_DEFAULTS in (
|
|
223
230
|
await port_client.get_organization_feature_flags()
|
|
224
231
|
)
|
|
225
232
|
|
|
@@ -20,6 +20,10 @@ from port_ocean.core.event_listener.webhooks_only import (
|
|
|
20
20
|
WebhooksOnlyEventListener,
|
|
21
21
|
WebhooksOnlyEventListenerSettings,
|
|
22
22
|
)
|
|
23
|
+
from port_ocean.core.event_listener.actions_only import (
|
|
24
|
+
ActionsOnlyEventListener,
|
|
25
|
+
ActionsOnlyEventListenerSettings,
|
|
26
|
+
)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
EventListenerSettingsType = (
|
|
@@ -28,6 +32,7 @@ EventListenerSettingsType = (
|
|
|
28
32
|
| PollingEventListenerSettings
|
|
29
33
|
| OnceEventListenerSettings
|
|
30
34
|
| WebhooksOnlyEventListenerSettings
|
|
35
|
+
| ActionsOnlyEventListenerSettings
|
|
31
36
|
)
|
|
32
37
|
|
|
33
38
|
__all__ = [
|
|
@@ -42,4 +47,6 @@ __all__ = [
|
|
|
42
47
|
"OnceEventListenerSettings",
|
|
43
48
|
"WebhooksOnlyEventListener",
|
|
44
49
|
"WebhooksOnlyEventListenerSettings",
|
|
50
|
+
"ActionsOnlyEventListener",
|
|
51
|
+
"ActionsOnlyEventListenerSettings",
|
|
45
52
|
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
from loguru import logger
|
|
3
|
+
|
|
4
|
+
from port_ocean.core.event_listener.base import (
|
|
5
|
+
BaseEventListener,
|
|
6
|
+
EventListenerEvents,
|
|
7
|
+
EventListenerSettings,
|
|
8
|
+
)
|
|
9
|
+
from port_ocean.core.models import EventListenerType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ActionsOnlyEventListenerSettings(EventListenerSettings):
|
|
13
|
+
"""
|
|
14
|
+
This class inherits from `EventListenerSettings`, which provides a foundation for creating event listener settings.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
type: Literal[EventListenerType.ACTIONS_ONLY]
|
|
18
|
+
should_resync: bool = False
|
|
19
|
+
should_process_webhooks: bool = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ActionsOnlyEventListener(BaseEventListener):
|
|
23
|
+
"""
|
|
24
|
+
No resync event listener.
|
|
25
|
+
|
|
26
|
+
It is used to handle events exclusively through actions without supporting resync events.
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
events (EventListenerEvents): A dictionary containing event types and their corresponding event handlers.
|
|
30
|
+
event_listener_config (ActionsOnlyEventListenerSettings): The event listener configuration settings.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
events: EventListenerEvents,
|
|
36
|
+
event_listener_config: ActionsOnlyEventListenerSettings,
|
|
37
|
+
):
|
|
38
|
+
super().__init__(events)
|
|
39
|
+
self.event_listener_config = event_listener_config
|
|
40
|
+
|
|
41
|
+
async def _start(self) -> None:
|
|
42
|
+
logger.info("Starting Actions-only event listener")
|
|
@@ -4,6 +4,7 @@ from typing import TypedDict, Callable, Any, Awaitable
|
|
|
4
4
|
from pydantic import Extra
|
|
5
5
|
|
|
6
6
|
from port_ocean.config.base import BaseOceanModel
|
|
7
|
+
from port_ocean.core.models import EventListenerType
|
|
7
8
|
from port_ocean.utils.signal import signal_handler
|
|
8
9
|
from port_ocean.context.ocean import ocean
|
|
9
10
|
from port_ocean.utils.misc import IntegrationStateStatus
|
|
@@ -78,8 +79,10 @@ class BaseEventListener:
|
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
class EventListenerSettings(BaseOceanModel, extra=Extra.allow):
|
|
81
|
-
type:
|
|
82
|
+
type: EventListenerType
|
|
82
83
|
should_resync: bool = True
|
|
84
|
+
should_process_webhooks: bool = True
|
|
85
|
+
should_run_actions: bool = True
|
|
83
86
|
|
|
84
87
|
def get_changelog_destination_details(self) -> dict[str, Any]:
|
|
85
88
|
"""
|
|
@@ -13,6 +13,10 @@ from port_ocean.core.event_listener import (
|
|
|
13
13
|
KafkaEventListenerSettings,
|
|
14
14
|
PollingEventListenerSettings,
|
|
15
15
|
)
|
|
16
|
+
from port_ocean.core.event_listener.actions_only import (
|
|
17
|
+
ActionsOnlyEventListener,
|
|
18
|
+
ActionsOnlyEventListenerSettings,
|
|
19
|
+
)
|
|
16
20
|
from port_ocean.core.event_listener.base import (
|
|
17
21
|
BaseEventListener,
|
|
18
22
|
EventListenerEvents,
|
|
@@ -21,6 +25,7 @@ from port_ocean.core.event_listener.webhooks_only import (
|
|
|
21
25
|
WebhooksOnlyEventListener,
|
|
22
26
|
WebhooksOnlyEventListenerSettings,
|
|
23
27
|
)
|
|
28
|
+
from port_ocean.core.models import EventListenerType
|
|
24
29
|
from port_ocean.exceptions.core import UnsupportedEventListenerTypeException
|
|
25
30
|
|
|
26
31
|
|
|
@@ -57,12 +62,11 @@ class EventListenerFactory:
|
|
|
57
62
|
wrapped_events: EventListenerEvents = {"on_resync": self.events["on_resync"]}
|
|
58
63
|
event_listener: BaseEventListener
|
|
59
64
|
config = self.context.config.event_listener
|
|
60
|
-
_type = config.type.lower()
|
|
61
65
|
assert_message = "Invalid event listener config, expected KafkaEventListenerSettings and got {0}"
|
|
62
|
-
logger.info(f"Found event listener type: {
|
|
66
|
+
logger.info(f"Found event listener type: {config.type}")
|
|
63
67
|
|
|
64
|
-
match
|
|
65
|
-
case
|
|
68
|
+
match config.type:
|
|
69
|
+
case EventListenerType.KAFKA:
|
|
66
70
|
assert isinstance(
|
|
67
71
|
config, KafkaEventListenerSettings
|
|
68
72
|
), assert_message.format(type(config))
|
|
@@ -75,31 +79,36 @@ class EventListenerFactory:
|
|
|
75
79
|
self.context.config.integration.type,
|
|
76
80
|
)
|
|
77
81
|
|
|
78
|
-
case
|
|
82
|
+
case EventListenerType.WEBHOOK:
|
|
79
83
|
assert isinstance(
|
|
80
84
|
config, HttpEventListenerSettings
|
|
81
85
|
), assert_message.format(type(config))
|
|
82
86
|
event_listener = HttpEventListener(wrapped_events, config)
|
|
83
87
|
|
|
84
|
-
case
|
|
88
|
+
case EventListenerType.POLLING:
|
|
85
89
|
assert isinstance(
|
|
86
90
|
config, PollingEventListenerSettings
|
|
87
91
|
), assert_message.format(type(config))
|
|
88
92
|
event_listener = PollingEventListener(wrapped_events, config)
|
|
89
93
|
|
|
90
|
-
case
|
|
94
|
+
case EventListenerType.ONCE:
|
|
91
95
|
assert isinstance(
|
|
92
96
|
config, OnceEventListenerSettings
|
|
93
97
|
), assert_message.format(type(config))
|
|
94
98
|
event_listener = OnceEventListener(wrapped_events, config)
|
|
95
|
-
case
|
|
99
|
+
case EventListenerType.WEBHOOKS_ONLY:
|
|
96
100
|
assert isinstance(
|
|
97
101
|
config, WebhooksOnlyEventListenerSettings
|
|
98
102
|
), assert_message.format(type(config))
|
|
99
103
|
event_listener = WebhooksOnlyEventListener(wrapped_events, config)
|
|
104
|
+
case EventListenerType.ACTIONS_ONLY:
|
|
105
|
+
assert isinstance(
|
|
106
|
+
config, ActionsOnlyEventListenerSettings
|
|
107
|
+
), assert_message.format(type(config))
|
|
108
|
+
event_listener = ActionsOnlyEventListener(wrapped_events, config)
|
|
100
109
|
case _:
|
|
101
110
|
raise UnsupportedEventListenerTypeException(
|
|
102
|
-
f"Event listener {
|
|
111
|
+
f"Event listener {config.type} not supported"
|
|
103
112
|
)
|
|
104
113
|
|
|
105
114
|
return event_listener
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any, Literal
|
|
2
2
|
|
|
3
3
|
from fastapi import APIRouter
|
|
4
4
|
from loguru import logger
|
|
@@ -11,6 +11,7 @@ from port_ocean.core.event_listener.base import (
|
|
|
11
11
|
EventListenerEvents,
|
|
12
12
|
EventListenerSettings,
|
|
13
13
|
)
|
|
14
|
+
from port_ocean.core.models import EventListenerType
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class HttpEventListenerSettings(EventListenerSettings):
|
|
@@ -19,12 +20,12 @@ class HttpEventListenerSettings(EventListenerSettings):
|
|
|
19
20
|
The `HttpEventListenerSettings` specifically includes settings related to the HTTP event listener (Webhook).
|
|
20
21
|
|
|
21
22
|
Attributes:
|
|
22
|
-
type (
|
|
23
|
+
type (EventListenerType): A literal indicating the type of the event listener, which is set to "WEBHOOK" for this class.
|
|
23
24
|
app_host (AnyHttpUrl): The base URL of the application hosting the webhook.
|
|
24
25
|
The "AnyHttpUrl" type indicates that the value must be a valid HTTP/HTTPS URL.
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
|
-
type: Literal[
|
|
28
|
+
type: Literal[EventListenerType.WEBHOOK]
|
|
28
29
|
app_host: AnyHttpUrl = Field(..., sensitive=True)
|
|
29
30
|
|
|
30
31
|
def get_changelog_destination_details(self) -> dict[str, Any]:
|
|
@@ -17,6 +17,7 @@ from port_ocean.core.event_listener.base import (
|
|
|
17
17
|
EventListenerSettings,
|
|
18
18
|
)
|
|
19
19
|
from pydantic import validator
|
|
20
|
+
from port_ocean.core.models import EventListenerType
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class KafkaEventListenerSettings(EventListenerSettings):
|
|
@@ -25,7 +26,7 @@ class KafkaEventListenerSettings(EventListenerSettings):
|
|
|
25
26
|
The `KafkaEventListenerSettings` specifically includes settings related to the Kafka event listener.
|
|
26
27
|
|
|
27
28
|
Attributes:
|
|
28
|
-
type (
|
|
29
|
+
type (EventListenerType): A literal indicating the type of the event listener, which is set to "KAFKA" for this class.
|
|
29
30
|
brokers (str): The comma-separated list of Kafka broker URLs to connect to.
|
|
30
31
|
security_protocol (str): The security protocol used for communication with Kafka brokers.
|
|
31
32
|
The default value is "SASL_SSL".
|
|
@@ -38,7 +39,7 @@ class KafkaEventListenerSettings(EventListenerSettings):
|
|
|
38
39
|
The default value is 1 second.
|
|
39
40
|
"""
|
|
40
41
|
|
|
41
|
-
type: Literal[
|
|
42
|
+
type: Literal[EventListenerType.KAFKA]
|
|
42
43
|
brokers: str = (
|
|
43
44
|
"b-1-public.publicclusterprod.t9rw6w.c1.kafka.eu-west-1.amazonaws.com:9196,b-2-public.publicclusterprod.t9rw6w.c1.kafka.eu-west-1.amazonaws.com:9196,b-3-public.publicclusterprod.t9rw6w.c1.kafka.eu-west-1.amazonaws.com:9196"
|
|
44
45
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import signal
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any, Literal
|
|
4
4
|
|
|
5
5
|
from loguru import logger
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ from port_ocean.core.event_listener.base import (
|
|
|
9
9
|
EventListenerEvents,
|
|
10
10
|
EventListenerSettings,
|
|
11
11
|
)
|
|
12
|
+
from port_ocean.core.models import EventListenerType
|
|
12
13
|
from port_ocean.utils.repeat import repeat_every
|
|
13
14
|
from port_ocean.context.ocean import ocean
|
|
14
15
|
from port_ocean.utils.time import convert_str_to_utc_datetime, convert_to_minutes
|
|
@@ -21,7 +22,9 @@ class OnceEventListenerSettings(EventListenerSettings):
|
|
|
21
22
|
This class inherits from `EventListenerSettings`, which provides a foundation for creating event listener settings.
|
|
22
23
|
"""
|
|
23
24
|
|
|
24
|
-
type: Literal[
|
|
25
|
+
type: Literal[EventListenerType.ONCE]
|
|
26
|
+
should_process_webhooks: bool = False
|
|
27
|
+
should_run_actions: bool = False
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
class OnceEventListener(BaseEventListener):
|