plynt 0.11.0__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.
- plynt-0.11.0/.github/CODEOWNERS +2 -0
- plynt-0.11.0/.github/ISSUE_TEMPLATE/bug_report.yml +37 -0
- plynt-0.11.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- plynt-0.11.0/.github/ISSUE_TEMPLATE/feature_request.yml +25 -0
- plynt-0.11.0/.github/ISSUE_TEMPLATE/release_smoke_checklist.yml +84 -0
- plynt-0.11.0/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +16 -0
- plynt-0.11.0/.github/copilot-instructions.md +310 -0
- plynt-0.11.0/.github/dependabot.yml +41 -0
- plynt-0.11.0/.github/workflows/automerge.yml +128 -0
- plynt-0.11.0/.github/workflows/check.yml +74 -0
- plynt-0.11.0/.github/workflows/commit.yml +111 -0
- plynt-0.11.0/.github/workflows/distribution.yml +90 -0
- plynt-0.11.0/.github/workflows/publish.yml +139 -0
- plynt-0.11.0/.github/workflows/release.yml +74 -0
- plynt-0.11.0/.github/workflows/salesforce-cdc-proto-watch.yml +44 -0
- plynt-0.11.0/.github/workflows/security.yml +64 -0
- plynt-0.11.0/.github/workflows/verify.yml +63 -0
- plynt-0.11.0/.gitignore +59 -0
- plynt-0.11.0/.gitlint +7 -0
- plynt-0.11.0/.markdownlint.yml +5 -0
- plynt-0.11.0/.pre-commit-config.yaml +43 -0
- plynt-0.11.0/.python-version +4 -0
- plynt-0.11.0/.release-please-config.json +70 -0
- plynt-0.11.0/.release-please-manifest.json +3 -0
- plynt-0.11.0/.yamllint.yml +15 -0
- plynt-0.11.0/AGENTS.md +121 -0
- plynt-0.11.0/CHANGELOG.md +400 -0
- plynt-0.11.0/CODE_OF_CONDUCT.md +32 -0
- plynt-0.11.0/CONTRIBUTING.md +237 -0
- plynt-0.11.0/LICENSE +21 -0
- plynt-0.11.0/Makefile +266 -0
- plynt-0.11.0/PKG-INFO +188 -0
- plynt-0.11.0/README-pypi.md +113 -0
- plynt-0.11.0/README.md +219 -0
- plynt-0.11.0/SECURITY.md +22 -0
- plynt-0.11.0/cchk.toml +55 -0
- plynt-0.11.0/docs/architecture/adr/0001-architecture-principles.md +80 -0
- plynt-0.11.0/docs/architecture/adr/0002-layered-architecture.md +209 -0
- plynt-0.11.0/docs/architecture/adr/0003-dependency-policy.md +33 -0
- plynt-0.11.0/docs/architecture/adr/0004-settings-and-configuration.md +264 -0
- plynt-0.11.0/docs/architecture/adr/0005-request-layer.md +129 -0
- plynt-0.11.0/docs/architecture/adr/0006-transport-layer.md +124 -0
- plynt-0.11.0/docs/architecture/adr/0007-response-layer.md +215 -0
- plynt-0.11.0/docs/architecture/adr/0008-client-layer.md +241 -0
- plynt-0.11.0/docs/architecture/adr/0009-service-layer.md +197 -0
- plynt-0.11.0/docs/architecture/adr/0010-caching.md +247 -0
- plynt-0.11.0/docs/architecture/adr/0011-authentication.md +319 -0
- plynt-0.11.0/docs/architecture/adr/0012-retry-strategy.md +206 -0
- plynt-0.11.0/docs/architecture/adr/0013-transport-base-class.md +248 -0
- plynt-0.11.0/docs/architecture/adr/0014-logging.md +318 -0
- plynt-0.11.0/docs/architecture/adr/0015-header-middleware.md +115 -0
- plynt-0.11.0/docs/architecture/adr/0016-vcr-testsupport.md +164 -0
- plynt-0.11.0/docs/architecture/adr/0017-streaming-response.md +270 -0
- plynt-0.11.0/docs/architecture/adr/0018-raw-response-access.md +141 -0
- plynt-0.11.0/docs/architecture/adr/0019-circuit-breaker-middleware.md +148 -0
- plynt-0.11.0/docs/architecture/adr/0020-rate-limit-middleware.md +150 -0
- plynt-0.11.0/docs/architecture/adr/0021-llm-contract-boundary.md +178 -0
- plynt-0.11.0/docs/architecture/adr/0022-upstream-rate-governance.md +175 -0
- plynt-0.11.0/docs/architecture/adr/0023-httpx2-transport-backend.md +136 -0
- plynt-0.11.0/docs/architecture/adr/0024-framework-adapter-strategy.md +157 -0
- plynt-0.11.0/docs/architecture/adr/0025-django-adapter-sync-async-strategy.md +189 -0
- plynt-0.11.0/docs/architecture/adr/0026-fastapi-adapter-lifecycle-and-di.md +169 -0
- plynt-0.11.0/docs/architecture/adr/0027-public-api-compatibility-and-deprecation-policy.md +111 -0
- plynt-0.11.0/docs/architecture/adr/0028-supported-environments-and-extras-policy.md +117 -0
- plynt-0.11.0/docs/architecture/adr/0029-release-acceptance-gates-and-evidence-model.md +117 -0
- plynt-0.11.0/docs/architecture/adr/0030-grpc-protocol-boundary.md +170 -0
- plynt-0.11.0/docs/architecture/adr/0031-experimental-release-installation-contract.md +109 -0
- plynt-0.11.0/docs/architecture/adr/0032-grpc-codegen-version-refresh.md +72 -0
- plynt-0.11.0/docs/architecture/adr/0033-python-315-support-and-local-pyenv.md +129 -0
- plynt-0.11.0/docs/architecture/adr/0034-django-6-support.md +76 -0
- plynt-0.11.0/docs/architecture/adr/0035-pre-1-versioning-policy.md +72 -0
- plynt-0.11.0/docs/architecture/adr/0036-project-and-package-rebrand-to-plynt.md +230 -0
- plynt-0.11.0/docs/architecture/adr/README.md +65 -0
- plynt-0.11.0/docs/architecture/overview.md +140 -0
- plynt-0.11.0/docs/architecture/risks/ai-connectors.md +49 -0
- plynt-0.11.0/docs/changes/django-framework-adapter_django_adapter_20260713.md +537 -0
- plynt-0.11.0/docs/changes/fastapi-framework-adapter_fastapi_adapter_20260725.md +184 -0
- plynt-0.11.0/docs/changes/llm-adapters_openai_anthropic_20260705.md +172 -0
- plynt-0.11.0/docs/changes/public-release-readiness_20260802.md +737 -0
- plynt-0.11.0/docs/connectors/llm/README.md +128 -0
- plynt-0.11.0/docs/connectors/salesforce/README.md +538 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/README.md +31 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0001-error-mapping.md +173 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0002-sobject-api-facade.md +63 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0003-query-service-design.md +290 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0004-search-capability-design.md +140 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0005-bulk-api-2-design.md +313 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0006-jwt-bearer-auth.md +114 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0007-composite-rest-primitives.md +122 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0008-metadata-rest-deploy.md +117 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0009-identity-access-primitives.md +112 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0010-query-response-normalization.md +124 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0011-ai-connector-boundary.md +89 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0012-extraction-strategy.md +176 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/adr/sf-0013-salesforce-eventing-architecture.md +162 -0
- plynt-0.11.0/docs/connectors/salesforce/architecture/overview.md +84 -0
- plynt-0.11.0/docs/connectors/salesforce/design/ai-models-design.md +160 -0
- plynt-0.11.0/docs/connectors/salesforce/product/roadmap.md +350 -0
- plynt-0.11.0/docs/connectors/salesforce/user/README.md +49 -0
- plynt-0.11.0/docs/connectors/salesforce/user/explanation/README.md +8 -0
- plynt-0.11.0/docs/connectors/salesforce/user/explanation/api-limits.md +90 -0
- plynt-0.11.0/docs/connectors/salesforce/user/explanation/auth-flows.md +172 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/README.md +42 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/authenticate.md +257 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/bulk.md +190 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/deploy-cdc.md +255 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/handle-errors.md +97 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/query-records.md +94 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/resilience.md +141 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/search.md +100 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/sobject-crud.md +200 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/use-agent-api.md +163 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/use-composite.md +175 -0
- plynt-0.11.0/docs/connectors/salesforce/user/how-to/use-models-api.md +183 -0
- plynt-0.11.0/docs/connectors/salesforce/user/reference/README.md +13 -0
- plynt-0.11.0/docs/connectors/salesforce/user/reference/errors.md +116 -0
- plynt-0.11.0/docs/connectors/salesforce/user/reference/models.md +77 -0
- plynt-0.11.0/docs/connectors/salesforce/user/reference/services.md +260 -0
- plynt-0.11.0/docs/connectors/salesforce/user/reference/settings.md +58 -0
- plynt-0.11.0/docs/connectors/salesforce/user/tutorials/01-connect-and-query.md +110 -0
- plynt-0.11.0/docs/connectors/salesforce/user/tutorials/README.md +7 -0
- plynt-0.11.0/docs/product/ideas/flask-adapter.md +134 -0
- plynt-0.11.0/docs/product/ideas/middleware-extensions.md +90 -0
- plynt-0.11.0/docs/product/requirements.md +92 -0
- plynt-0.11.0/docs/product/roadmap.md +853 -0
- plynt-0.11.0/docs/product/vision.md +65 -0
- plynt-0.11.0/docs/releases/2026-08-02-public-readiness-evidence.md +39 -0
- plynt-0.11.0/docs/releases/2026-10-13-experimental-rc-hardening-evidence.md +338 -0
- plynt-0.11.0/docs/user/README.md +91 -0
- plynt-0.11.0/docs/user/explanation/README.md +14 -0
- plynt-0.11.0/docs/user/explanation/architecture.md +236 -0
- plynt-0.11.0/docs/user/explanation/middleware-model.md +164 -0
- plynt-0.11.0/docs/user/explanation/sync-async.md +74 -0
- plynt-0.11.0/docs/user/how-to/README.md +47 -0
- plynt-0.11.0/docs/user/how-to/add-authentication.md +161 -0
- plynt-0.11.0/docs/user/how-to/configure-logging.md +128 -0
- plynt-0.11.0/docs/user/how-to/django/django-middleware-interoperability.md +80 -0
- plynt-0.11.0/docs/user/how-to/django/use-django-cache-backend.md +81 -0
- plynt-0.11.0/docs/user/how-to/django/use-django-transport-helper.md +183 -0
- plynt-0.11.0/docs/user/how-to/drf/drf-serializer-business-patterns.md +246 -0
- plynt-0.11.0/docs/user/how-to/drf/use-drf-plynt-service-mixin.md +391 -0
- plynt-0.11.0/docs/user/how-to/fastapi/use-fastapi-service-facade.md +407 -0
- plynt-0.11.0/docs/user/how-to/handle-errors.md +124 -0
- plynt-0.11.0/docs/user/how-to/salesforce/README.md +5 -0
- plynt-0.11.0/docs/user/how-to/use-async.md +114 -0
- plynt-0.11.0/docs/user/how-to/use-cache.md +181 -0
- plynt-0.11.0/docs/user/how-to/use-middleware.md +200 -0
- plynt-0.11.0/docs/user/how-to/write-middleware.md +196 -0
- plynt-0.11.0/docs/user/reference/README.md +22 -0
- plynt-0.11.0/docs/user/reference/auth-configs.md +157 -0
- plynt-0.11.0/docs/user/reference/cache-backends.md +121 -0
- plynt-0.11.0/docs/user/reference/installation.md +124 -0
- plynt-0.11.0/docs/user/reference/middleware.md +212 -0
- plynt-0.11.0/docs/user/reference/settings.md +148 -0
- plynt-0.11.0/docs/user/tutorials/01-getting-started.md +140 -0
- plynt-0.11.0/docs/user/tutorials/02-build-a-connector.md +185 -0
- plynt-0.11.0/docs/user/tutorials/03-add-middleware.md +160 -0
- plynt-0.11.0/docs/user/tutorials/04-add-caching.md +148 -0
- plynt-0.11.0/docs/user/tutorials/05-test-with-vcr.md +194 -0
- plynt-0.11.0/docs/user/tutorials/README.md +25 -0
- plynt-0.11.0/examples/django/README.md +34 -0
- plynt-0.11.0/examples/django/cache_backend.md +34 -0
- plynt-0.11.0/examples/django/middleware_profile.md +30 -0
- plynt-0.11.0/examples/django/transport_from_settings.md +70 -0
- plynt-0.11.0/examples/drf/README.md +30 -0
- plynt-0.11.0/examples/drf/drf_service_view.md +96 -0
- plynt-0.11.0/examples/drf/exception_handler_setup.md +30 -0
- plynt-0.11.0/examples/drf/serializer_orchestrator_view.md +111 -0
- plynt-0.11.0/examples/llm/README.md +88 -0
- plynt-0.11.0/examples/llm/anthropic_messages.md +77 -0
- plynt-0.11.0/examples/llm/example.env +16 -0
- plynt-0.11.0/examples/llm/openai_responses.md +69 -0
- plynt-0.11.0/examples/salesforce/README.md +173 -0
- plynt-0.11.0/examples/salesforce/client_credentials.md +69 -0
- plynt-0.11.0/examples/salesforce/example.env +79 -0
- plynt-0.11.0/examples/salesforce/shared_demo.md +169 -0
- plynt-0.11.0/examples/salesforce/username_password.md +123 -0
- plynt-0.11.0/pyproject.toml +262 -0
- plynt-0.11.0/setup.cfg +4 -0
- plynt-0.11.0/src/plynt/__init__.py +1 -0
- plynt-0.11.0/src/plynt/adapters/__init__.py +8 -0
- plynt-0.11.0/src/plynt/adapters/django/__init__.py +23 -0
- plynt-0.11.0/src/plynt/adapters/django/cache.py +159 -0
- plynt-0.11.0/src/plynt/adapters/django/drf/__init__.py +28 -0
- plynt-0.11.0/src/plynt/adapters/django/drf/errors.py +119 -0
- plynt-0.11.0/src/plynt/adapters/django/drf/headers.py +140 -0
- plynt-0.11.0/src/plynt/adapters/django/drf/views.py +354 -0
- plynt-0.11.0/src/plynt/adapters/django/settings.py +114 -0
- plynt-0.11.0/src/plynt/adapters/django/transport.py +155 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/__init__.py +38 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/dependencies.py +57 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/errors.py +140 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/headers.py +141 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/lifespan.py +76 -0
- plynt-0.11.0/src/plynt/adapters/fastapi/services.py +98 -0
- plynt-0.11.0/src/plynt/base/__init__.py +68 -0
- plynt-0.11.0/src/plynt/base/cache.py +264 -0
- plynt-0.11.0/src/plynt/base/errors.py +319 -0
- plynt-0.11.0/src/plynt/base/mapping.py +22 -0
- plynt-0.11.0/src/plynt/base/middleware.py +152 -0
- plynt-0.11.0/src/plynt/base/policies.py +279 -0
- plynt-0.11.0/src/plynt/base/request.py +62 -0
- plynt-0.11.0/src/plynt/base/response.py +275 -0
- plynt-0.11.0/src/plynt/base/settings.py +52 -0
- plynt-0.11.0/src/plynt/base/transport.py +255 -0
- plynt-0.11.0/src/plynt/cache/__init__.py +171 -0
- plynt-0.11.0/src/plynt/cache/cachetools.py +78 -0
- plynt-0.11.0/src/plynt/cache/dummy.py +65 -0
- plynt-0.11.0/src/plynt/cache/locmem.py +209 -0
- plynt-0.11.0/src/plynt/cache/redis.py +222 -0
- plynt-0.11.0/src/plynt/connectors/__init__.py +1 -0
- plynt-0.11.0/src/plynt/connectors/llm/__init__.py +59 -0
- plynt-0.11.0/src/plynt/connectors/llm/adapters/__init__.py +43 -0
- plynt-0.11.0/src/plynt/connectors/llm/adapters/anthropic.py +628 -0
- plynt-0.11.0/src/plynt/connectors/llm/adapters/base.py +176 -0
- plynt-0.11.0/src/plynt/connectors/llm/adapters/openai.py +918 -0
- plynt-0.11.0/src/plynt/connectors/llm/models.py +264 -0
- plynt-0.11.0/src/plynt/connectors/llm/service.py +593 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/__init__.py +203 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/agent.py +201 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/ai.py +252 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/apex.py +92 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/__init__.py +49 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/bearer.py +217 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/credentials.py +60 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/mixins.py +109 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/password.py +87 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/auth/session.py +40 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/bulk/__init__.py +27 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/bulk/service.py +932 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/__init__.py +53 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_bitmap.py +190 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/README.md +33 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/SOURCE.md +20 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/__init__.py +5 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/pubsub_api.proto +413 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/pubsub_api_pb2.py +75 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/_proto/pubsub_api_pb2_grpc.py +422 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/auth.py +100 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/avro.py +87 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/checkpoint.py +80 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/errors.py +44 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/models.py +109 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/pubsub.py +436 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/cdc/service.py +846 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/client.py +368 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/composite.py +370 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/constants.py +65 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/errors.py +362 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/facade.py +428 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/helpers.py +270 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/identity/__init__.py +13 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/identity/service.py +496 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/__init__.py +65 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/base.py +173 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/factory.py +90 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/pricebook.py +105 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/profile.py +130 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/queue.py +134 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/record_type.py +111 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/types.py +15 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/lookup/user.py +108 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/metadata.py +319 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/models/__init__.py +63 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/models/schemas.py +611 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/query/__init__.py +17 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/query/service.py +694 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/renderer.py +61 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/search.py +134 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/settings.py +101 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/sobject/__init__.py +15 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/sobject/service.py +732 -0
- plynt-0.11.0/src/plynt/connectors/salesforce/utility.py +445 -0
- plynt-0.11.0/src/plynt/grpc/__init__.py +33 -0
- plynt-0.11.0/src/plynt/grpc/client.py +302 -0
- plynt-0.11.0/src/plynt/grpc/errors.py +35 -0
- plynt-0.11.0/src/plynt/grpc/handler.py +22 -0
- plynt-0.11.0/src/plynt/grpc/interceptor.py +18 -0
- plynt-0.11.0/src/plynt/grpc/protobuf.py +73 -0
- plynt-0.11.0/src/plynt/grpc/settings.py +23 -0
- plynt-0.11.0/src/plynt/grpc/transport.py +296 -0
- plynt-0.11.0/src/plynt/http/__init__.py +93 -0
- plynt-0.11.0/src/plynt/http/auth.py +377 -0
- plynt-0.11.0/src/plynt/http/client.py +749 -0
- plynt-0.11.0/src/plynt/http/errors.py +464 -0
- plynt-0.11.0/src/plynt/http/mapping.py +47 -0
- plynt-0.11.0/src/plynt/http/middleware/__init__.py +40 -0
- plynt-0.11.0/src/plynt/http/middleware/auth/__init__.py +61 -0
- plynt-0.11.0/src/plynt/http/middleware/auth/basic.py +88 -0
- plynt-0.11.0/src/plynt/http/middleware/auth/bearer.py +81 -0
- plynt-0.11.0/src/plynt/http/middleware/auth/oauth2.py +853 -0
- plynt-0.11.0/src/plynt/http/policies.py +67 -0
- plynt-0.11.0/src/plynt/http/renderer.py +121 -0
- plynt-0.11.0/src/plynt/http/response.py +131 -0
- plynt-0.11.0/src/plynt/http/service.py +176 -0
- plynt-0.11.0/src/plynt/http/settings.py +303 -0
- plynt-0.11.0/src/plynt/http/transport.py +696 -0
- plynt-0.11.0/src/plynt/log/__init__.py +45 -0
- plynt-0.11.0/src/plynt/log/filters.py +189 -0
- plynt-0.11.0/src/plynt/log/formatter.py +131 -0
- plynt-0.11.0/src/plynt/middleware/__init__.py +60 -0
- plynt-0.11.0/src/plynt/middleware/cache.py +163 -0
- plynt-0.11.0/src/plynt/middleware/circuit_breaker.py +159 -0
- plynt-0.11.0/src/plynt/middleware/header.py +149 -0
- plynt-0.11.0/src/plynt/middleware/logging.py +227 -0
- plynt-0.11.0/src/plynt/middleware/rate_limit.py +90 -0
- plynt-0.11.0/src/plynt/middleware/retry.py +301 -0
- plynt-0.11.0/src/plynt/middleware/throttle.py +313 -0
- plynt-0.11.0/src/plynt/testsupport/__init__.py +43 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/README.md +501 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/__init__.py +48 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/config.py +64 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/matchers.py +141 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/middleware.py +77 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/path.py +170 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/py.typed +0 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/serializer.py +94 -0
- plynt-0.11.0/src/plynt/testsupport/vcr/session.py +378 -0
- plynt-0.11.0/src/plynt.egg-info/PKG-INFO +188 -0
- plynt-0.11.0/src/plynt.egg-info/SOURCES.txt +470 -0
- plynt-0.11.0/src/plynt.egg-info/dependency_links.txt +1 -0
- plynt-0.11.0/src/plynt.egg-info/requires.txt +55 -0
- plynt-0.11.0/src/plynt.egg-info/scm_file_list.json +467 -0
- plynt-0.11.0/src/plynt.egg-info/scm_version.json +8 -0
- plynt-0.11.0/src/plynt.egg-info/top_level.txt +1 -0
- plynt-0.11.0/tests/__init__.py +1 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/ai_smoke/salesforceaivcrsmoke/models_generate_chat__6b8ea57e.yaml +398 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/ai_smoke/salesforceaivcrsmoke/models_generate_text__4321b893.yaml +398 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/limits__eea7066d.yaml +670 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/objects_catalog__b14b1071.yaml +7386 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/query_accounts__58b98669.yaml +766 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/query_org_metadata__a9358913.yaml +456 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/quick_search__1101ee82.yaml +838 -0
- plynt-0.11.0/tests/_mock/cassettes/connectors/salesforce/smoke/salesforcevcrsmoke/versions__679797d3.yaml +576 -0
- plynt-0.11.0/tests/adapters/__init__.py +1 -0
- plynt-0.11.0/tests/adapters/django/__init__.py +1 -0
- plynt-0.11.0/tests/adapters/django/drf/__init__.py +1 -0
- plynt-0.11.0/tests/adapters/django/drf/test_drf_package.py +52 -0
- plynt-0.11.0/tests/adapters/django/drf/test_errors.py +378 -0
- plynt-0.11.0/tests/adapters/django/drf/test_headers.py +234 -0
- plynt-0.11.0/tests/adapters/django/drf/test_smoke.py +110 -0
- plynt-0.11.0/tests/adapters/django/drf/test_views.py +882 -0
- plynt-0.11.0/tests/adapters/django/test_cache.py +456 -0
- plynt-0.11.0/tests/adapters/django/test_django_package.py +42 -0
- plynt-0.11.0/tests/adapters/django/test_settings.py +127 -0
- plynt-0.11.0/tests/adapters/django/test_smoke.py +97 -0
- plynt-0.11.0/tests/adapters/django/test_transport.py +374 -0
- plynt-0.11.0/tests/adapters/fastapi/test_errors.py +91 -0
- plynt-0.11.0/tests/adapters/fastapi/test_fastapi_package.py +69 -0
- plynt-0.11.0/tests/adapters/fastapi/test_headers.py +75 -0
- plynt-0.11.0/tests/adapters/fastapi/test_lifespan.py +252 -0
- plynt-0.11.0/tests/adapters/fastapi/test_services.py +222 -0
- plynt-0.11.0/tests/base/__init__.py +1 -0
- plynt-0.11.0/tests/base/test_base.py +93 -0
- plynt-0.11.0/tests/base/test_base_package.py +65 -0
- plynt-0.11.0/tests/base/test_errors.py +142 -0
- plynt-0.11.0/tests/base/test_mapping.py +72 -0
- plynt-0.11.0/tests/base/test_middleware.py +264 -0
- plynt-0.11.0/tests/base/test_policies.py +91 -0
- plynt-0.11.0/tests/base/test_request.py +57 -0
- plynt-0.11.0/tests/base/test_response.py +488 -0
- plynt-0.11.0/tests/base/test_retry.py +56 -0
- plynt-0.11.0/tests/base/test_settings.py +46 -0
- plynt-0.11.0/tests/base/test_transport.py +649 -0
- plynt-0.11.0/tests/cache/__init__.py +0 -0
- plynt-0.11.0/tests/cache/test_cache.py +215 -0
- plynt-0.11.0/tests/cache/test_cachetools.py +117 -0
- plynt-0.11.0/tests/cache/test_dummy.py +77 -0
- plynt-0.11.0/tests/cache/test_locmem.py +184 -0
- plynt-0.11.0/tests/cache/test_redis.py +215 -0
- plynt-0.11.0/tests/conftest.py +124 -0
- plynt-0.11.0/tests/connectors/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/llm/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/llm/adapters/test_anthropic.py +789 -0
- plynt-0.11.0/tests/connectors/llm/adapters/test_base.py +126 -0
- plynt-0.11.0/tests/connectors/llm/adapters/test_openai.py +980 -0
- plynt-0.11.0/tests/connectors/llm/models/test_models.py +163 -0
- plynt-0.11.0/tests/connectors/llm/test_service.py +877 -0
- plynt-0.11.0/tests/connectors/salesforce/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/helpers.py +221 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/test_bearer.py +240 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/test_credentials.py +221 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/test_password.py +107 -0
- plynt-0.11.0/tests/connectors/salesforce/auth/test_session.py +41 -0
- plynt-0.11.0/tests/connectors/salesforce/bulk/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/bulk/test_service.py +1339 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_auth.py +118 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_avro.py +169 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_bitmap.py +240 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_checkpoint.py +74 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_integration_grpc.py +456 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_models.py +194 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_pubsub.py +437 -0
- plynt-0.11.0/tests/connectors/salesforce/cdc/test_service.py +1285 -0
- plynt-0.11.0/tests/connectors/salesforce/conftest.py +197 -0
- plynt-0.11.0/tests/connectors/salesforce/identity/test_service.py +784 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/conftest.py +29 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_facade.py +73 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_pricebook.py +84 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_profile.py +129 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_queue.py +138 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_record_type.py +112 -0
- plynt-0.11.0/tests/connectors/salesforce/lookup/test_user.py +106 -0
- plynt-0.11.0/tests/connectors/salesforce/models/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/models/test_schemas.py +329 -0
- plynt-0.11.0/tests/connectors/salesforce/query/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/query/test_service.py +791 -0
- plynt-0.11.0/tests/connectors/salesforce/sobject/__init__.py +1 -0
- plynt-0.11.0/tests/connectors/salesforce/sobject/test_service.py +821 -0
- plynt-0.11.0/tests/connectors/salesforce/test_agent.py +268 -0
- plynt-0.11.0/tests/connectors/salesforce/test_ai.py +383 -0
- plynt-0.11.0/tests/connectors/salesforce/test_ai_smoke.py +182 -0
- plynt-0.11.0/tests/connectors/salesforce/test_apex.py +148 -0
- plynt-0.11.0/tests/connectors/salesforce/test_client.py +685 -0
- plynt-0.11.0/tests/connectors/salesforce/test_composite.py +433 -0
- plynt-0.11.0/tests/connectors/salesforce/test_constants.py +106 -0
- plynt-0.11.0/tests/connectors/salesforce/test_errors.py +270 -0
- plynt-0.11.0/tests/connectors/salesforce/test_helpers.py +317 -0
- plynt-0.11.0/tests/connectors/salesforce/test_metadata.py +370 -0
- plynt-0.11.0/tests/connectors/salesforce/test_renderer.py +123 -0
- plynt-0.11.0/tests/connectors/salesforce/test_salesforce_package.py +51 -0
- plynt-0.11.0/tests/connectors/salesforce/test_search.py +238 -0
- plynt-0.11.0/tests/connectors/salesforce/test_settings.py +51 -0
- plynt-0.11.0/tests/connectors/salesforce/test_smoke.py +277 -0
- plynt-0.11.0/tests/connectors/salesforce/test_throttle.py +200 -0
- plynt-0.11.0/tests/connectors/salesforce/test_utility.py +557 -0
- plynt-0.11.0/tests/distribution/test_installed.py +192 -0
- plynt-0.11.0/tests/grpc/test_client.py +418 -0
- plynt-0.11.0/tests/grpc/test_errors_interceptor.py +49 -0
- plynt-0.11.0/tests/grpc/test_protobuf.py +91 -0
- plynt-0.11.0/tests/grpc/test_settings.py +32 -0
- plynt-0.11.0/tests/grpc/test_transport.py +420 -0
- plynt-0.11.0/tests/http/__init__.py +0 -0
- plynt-0.11.0/tests/http/conftest.py +119 -0
- plynt-0.11.0/tests/http/middleware/__init__.py +0 -0
- plynt-0.11.0/tests/http/middleware/auth/__init__.py +0 -0
- plynt-0.11.0/tests/http/middleware/auth/test_basic.py +90 -0
- plynt-0.11.0/tests/http/middleware/auth/test_bearer.py +86 -0
- plynt-0.11.0/tests/http/middleware/auth/test_oauth2.py +1382 -0
- plynt-0.11.0/tests/http/test_auth.py +311 -0
- plynt-0.11.0/tests/http/test_client.py +710 -0
- plynt-0.11.0/tests/http/test_errors.py +325 -0
- plynt-0.11.0/tests/http/test_http_package.py +80 -0
- plynt-0.11.0/tests/http/test_mapping.py +92 -0
- plynt-0.11.0/tests/http/test_response.py +189 -0
- plynt-0.11.0/tests/http/test_retry.py +71 -0
- plynt-0.11.0/tests/http/test_service.py +418 -0
- plynt-0.11.0/tests/http/test_settings.py +393 -0
- plynt-0.11.0/tests/http/test_transport.py +1531 -0
- plynt-0.11.0/tests/log/__init__.py +1 -0
- plynt-0.11.0/tests/log/test_filters.py +254 -0
- plynt-0.11.0/tests/log/test_formatter.py +99 -0
- plynt-0.11.0/tests/middleware/__init__.py +0 -0
- plynt-0.11.0/tests/middleware/test_cache.py +653 -0
- plynt-0.11.0/tests/middleware/test_circuit_breaker.py +378 -0
- plynt-0.11.0/tests/middleware/test_header.py +267 -0
- plynt-0.11.0/tests/middleware/test_logging.py +326 -0
- plynt-0.11.0/tests/middleware/test_rate_limit.py +180 -0
- plynt-0.11.0/tests/middleware/test_retry.py +338 -0
- plynt-0.11.0/tests/middleware/test_throttle.py +618 -0
- plynt-0.11.0/tests/testsupport/__init__.py +1 -0
- plynt-0.11.0/tests/testsupport/vcr/__init__.py +1 -0
- plynt-0.11.0/tests/testsupport/vcr/_helpers.py +50 -0
- plynt-0.11.0/tests/testsupport/vcr/test_context.py +76 -0
- plynt-0.11.0/tests/testsupport/vcr/test_matchers.py +226 -0
- plynt-0.11.0/tests/testsupport/vcr/test_middleware.py +354 -0
- plynt-0.11.0/tests/testsupport/vcr/test_path.py +114 -0
- plynt-0.11.0/tests/testsupport/vcr/test_serializer.py +142 -0
- plynt-0.11.0/tests/testsupport/vcr/test_session.py +106 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a reproducible bug
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: summary
|
|
7
|
+
attributes:
|
|
8
|
+
label: Summary
|
|
9
|
+
description: What happened?
|
|
10
|
+
placeholder: A clear and concise description of the bug.
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: steps
|
|
16
|
+
attributes:
|
|
17
|
+
label: Steps to reproduce
|
|
18
|
+
description: Exact steps to reproduce the issue.
|
|
19
|
+
placeholder: |
|
|
20
|
+
1. ...
|
|
21
|
+
2. ...
|
|
22
|
+
3. ...
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: expected
|
|
28
|
+
attributes:
|
|
29
|
+
label: Expected behavior
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: environment
|
|
35
|
+
attributes:
|
|
36
|
+
label: Environment
|
|
37
|
+
description: Python version, OS, and any relevant details.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem statement
|
|
9
|
+
description: What user or developer problem does this solve?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: Proposed solution
|
|
17
|
+
description: Describe your proposed approach.
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: alternatives
|
|
23
|
+
attributes:
|
|
24
|
+
label: Alternatives considered
|
|
25
|
+
description: What alternatives did you consider?
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: Release smoke checklist
|
|
2
|
+
description: Verify release automation and publish safety for a real release
|
|
3
|
+
labels: ["release"]
|
|
4
|
+
body:
|
|
5
|
+
- type: input
|
|
6
|
+
id: target_version
|
|
7
|
+
attributes:
|
|
8
|
+
label: Target version
|
|
9
|
+
description: Planned release version (SemVer)
|
|
10
|
+
placeholder: 0.2.2
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: dropdown
|
|
15
|
+
id: release_reason
|
|
16
|
+
attributes:
|
|
17
|
+
label: Release reason
|
|
18
|
+
description: Select why this release is being made
|
|
19
|
+
options:
|
|
20
|
+
- Feature delivery
|
|
21
|
+
- Bug fix
|
|
22
|
+
- Security fix
|
|
23
|
+
- Maintenance
|
|
24
|
+
- Other
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: checkboxes
|
|
29
|
+
id: pre_release_checks
|
|
30
|
+
attributes:
|
|
31
|
+
label: Pre-release checks
|
|
32
|
+
description: Validate the baseline before merging the release PR
|
|
33
|
+
options:
|
|
34
|
+
- label: make check passed locally
|
|
35
|
+
required: true
|
|
36
|
+
- label: No manual version bump or manual git tag was created
|
|
37
|
+
required: true
|
|
38
|
+
- label: Release-please PR was reviewed and merged to main
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: checkboxes
|
|
42
|
+
id: release_artifact_checks
|
|
43
|
+
attributes:
|
|
44
|
+
label: Release artifact checks
|
|
45
|
+
description: Confirm naming and generated artifacts
|
|
46
|
+
options:
|
|
47
|
+
- label: Git tag format is X.Y.Z (no v prefix)
|
|
48
|
+
required: true
|
|
49
|
+
- label: GitHub release title format is vX.Y.Z
|
|
50
|
+
required: true
|
|
51
|
+
- label: CHANGELOG entry exists for X.Y.Z
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
- type: checkboxes
|
|
55
|
+
id: publish_checks
|
|
56
|
+
attributes:
|
|
57
|
+
label: Publish checks
|
|
58
|
+
description: Validate publish workflow and guard settings
|
|
59
|
+
options:
|
|
60
|
+
- label: Publish workflow run succeeded for this release
|
|
61
|
+
required: true
|
|
62
|
+
- label: OIDC was used (no API token in workflow)
|
|
63
|
+
required: true
|
|
64
|
+
- label: ENABLE_PYPI_PUBLISH was intentionally set for this release path
|
|
65
|
+
required: true
|
|
66
|
+
|
|
67
|
+
- type: textarea
|
|
68
|
+
id: evidence
|
|
69
|
+
attributes:
|
|
70
|
+
label: Evidence links
|
|
71
|
+
description: Add links to PR, release page, and workflow runs
|
|
72
|
+
placeholder: |
|
|
73
|
+
- Release PR:
|
|
74
|
+
- GitHub release:
|
|
75
|
+
- Publish run:
|
|
76
|
+
- Verify run:
|
|
77
|
+
validations:
|
|
78
|
+
required: true
|
|
79
|
+
|
|
80
|
+
- type: textarea
|
|
81
|
+
id: notes
|
|
82
|
+
attributes:
|
|
83
|
+
label: Notes
|
|
84
|
+
description: Optional risks, follow-ups, or deviations
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Copilot Instructions
|
|
2
|
+
|
|
3
|
+
These instructions define how GitHub Copilot and other AI agents must operate within this repository. They are aligned with the project's architecture, ADRs, and long-term goals.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Language, Documentation, and Coding Requirements
|
|
8
|
+
|
|
9
|
+
- All comments, docstrings, and documentation must be written in clear, developer-friendly English.
|
|
10
|
+
- Use language that is easy to understand for developers of varying backgrounds.
|
|
11
|
+
- All markdown files must conform to markdown linting rules (e.g., blank lines around headings and lists, proper heading levels, no hard tabs, etc.).
|
|
12
|
+
- Keep documentation lines, comments, and docstrings concise: aim for 80 characters per line, and never exceed 120 characters per line.
|
|
13
|
+
- All code must use type hinting (type annotations) wherever possible, including function arguments, return types, and class attributes.
|
|
14
|
+
- All tests must be written using pytest (no unittest or nose). Use pytest idioms and fixtures.
|
|
15
|
+
- Prefer grouping tests in a class (e.g., TestSettings) that corresponds to the class under test.
|
|
16
|
+
|
|
17
|
+
### Docstring style
|
|
18
|
+
|
|
19
|
+
Use **Google-style docstrings** throughout. Apply the following rules:
|
|
20
|
+
|
|
21
|
+
**Summary line**
|
|
22
|
+
|
|
23
|
+
- One sentence, imperative mood, no trailing period.
|
|
24
|
+
- Must stand alone — a reader should understand the purpose without reading
|
|
25
|
+
the body.
|
|
26
|
+
- Good: `"""Return the global SObject catalog for the org."""`
|
|
27
|
+
- Avoid: `"""This method returns..."""`
|
|
28
|
+
|
|
29
|
+
**When to add `Args:` / `Returns:` / `Raises:` sections**
|
|
30
|
+
|
|
31
|
+
Only add a section when it adds information not already expressed by the type
|
|
32
|
+
hints and parameter names. Omit it when the signature is self-explanatory.
|
|
33
|
+
|
|
34
|
+
| Situation | Add section? |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| Parameter has non-trivial semantics (format, validation, side-effects) | Yes |
|
|
37
|
+
| Parameter name and type are self-explanatory | No |
|
|
38
|
+
| Return type is a typed model and the summary says what it contains | No |
|
|
39
|
+
| Return has subtle behaviour (e.g. `None` on 204, pagination semantics) | Yes |
|
|
40
|
+
| Function always raises under a specific condition | Yes (`Raises:`) |
|
|
41
|
+
| Private / internal method | No — one-liner only |
|
|
42
|
+
|
|
43
|
+
**`Args:` format**
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
Args:
|
|
47
|
+
record_id: Salesforce 15- or 18-character record ID.
|
|
48
|
+
fields: Field API names to include. Returns all fields when omitted.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- One line per parameter where possible.
|
|
52
|
+
- No Sphinx cross-references (`:class:`, `:meth:`, `:attr:`).
|
|
53
|
+
- Use plain names: `SalesforceQueryResponse`, not
|
|
54
|
+
`:class:`~plynt.connectors.salesforce.models.SalesforceQueryResponse``.
|
|
55
|
+
|
|
56
|
+
**`Returns:` format**
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
Returns:
|
|
60
|
+
Parsed query response with a ``records`` list and pagination state.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- Describe the value, not the type — the type is already in the signature.
|
|
64
|
+
- Never repeat the class name as the sole content.
|
|
65
|
+
|
|
66
|
+
**`Example::` blocks**
|
|
67
|
+
|
|
68
|
+
- Add only on public API methods where usage is non-obvious.
|
|
69
|
+
- Omit on private methods, simple getters, and one-liners.
|
|
70
|
+
- Keep examples short — 4–8 lines maximum.
|
|
71
|
+
|
|
72
|
+
**Class docstrings**
|
|
73
|
+
|
|
74
|
+
- Describe the responsibility of the class, not its constructor.
|
|
75
|
+
- Put constructor parameter docs on the class docstring, not on `__init__`.
|
|
76
|
+
- Keep `__init__` docstrings to a single line or omit them entirely.
|
|
77
|
+
|
|
78
|
+
**What to avoid**
|
|
79
|
+
|
|
80
|
+
- Sphinx cross-reference syntax (`:class:`, `:meth:`, `:attr:`, `:param:`).
|
|
81
|
+
- Restating the type hint in prose: `"Returns a str"` when `-> str` is present.
|
|
82
|
+
- Long `Returns:` blocks that copy the class definition.
|
|
83
|
+
- Docstrings on private helpers (`_method`) longer than one line.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 1. Project Intent & Scope
|
|
88
|
+
|
|
89
|
+
- Treat this repository as a framework-agnostic external API client library.
|
|
90
|
+
- Prioritize long-term reuse and architectural consistency over short-term feature delivery or local optimizations.
|
|
91
|
+
- When in doubt, defer to existing ADRs and design documentation.
|
|
92
|
+
|
|
93
|
+
## 2. Architectural Decision Records (ADRs)
|
|
94
|
+
|
|
95
|
+
- Always consult ADRs before making architectural or structural changes.
|
|
96
|
+
- Do **not** override or reinterpret an accepted ADR.
|
|
97
|
+
- If a required decision is missing or unclear:
|
|
98
|
+
- Flag the gap.
|
|
99
|
+
- Propose a new ADR instead of making assumptions.
|
|
100
|
+
- Reference ADR identifiers (e.g., ADR-003) in code comments and commit messages.
|
|
101
|
+
|
|
102
|
+
## 3. Core vs Optional Components
|
|
103
|
+
|
|
104
|
+
- Treat the core package as minimal and framework-independent.
|
|
105
|
+
- Do **not** introduce framework dependencies into the core.
|
|
106
|
+
- All framework-specific functionality must live in optional modules.
|
|
107
|
+
- Respect the modular installation model (extras such as `[django]`, `[fastapi]`, `[oauth]`).
|
|
108
|
+
- Assume users may install only a subset of the package.
|
|
109
|
+
|
|
110
|
+
## 4. Dependency Management Principles
|
|
111
|
+
|
|
112
|
+
- Keep core dependencies minimal and stable.
|
|
113
|
+
- Avoid introducing new dependencies without architectural justification.
|
|
114
|
+
- When adding a dependency:
|
|
115
|
+
- Document the rationale.
|
|
116
|
+
- Assess impact on optional installs.
|
|
117
|
+
- Reference or propose an ADR.
|
|
118
|
+
- Prefer standard library solutions when feasible.
|
|
119
|
+
|
|
120
|
+
## 5. Sync and Async Design Constraints
|
|
121
|
+
|
|
122
|
+
- Treat sync vs async as a transport concern only.
|
|
123
|
+
- Services, models, and responses must remain execution-model agnostic.
|
|
124
|
+
- Never duplicate business logic for sync and async paths.
|
|
125
|
+
- Follow documented transport abstractions.
|
|
126
|
+
|
|
127
|
+
## 6. Composition Over Inheritance
|
|
128
|
+
|
|
129
|
+
- Prefer composition, explicit objects, and small interfaces.
|
|
130
|
+
- Avoid deep inheritance hierarchies or “god base classes.”
|
|
131
|
+
- Do **not** introduce implicit behavior via magic methods.
|
|
132
|
+
- Align with documented architectural patterns.
|
|
133
|
+
|
|
134
|
+
## 7. Service Layer Responsibilities
|
|
135
|
+
|
|
136
|
+
- Services represent external domains or APIs.
|
|
137
|
+
- Services:
|
|
138
|
+
- Define endpoints.
|
|
139
|
+
- Orchestrate requests.
|
|
140
|
+
- Select response models.
|
|
141
|
+
- Services must **not**:
|
|
142
|
+
- Manage HTTP internals.
|
|
143
|
+
- Manage framework concerns.
|
|
144
|
+
- Perform I/O outside the client abstraction.
|
|
145
|
+
|
|
146
|
+
## 8. Response and Error Handling
|
|
147
|
+
|
|
148
|
+
- Centralize response parsing and error handling.
|
|
149
|
+
- Avoid leaking raw HTTP responses outside the response layer.
|
|
150
|
+
- Use typed response models consistently.
|
|
151
|
+
- Do **not** implement ad-hoc error handling inside services or frameworks.
|
|
152
|
+
|
|
153
|
+
## 9. Models and Validation
|
|
154
|
+
|
|
155
|
+
- Models are data carriers only.
|
|
156
|
+
- No business logic inside models.
|
|
157
|
+
- Models must remain framework-independent.
|
|
158
|
+
- Reuse models across services, framework adapters, and tests.
|
|
159
|
+
- Follow documented validation and serialization rules.
|
|
160
|
+
|
|
161
|
+
## 10. Authentication and Caching
|
|
162
|
+
|
|
163
|
+
- Authentication must be pluggable, optional, and non-intrusive.
|
|
164
|
+
- Do **not** hard-code authentication logic into services.
|
|
165
|
+
- Token and response caching must:
|
|
166
|
+
- Be explicitly enabled.
|
|
167
|
+
- Use abstract cache interfaces.
|
|
168
|
+
- Framework-specific caches must be implemented via adapters.
|
|
169
|
+
|
|
170
|
+
## 11. Framework Integrations
|
|
171
|
+
|
|
172
|
+
- Framework integrations (Django, FastAPI, etc.) must:
|
|
173
|
+
- Be thin adapters.
|
|
174
|
+
- Avoid duplicating core logic.
|
|
175
|
+
- Only depend on the core through public interfaces.
|
|
176
|
+
- No framework assumptions may leak back into the core.
|
|
177
|
+
|
|
178
|
+
## 12. Testing and Mocking Expectations
|
|
179
|
+
|
|
180
|
+
- Design all code to be testable without real network calls.
|
|
181
|
+
- Avoid global state and singletons.
|
|
182
|
+
- Prefer HTTP-level mocking over service stubbing.
|
|
183
|
+
- Follow documented testing conventions and tooling.
|
|
184
|
+
|
|
185
|
+
## 13. Documentation-Driven Development
|
|
186
|
+
|
|
187
|
+
- When behavior is unclear:
|
|
188
|
+
- Search for existing documentation.
|
|
189
|
+
- Reference ADRs, README, or design docs.
|
|
190
|
+
- If documentation is missing or outdated:
|
|
191
|
+
- Note the discrepancy.
|
|
192
|
+
- Suggest documentation updates.
|
|
193
|
+
- Do **not** “invent” undocumented behavior.
|
|
194
|
+
|
|
195
|
+
## 14. Code Generation & Refactoring Behavior
|
|
196
|
+
|
|
197
|
+
- Favor small, incremental changes.
|
|
198
|
+
- Keep changes aligned with existing patterns.
|
|
199
|
+
- Avoid large refactors without architectural context.
|
|
200
|
+
- Always preserve backward compatibility unless explicitly instructed otherwise.
|
|
201
|
+
|
|
202
|
+
## 15. Decision Escalation Rules
|
|
203
|
+
|
|
204
|
+
- If a change impacts:
|
|
205
|
+
- Public APIs
|
|
206
|
+
- Dependency structure
|
|
207
|
+
- Installation model
|
|
208
|
+
- Core abstractions
|
|
209
|
+
→ Stop and request an architectural decision.
|
|
210
|
+
- Do **not** silently introduce breaking changes.
|
|
211
|
+
|
|
212
|
+
## 16. Branch Workflow Safety
|
|
213
|
+
|
|
214
|
+
- Do **not** commit directly to `main` or `master` unless the user explicitly
|
|
215
|
+
approves this in the current conversation.
|
|
216
|
+
- Implement new functionality on a dedicated branch first.
|
|
217
|
+
- Before starting work on a branch name, check whether that branch already
|
|
218
|
+
exists on the remote and whether it has already been merged.
|
|
219
|
+
- If a branch has already been merged remotely, do not reuse it for new work;
|
|
220
|
+
create a new branch.
|
|
221
|
+
|
|
222
|
+
## 17. Repo Operating Profile
|
|
223
|
+
|
|
224
|
+
Use this profile for day-to-day implementation decisions in this repository.
|
|
225
|
+
|
|
226
|
+
### 17.1 Source Boundaries
|
|
227
|
+
|
|
228
|
+
- Core framework-agnostic code lives in `src/plynt/base`, `src/plynt/http`,
|
|
229
|
+
`src/plynt/middleware`, and `src/plynt/cache`.
|
|
230
|
+
- Connector-specific code lives under `src/plynt/connectors/*`.
|
|
231
|
+
- `src/plynt/connectors/salesforce` is the active validation connector.
|
|
232
|
+
- Keep connector-to-connector dependencies out of scope.
|
|
233
|
+
- If shared behavior is needed, move it to a neutral core abstraction.
|
|
234
|
+
|
|
235
|
+
### 17.2 Canonical Local Commands
|
|
236
|
+
|
|
237
|
+
- Bootstrap: `make install`
|
|
238
|
+
- Full local gate: `make check`
|
|
239
|
+
- Lint only: `make lint`
|
|
240
|
+
- Tests only: `make unittests`
|
|
241
|
+
- Full test matrix: `make test-all`
|
|
242
|
+
- Coverage report: `make coverage`
|
|
243
|
+
|
|
244
|
+
When validating focused changes, prefer targeted pytest runs first, then run
|
|
245
|
+
`make check` before final handoff.
|
|
246
|
+
|
|
247
|
+
### 17.3 Testing Conventions
|
|
248
|
+
|
|
249
|
+
- Use pytest test classes that map to the unit under test where practical.
|
|
250
|
+
- Prefer HTTP-level mocking over service stubbing.
|
|
251
|
+
- Keep tests deterministic and avoid time- or network-dependent flakiness.
|
|
252
|
+
- For connector additions, maintain sync and async parity in both code and
|
|
253
|
+
tests.
|
|
254
|
+
|
|
255
|
+
### 17.4 AI Connector Track Rules
|
|
256
|
+
|
|
257
|
+
- `plynt.connectors.llm` and Salesforce AI services may progress in parallel.
|
|
258
|
+
- Do not make the LLM connector depend on Salesforce internals.
|
|
259
|
+
- Do not make Salesforce AI services depend on `plynt.connectors.llm`.
|
|
260
|
+
- Share only transport, streaming, middleware, and typed core abstractions.
|
|
261
|
+
|
|
262
|
+
### 17.5 ADR Trigger Checklist
|
|
263
|
+
|
|
264
|
+
Stop and request an ADR before implementation if the change affects:
|
|
265
|
+
|
|
266
|
+
- Public API shape or compatibility promises
|
|
267
|
+
- Dependency model (including new runtime dependencies)
|
|
268
|
+
- Installation extras or package extraction boundaries
|
|
269
|
+
- Transport contracts (HTTP, streaming, gRPC, SOAP)
|
|
270
|
+
- Core abstraction responsibilities across layers
|
|
271
|
+
|
|
272
|
+
### 17.6 Local Tooling Artifacts
|
|
273
|
+
|
|
274
|
+
- Local vstack artifacts may exist for developer workflow support.
|
|
275
|
+
- Do not commit local-only generated vstack artifacts unless explicitly
|
|
276
|
+
requested for repository governance.
|
|
277
|
+
- Keep `.gitignore` aligned so local vstack output stays out of commits by
|
|
278
|
+
default.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 🧭 Meta-Instruction for Copilot and AI Agents
|
|
283
|
+
|
|
284
|
+
- Act as an architectural contributor, not just a code generator.
|
|
285
|
+
- Prefer referencing decisions, documentation, and constraints over guessing intent.
|
|
286
|
+
- When uncertain, surface questions and propose ADRs instead of making assumptions.
|
|
287
|
+
|
|
288
|
+
### Python file/module naming conventions
|
|
289
|
+
|
|
290
|
+
- Use the singular form for modules (files) that define a single main concept (e.g., `request.py`, `response.py`, `client.py`).
|
|
291
|
+
- Use the plural form for modules that contain a collection of related objects or utilities (e.g., `errors.py`, `settings.py`, `utils.py`).
|
|
292
|
+
- Classes are always singular (e.g., `Request`, `Response`, `User`).
|
|
293
|
+
- Packages (folders) are usually plural if they contain a collection (e.g., `models`, `services`), but singular is allowed if it fits the domain.
|
|
294
|
+
- Follow the conventions of the Python standard library and popular frameworks for consistency.
|
|
295
|
+
|
|
296
|
+
> Example: `request.py` and `response.py` for single data carriers; `errors.py` for multiple error types.
|
|
297
|
+
|
|
298
|
+
### Class naming length and consistency
|
|
299
|
+
|
|
300
|
+
- Before naming a new public class, check sibling classes already exported in
|
|
301
|
+
the same module's `__all__` and follow their established
|
|
302
|
+
`<Adjective><Domain><Concept>` pattern instead of inventing a new shape.
|
|
303
|
+
- Avoid redundant words that repeat what a wrapped protocol or base type
|
|
304
|
+
already conveys (e.g. prefer `CacheSalesforceCDCCheckpointStore` over
|
|
305
|
+
`CacheBackendSalesforceCDCCheckpointStore` when the sibling
|
|
306
|
+
`InMemorySalesforceCDCCheckpointStore` already sets the pattern).
|
|
307
|
+
- Renaming an already-exported public symbol touches the defining module, the
|
|
308
|
+
package `__init__.py` (import and `__all__`), tests, and any docs/how-to
|
|
309
|
+
examples referencing it. Grep the repository for the old name before
|
|
310
|
+
declaring a rename complete.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
assignees:
|
|
8
|
+
- "eschaar"
|
|
9
|
+
open-pull-requests-limit: 5
|
|
10
|
+
labels:
|
|
11
|
+
- "dependencies"
|
|
12
|
+
- "python"
|
|
13
|
+
commit-message:
|
|
14
|
+
prefix: "chore(deps)"
|
|
15
|
+
groups:
|
|
16
|
+
pip-patch-minor:
|
|
17
|
+
patterns:
|
|
18
|
+
- "*"
|
|
19
|
+
update-types:
|
|
20
|
+
- "patch"
|
|
21
|
+
- "minor"
|
|
22
|
+
|
|
23
|
+
- package-ecosystem: "github-actions"
|
|
24
|
+
directory: "/"
|
|
25
|
+
schedule:
|
|
26
|
+
interval: "daily"
|
|
27
|
+
assignees:
|
|
28
|
+
- "eschaar"
|
|
29
|
+
open-pull-requests-limit: 5
|
|
30
|
+
labels:
|
|
31
|
+
- "dependencies"
|
|
32
|
+
- "github-actions"
|
|
33
|
+
commit-message:
|
|
34
|
+
prefix: "chore(ci)"
|
|
35
|
+
groups:
|
|
36
|
+
gha-patch-minor:
|
|
37
|
+
patterns:
|
|
38
|
+
- "*"
|
|
39
|
+
update-types:
|
|
40
|
+
- "patch"
|
|
41
|
+
- "minor"
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Automerge workflow.
|
|
2
|
+
# Purpose: automatically merge safe Dependabot pull requests without manual review.
|
|
3
|
+
# Policy: auto-merge is enabled for:
|
|
4
|
+
# - github-actions ecosystem: patch and minor version updates
|
|
5
|
+
# - pip ecosystem: patch version updates only
|
|
6
|
+
# Major version bumps and non-Dependabot PRs are never auto-merged.
|
|
7
|
+
# Requires the repository setting "Allow auto-merge" to be enabled.
|
|
8
|
+
name: "Dependabot Safe Auto-merge for Patch and Minor Updates"
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
pull_request_target:
|
|
12
|
+
branches:
|
|
13
|
+
- main
|
|
14
|
+
types:
|
|
15
|
+
- opened
|
|
16
|
+
- synchronize
|
|
17
|
+
- reopened
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: write
|
|
21
|
+
pull-requests: write
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
auto-merge:
|
|
25
|
+
if: github.actor == 'dependabot[bot]'
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Fetch Dependabot metadata
|
|
30
|
+
id: metadata
|
|
31
|
+
uses: dependabot/fetch-metadata@v3
|
|
32
|
+
with:
|
|
33
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
34
|
+
|
|
35
|
+
- name: Decide if this PR is eligible
|
|
36
|
+
id: decision
|
|
37
|
+
env:
|
|
38
|
+
PACKAGE_ECOSYSTEM: ${{ steps.metadata.outputs.package-ecosystem }}
|
|
39
|
+
UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }}
|
|
40
|
+
run: |
|
|
41
|
+
should_automerge=false
|
|
42
|
+
|
|
43
|
+
if [[ "$PACKAGE_ECOSYSTEM" == "github-actions" ]]; then
|
|
44
|
+
if [[ "$UPDATE_TYPE" == "version-update:semver-patch" || "$UPDATE_TYPE" == "version-update:semver-minor" ]]; then
|
|
45
|
+
should_automerge=true
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [[ "$PACKAGE_ECOSYSTEM" == "pip" ]]; then
|
|
50
|
+
if [[ "$UPDATE_TYPE" == "version-update:semver-patch" ]]; then
|
|
51
|
+
should_automerge=true
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
echo "should_automerge=$should_automerge" >> "$GITHUB_OUTPUT"
|
|
56
|
+
echo "package_ecosystem=$PACKAGE_ECOSYSTEM" >> "$GITHUB_OUTPUT"
|
|
57
|
+
echo "update_type=$UPDATE_TYPE" >> "$GITHUB_OUTPUT"
|
|
58
|
+
|
|
59
|
+
- name: Approve eligible PR
|
|
60
|
+
if: steps.decision.outputs.should_automerge == 'true'
|
|
61
|
+
uses: actions/github-script@v9
|
|
62
|
+
with:
|
|
63
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
64
|
+
script: |
|
|
65
|
+
await github.rest.pulls.createReview({
|
|
66
|
+
owner: context.repo.owner,
|
|
67
|
+
repo: context.repo.repo,
|
|
68
|
+
pull_number: context.payload.pull_request.number,
|
|
69
|
+
event: "APPROVE",
|
|
70
|
+
body: "Auto-approved for safe Dependabot update policy."
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
- name: Update branch for eligible PR
|
|
74
|
+
if: steps.decision.outputs.should_automerge == 'true'
|
|
75
|
+
uses: actions/github-script@v9
|
|
76
|
+
with:
|
|
77
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
78
|
+
script: |
|
|
79
|
+
// Intentional strategy:
|
|
80
|
+
// - Always request an update for eligible PRs instead of pre-checking merge state.
|
|
81
|
+
// - GitHub may report transient/unknown merge state during event handling.
|
|
82
|
+
// - updateBranch is idempotent; if already current, GitHub returns a benign 422/no-op.
|
|
83
|
+
// This keeps automerge flow deterministic without relying on flaky preconditions.
|
|
84
|
+
try {
|
|
85
|
+
await github.rest.pulls.updateBranch({
|
|
86
|
+
owner: context.repo.owner,
|
|
87
|
+
repo: context.repo.repo,
|
|
88
|
+
pull_number: context.payload.pull_request.number
|
|
89
|
+
})
|
|
90
|
+
core.info("Requested branch update from base branch.")
|
|
91
|
+
} catch (error) {
|
|
92
|
+
const msg = String(error.message || "")
|
|
93
|
+
if (error.status === 422 || msg.includes("not behind")) {
|
|
94
|
+
// Expected no-op path when branch is already up to date.
|
|
95
|
+
core.info("Branch already up to date; continuing.")
|
|
96
|
+
} else {
|
|
97
|
+
core.setFailed("Could not update branch before automerge. " + msg)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- name: Enable auto-merge for eligible PR
|
|
102
|
+
if: steps.decision.outputs.should_automerge == 'true'
|
|
103
|
+
uses: actions/github-script@v9
|
|
104
|
+
with:
|
|
105
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
106
|
+
script: |
|
|
107
|
+
try {
|
|
108
|
+
await github.graphql(
|
|
109
|
+
`mutation($pullRequestId: ID!) {
|
|
110
|
+
enablePullRequestAutoMerge(input: {pullRequestId: $pullRequestId, mergeMethod: SQUASH}) {
|
|
111
|
+
pullRequest { number }
|
|
112
|
+
}
|
|
113
|
+
}`,
|
|
114
|
+
{ pullRequestId: context.payload.pull_request.node_id }
|
|
115
|
+
)
|
|
116
|
+
} catch (error) {
|
|
117
|
+
core.setFailed(
|
|
118
|
+
"Could not enable auto-merge. Ensure repository auto-merge is enabled and branch protections are satisfied.\n" +
|
|
119
|
+
error.message
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
- name: Log skipped PR
|
|
124
|
+
if: steps.decision.outputs.should_automerge != 'true'
|
|
125
|
+
run: |
|
|
126
|
+
echo "Automerge skipped by policy."
|
|
127
|
+
echo "ecosystem=${{ steps.decision.outputs.package_ecosystem }}"
|
|
128
|
+
echo "update_type=${{ steps.decision.outputs.update_type }}"
|