amsdal_cli 0.5.2__tar.gz → 0.5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/.gitignore +1 -0
- amsdal_cli-0.5.3/.junie/guidelines.md +102 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/PKG-INFO +2 -1
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/change-logs.md +6 -0
- amsdal_cli-0.5.3/latest-changelogs.md +5 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/pyproject.toml +47 -38
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/__about__.py +1 -1
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/command.py +118 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/config.py +192 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/data_classes.py +13 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/operation_log.py +78 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services/comparison.py +47 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services/data_factory.py +158 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services/loader.py +11 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services/runner.py +499 -0
- amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services/storage.py +12 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/services/mixin.py +2 -2
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/callbacks.py +1 -1
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/type_utils.py +3 -3
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/sub_commands/apply.py +6 -44
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/sub_commands/list.py +26 -25
- amsdal_cli-0.5.3/src/amsdal_cli/commands/migrations/utils.py +86 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/serve/utils.py +1 -1
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/worker/sub_commands/run.py +2 -2
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/config/main.py +1 -0
- amsdal_cli-0.5.3/src/amsdal_cli/py.typed +0 -0
- amsdal_cli-0.5.3/src/amsdal_cli/utils/__init__.py +0 -0
- amsdal_cli-0.5.3/uv.lock +1854 -0
- amsdal_cli-0.5.2/latest-changelogs.md +0 -5
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/.editorconfig +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/CONTRIBUTING.md +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/LICENSE.txt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/README.md +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/license_check.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/release_notes/.gitkeep +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/scripts/release.sh +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/scripts/tag_check.sh +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/Third-Party Materials - AMSDAL Dependencies - License Notices.md +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/__init__.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build → amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check}/__init__.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas → amsdal_cli-0.5.3/src/amsdal_cli/commands/api_check/services}/__init__.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas/data_models → amsdal_cli-0.5.3/src/amsdal_cli/commands/build}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/constants.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas/extenders → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas}/__init__.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas/loaders → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas/data_models}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/data_models/custom_code.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/data_models/options.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/data_models/schemas_directory.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas/mixins → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas/extenders}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/extenders/custom_code_extender.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/extenders/options_extender.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/schemas/utils → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas/loaders}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/base.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/cli_custom_code_loader.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/cli_loader.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/cli_options_loader.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/cli_statics_loader.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/cli_transactions_loader.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/loaders/utils.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build/services → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas/mixins}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/mixins/enrich_schemas_mixin.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/schema_json_loader.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/build → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/schemas}/utils/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/schemas/utils/merger.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/ci_cd → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/services}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/services/builder.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/clean → amsdal_cli-0.5.3/src/amsdal_cli/commands/build/utils}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/build/utils/build_config_file.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud → amsdal_cli-0.5.3/src/amsdal_cli/commands/ci_cd}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/ci_cd/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/ci_cd/constants.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/ci_cd/templates/github.yml +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/dependency → amsdal_cli-0.5.3/src/amsdal_cli/commands/clean}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/clean/command.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/deploy → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/command.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/environments → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/dependency}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/sub_commands/dependency_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/sub_commands/dependency_list.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/dependency/sub_commands/dependency_new.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/secret → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/deploy}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/sub_commands/deploy_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/sub_commands/deploy_list.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/deploy/sub_commands/deploy_new.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/enums.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/security → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/environments}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/constants.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/sub_commands/env_checkout.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/sub_commands/env_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/sub_commands/env_list.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/sub_commands/env_new.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/environments/utils.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/security/allowlist → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/secret}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/constants.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/sub_commands/secret_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/sub_commands/secret_list.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/secret/sub_commands/secret_new.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/cloud/security/basic_auth → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/security}/__init__.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/generate → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/security/allowlist}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/allowlist/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/allowlist/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/allowlist/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/allowlist/sub_commands/allowlist_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/allowlist/sub_commands/allowlist_new.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/app.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/generate/utils → amsdal_cli-0.5.3/src/amsdal_cli/commands/cloud/security/basic_auth}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/sub_commands/basic_auth_delete.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/sub_commands/basic_auth_new.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/basic_auth/sub_commands/basic_auth_retrieve.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/security/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/sub_commands/expose_db.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/sub_commands/get_monitoring_info.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/cloud/sub_commands/sync_db.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/generate/utils/tests → amsdal_cli-0.5.3/src/amsdal_cli/commands/generate}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/enums.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_frontend_config.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_hook.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_model.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_modifier.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_permission.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_property.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_tests.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/sub_commands/generate_transaction.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/async_transaction.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/hook.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/modifier/constructor.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/modifier/display_name.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/modifier/version_name.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/property.pyt +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/templates/transaction.pyt +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/migrations → amsdal_cli-0.5.3/src/amsdal_cli/commands/generate/utils}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/build_base_path.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/cast_to_attribute_type.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/model_attributes.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/new → amsdal_cli-0.5.3/src/amsdal_cli/commands/generate/utils/tests}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/async_mode_utils.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/conftest_utils.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/function_utils.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/model_utils.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/templates/async/conftest.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/templates/sync/conftest.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/generate/utils/tests/unit.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/register_connection → amsdal_cli-0.5.3/src/amsdal_cli/commands/migrations}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/constants.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/sub_commands/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/migrations/sub_commands/make.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/register_connection/utils → amsdal_cli-0.5.3/src/amsdal_cli/commands/new}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/.amsdal/.dependencies +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/.amsdal/.environment +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/.amsdal/.secrets +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/.amsdal-cli +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/.gitignore +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/README.md +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/config.yml +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/new/templates/requirements.txt +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/restore → amsdal_cli-0.5.3/src/amsdal_cli/commands/register_connection}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/command.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/serve → amsdal_cli-0.5.3/src/amsdal_cli/commands/register_connection/utils}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/build.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/config_updater.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/credentials.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/initialize.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/meta.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/migrate_models.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/model_generator.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/register_connection/utils/tables.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/serve/filters → amsdal_cli-0.5.3/src/amsdal_cli/commands/restore}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/restore/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/restore/enums.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/serve/services → amsdal_cli-0.5.3/src/amsdal_cli/commands/serve}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/serve/command.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/tests → amsdal_cli-0.5.3/src/amsdal_cli/commands/serve/filters}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/serve/filters/models_watch_filter.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/serve/filters/static_files_watch_filter.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/verify → amsdal_cli-0.5.3/src/amsdal_cli/commands/serve/services}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/serve/services/supervisor.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/verify/utils → amsdal_cli-0.5.3/src/amsdal_cli/commands/tests}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/tests/command.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/commands/worker → amsdal_cli-0.5.3/src/amsdal_cli/commands/verify}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/verify/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/verify/models.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/config → amsdal_cli-0.5.3/src/amsdal_cli/commands/verify/utils}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/verify/utils/verify_json_model.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/verify/utils/verify_python_file.py +0 -0
- {amsdal_cli-0.5.2/src/amsdal_cli/utils → amsdal_cli-0.5.3/src/amsdal_cli/commands/worker}/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/worker/app.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/worker/command.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/commands/worker/sub_commands/__init__.py +0 -0
- /amsdal_cli-0.5.2/src/amsdal_cli/py.typed → /amsdal_cli-0.5.3/src/amsdal_cli/config/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/main.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/alias_group.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/check_versions.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/cli_config.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/copier.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/markdown_patch.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/render_template.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/schema_repository.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/text.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/vcs/__init__.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/vcs/base.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/vcs/dummy.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/vcs/enums.py +0 -0
- {amsdal_cli-0.5.2 → amsdal_cli-0.5.3}/src/amsdal_cli/utils/vcs/git.py +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Project Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
AMSDAL CLI is a command-line interface for the AMSDAL (A. Michael Salem Data Access Layer) framework. It provides tools for managing AMSDAL applications, including:
|
|
6
|
+
|
|
7
|
+
- Generating code from models
|
|
8
|
+
- Running a development server
|
|
9
|
+
- Managing migrations
|
|
10
|
+
- Testing and verification
|
|
11
|
+
- Cloud integration
|
|
12
|
+
|
|
13
|
+
The project is structured as follows:
|
|
14
|
+
|
|
15
|
+
- `src/amsdal_cli/` - Main source code
|
|
16
|
+
- `commands/` - CLI commands implementation
|
|
17
|
+
- `config/` - Configuration management
|
|
18
|
+
- `utils/` - Utility functions and helpers
|
|
19
|
+
- `tests/` - Test suite
|
|
20
|
+
- `async/` - Asynchronous tests
|
|
21
|
+
- `e2e/` - End-to-end tests
|
|
22
|
+
- `fixtures/` - Test fixtures
|
|
23
|
+
- `sync/` - Synchronous tests
|
|
24
|
+
|
|
25
|
+
The CLI is built using Typer and follows a command-based structure with subcommands organized in modules.
|
|
26
|
+
|
|
27
|
+
## Code Style Guide
|
|
28
|
+
|
|
29
|
+
### Python Version
|
|
30
|
+
- Target Python version: 3.11+
|
|
31
|
+
- Code should be compatible with Python 3.10+ for development
|
|
32
|
+
|
|
33
|
+
### Formatting
|
|
34
|
+
- Line length: 120 characters
|
|
35
|
+
- Use Black for code formatting
|
|
36
|
+
- Use single quotes for strings, except for docstrings which use double quotes
|
|
37
|
+
- Imports should be on separate lines (no multi-imports)
|
|
38
|
+
- Imports should be ordered by type (standard library, third-party, first-party)
|
|
39
|
+
|
|
40
|
+
### Type Annotations
|
|
41
|
+
- All code must use type annotations
|
|
42
|
+
- Use `typing.TYPE_CHECKING` for import-only type dependencies
|
|
43
|
+
- Follow strict mypy rules:
|
|
44
|
+
- No implicit reexports
|
|
45
|
+
- Disallow untyped definitions
|
|
46
|
+
- Disallow any generics
|
|
47
|
+
- Check untyped definitions
|
|
48
|
+
|
|
49
|
+
### Linting
|
|
50
|
+
- Use Ruff for linting with the following rule sets enabled:
|
|
51
|
+
- A: flake8-builtins
|
|
52
|
+
- ARG: flake8-unused-arguments
|
|
53
|
+
- B: flake8-bugbear
|
|
54
|
+
- C: flake8-comprehensions
|
|
55
|
+
- DTZ: flake8-datetimez
|
|
56
|
+
- E: pycodestyle errors
|
|
57
|
+
- EM: flake8-errmsg
|
|
58
|
+
- F: pyflakes
|
|
59
|
+
- FBT: flake8-boolean-trap
|
|
60
|
+
- I: isort
|
|
61
|
+
- ICN: flake8-import-conventions
|
|
62
|
+
- ISC: flake8-implicit-str-concat
|
|
63
|
+
- N: pep8-naming
|
|
64
|
+
- PLC, PLE, PLR, PLW: pylint
|
|
65
|
+
- Q: flake8-quotes
|
|
66
|
+
- RUF: Ruff-specific rules
|
|
67
|
+
- S: flake8-bandit
|
|
68
|
+
- T: flake8-debugger
|
|
69
|
+
- TID: flake8-tidy-imports
|
|
70
|
+
- UP: pyupgrade
|
|
71
|
+
- W: pycodestyle warnings
|
|
72
|
+
- YTT: flake8-2020
|
|
73
|
+
|
|
74
|
+
### Imports
|
|
75
|
+
- No relative imports
|
|
76
|
+
- Group imports by source (standard library, third-party, first-party)
|
|
77
|
+
- Known first-party modules: amsdal_cli
|
|
78
|
+
|
|
79
|
+
### Documentation
|
|
80
|
+
- Use docstrings for functions, classes, and modules
|
|
81
|
+
- Use markdown formatting in docstrings
|
|
82
|
+
- Include help text for CLI commands and options
|
|
83
|
+
|
|
84
|
+
### Testing
|
|
85
|
+
- Write tests for all functionality
|
|
86
|
+
- Use pytest for testing
|
|
87
|
+
- Include both synchronous and asynchronous tests where appropriate
|
|
88
|
+
- Use fixtures for test data
|
|
89
|
+
- Aim for high test coverage
|
|
90
|
+
|
|
91
|
+
### Error Handling
|
|
92
|
+
- Use appropriate exception handling with try/except/finally blocks
|
|
93
|
+
- Properly clean up resources in finally blocks
|
|
94
|
+
|
|
95
|
+
### Asynchronous Code
|
|
96
|
+
- Support both synchronous and asynchronous execution paths where needed
|
|
97
|
+
- Use asyncio for asynchronous code
|
|
98
|
+
- Follow asyncio best practices
|
|
99
|
+
|
|
100
|
+
### Version Control
|
|
101
|
+
- Use towncrier for managing release notes
|
|
102
|
+
- Organize changes by type (security, removed, deprecated, added, changed, fixed, performance)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amsdal_cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: CLI for AMSDAL framework
|
|
5
5
|
Project-URL: Documentation, https://pypi.org/project/amsdal_cli/#readme
|
|
6
6
|
Project-URL: Issues, https://pypi.org/project/amsdal_cli/
|
|
@@ -125,6 +125,7 @@ Requires-Dist: amsdal-server==0.5.*
|
|
|
125
125
|
Requires-Dist: click<8.2.0
|
|
126
126
|
Requires-Dist: faker==27.*
|
|
127
127
|
Requires-Dist: gitpython~=3.1
|
|
128
|
+
Requires-Dist: httpx==0.28.*
|
|
128
129
|
Requires-Dist: jinja2~=3.1
|
|
129
130
|
Requires-Dist: pydantic-settings~=2.2
|
|
130
131
|
Requires-Dist: pydantic~=2.3
|
|
@@ -41,6 +41,32 @@ dependencies = [
|
|
|
41
41
|
"GitPython~=3.1",
|
|
42
42
|
"amsdal-server==0.5.*",
|
|
43
43
|
"faker==27.*",
|
|
44
|
+
"httpx==0.28.*",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[dependency-groups]
|
|
48
|
+
dev = [
|
|
49
|
+
"amsdal[async-sqlite]",
|
|
50
|
+
"amsdal[postgres-binary]",
|
|
51
|
+
"coverage[toml]>=7.4",
|
|
52
|
+
"pytest-cov>=6.0.0",
|
|
53
|
+
"pytest==8.4.1",
|
|
54
|
+
"pytest-mock==3.14.1",
|
|
55
|
+
"pytest-asyncio>=1.1.0",
|
|
56
|
+
"pytest-xdist[psutil]>=3.8.0",
|
|
57
|
+
"black>=24.3.0",
|
|
58
|
+
"mypy>=1.17.0",
|
|
59
|
+
"ruff>=0.12.4",
|
|
60
|
+
"towncrier==23.11.0",
|
|
61
|
+
"types-ujson",
|
|
62
|
+
"types-PyYAML",
|
|
63
|
+
"types-pytz",
|
|
64
|
+
"types-pexpect",
|
|
65
|
+
"types-docutils",
|
|
66
|
+
"types-defusedxml",
|
|
67
|
+
"types-colorama",
|
|
68
|
+
"types-Pygments",
|
|
69
|
+
"pandas-stubs",
|
|
44
70
|
]
|
|
45
71
|
|
|
46
72
|
[tool.hatch.envs.default.env-vars]
|
|
@@ -61,25 +87,16 @@ allow-direct-references = true
|
|
|
61
87
|
path = "src/amsdal_cli/__about__.py"
|
|
62
88
|
|
|
63
89
|
[[tool.hatch.envs.all.matrix]]
|
|
64
|
-
python = ["3.
|
|
90
|
+
python = ["3.11", "3.12"]
|
|
65
91
|
|
|
66
92
|
[tool.hatch.envs.default]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"coverage[toml]>=7.4",
|
|
70
|
-
"pytest-cov>=6.0.0",
|
|
71
|
-
"pytest==8.3.4",
|
|
72
|
-
"pytest-mock==3.14.0",
|
|
73
|
-
"pytest-asyncio>=0.25.3",
|
|
74
|
-
"pytest-xdist[psutil]>=3.6.1",
|
|
75
|
-
"black>=24.3.0",
|
|
76
|
-
"mypy>=1.15.0",
|
|
77
|
-
"ruff>=0.11.0",
|
|
78
|
-
"towncrier==23.11.0",
|
|
79
|
-
"aiosqlite",
|
|
80
|
-
]
|
|
93
|
+
installer = "uv"
|
|
94
|
+
path = ".venv"
|
|
81
95
|
|
|
82
96
|
[tool.hatch.envs.default.scripts]
|
|
97
|
+
sync = "uv sync --group dev"
|
|
98
|
+
lock = "uv lock"
|
|
99
|
+
lock-upgrade = "uv lock --upgrade"
|
|
83
100
|
test = "pytest -n auto {args:tests}"
|
|
84
101
|
test-single = "pytest -vvv {args:tests}"
|
|
85
102
|
test-cov = "pytest -n auto --cov=src {args:tests}"
|
|
@@ -107,31 +124,23 @@ release = "rm latest-changelogs.md && towncrier build --yes --version {args:vers
|
|
|
107
124
|
COLUMNS = "200"
|
|
108
125
|
|
|
109
126
|
[tool.hatch.envs.local]
|
|
110
|
-
|
|
111
|
-
path = "
|
|
112
|
-
dependencies = [
|
|
113
|
-
"pytest-cov>=6.0.0",
|
|
114
|
-
"pytest==8.3.4",
|
|
115
|
-
"pytest-mock==3.14.0",
|
|
116
|
-
"pytest-asyncio>=0.25.3",
|
|
117
|
-
"pytest-xdist[psutil]>=3.6.1",
|
|
118
|
-
"black>=24.3.0",
|
|
119
|
-
"mypy>=1.15.0",
|
|
120
|
-
"ruff>=0.11.0",
|
|
121
|
-
"aiosqlite",
|
|
122
|
-
]
|
|
127
|
+
installer = "uv"
|
|
128
|
+
path = ".venv"
|
|
123
129
|
pre-install-commands = [
|
|
124
|
-
"pip install -e ../amsdal-glue/libs/core/",
|
|
125
|
-
"pip install -e ../amsdal-glue/libs/connections/
|
|
126
|
-
"pip install -e ../amsdal-glue/libs/amsdal-glue/",
|
|
127
|
-
"pip install -e ../amsdal_utils/",
|
|
128
|
-
"pip install -e ../amsdal_data/",
|
|
129
|
-
"pip install -e ../amsdal_models/",
|
|
130
|
-
"pip install -e ../amsdal_framework/",
|
|
131
|
-
"pip install -e ../amsdal_server/",
|
|
130
|
+
"uv pip install -e ../amsdal-glue/libs/core/",
|
|
131
|
+
"uv pip install -e ../amsdal-glue/libs/connections/",
|
|
132
|
+
"uv pip install -e ../amsdal-glue/libs/amsdal-glue/",
|
|
133
|
+
"uv pip install -e ../amsdal_utils/",
|
|
134
|
+
"uv pip install -e ../amsdal_data/",
|
|
135
|
+
"uv pip install -e ../amsdal_models/",
|
|
136
|
+
"uv pip install -e ../amsdal_framework/",
|
|
137
|
+
"uv pip install -e ../amsdal_server/",
|
|
132
138
|
]
|
|
133
139
|
|
|
134
140
|
[tool.hatch.envs.local.scripts]
|
|
141
|
+
sync = "uv sync --group dev"
|
|
142
|
+
lock = "uv lock"
|
|
143
|
+
lock-upgrade = "uv lock --upgrade"
|
|
135
144
|
test = "pytest -n auto {args:tests}"
|
|
136
145
|
test-single = "pytest -vvv {args:tests}"
|
|
137
146
|
test-cov = "pytest -n auto --cov=src {args:tests}"
|
|
@@ -155,10 +164,10 @@ all = [
|
|
|
155
164
|
|
|
156
165
|
|
|
157
166
|
[tool.black]
|
|
158
|
-
target-version = ["
|
|
167
|
+
target-version = ["py311"]
|
|
159
168
|
line-length = 120
|
|
160
169
|
skip-string-normalization = true
|
|
161
|
-
exclude = "tests/fixtures
|
|
170
|
+
exclude = "tests/fixtures/*|.venv"
|
|
162
171
|
|
|
163
172
|
[tool.mypy]
|
|
164
173
|
plugins = ["pydantic.mypy"]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from amsdal_cli.app import app
|
|
7
|
+
from amsdal_cli.commands.api_check.config import ApiCheckConfig
|
|
8
|
+
from amsdal_cli.commands.api_check.services.comparison import check
|
|
9
|
+
from amsdal_cli.commands.api_check.services.loader import load_operation_logs
|
|
10
|
+
from amsdal_cli.commands.api_check.services.runner import ApiRunner
|
|
11
|
+
from amsdal_cli.commands.api_check.services.storage import save
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command(name='api-check')
|
|
15
|
+
def api_check(
|
|
16
|
+
target_url: str = typer.Argument( # noqa: B008
|
|
17
|
+
...,
|
|
18
|
+
help='Target API base URL to test',
|
|
19
|
+
),
|
|
20
|
+
config_file: Path = typer.Option( # noqa: B008
|
|
21
|
+
Path('api-check-config.json'),
|
|
22
|
+
'--config',
|
|
23
|
+
'-c',
|
|
24
|
+
help='Path to configuration file (YAML or JSON) with test cases and auth settings',
|
|
25
|
+
exists=True,
|
|
26
|
+
),
|
|
27
|
+
compare_url: Optional[str] = typer.Option( # noqa: B008
|
|
28
|
+
None,
|
|
29
|
+
'--compare-url',
|
|
30
|
+
help='Second API base URL to compare against',
|
|
31
|
+
),
|
|
32
|
+
compare_logs: Optional[Path] = typer.Option( # noqa: B008
|
|
33
|
+
None,
|
|
34
|
+
'--compare-logs',
|
|
35
|
+
help='Path to existing logs file to compare against',
|
|
36
|
+
exists=True,
|
|
37
|
+
),
|
|
38
|
+
output_logs: Optional[Path] = typer.Option( # noqa: B008
|
|
39
|
+
None,
|
|
40
|
+
'--output',
|
|
41
|
+
'-o',
|
|
42
|
+
help='Path to save output logs',
|
|
43
|
+
),
|
|
44
|
+
) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Run API tests against target URL and compare results with another endpoint or saved logs.
|
|
47
|
+
|
|
48
|
+
The command requires a configuration file (in YAML or JSON format) that defines:
|
|
49
|
+
- Test cases with inputs and expected outputs
|
|
50
|
+
- Authentication settings
|
|
51
|
+
- Endpoints to test
|
|
52
|
+
|
|
53
|
+
Authentication can be configured using environment variables:
|
|
54
|
+
- AMSDAL_API_CHECK_AUTHORIZATION: Authorization token
|
|
55
|
+
- AMSDAL_API_CHECK_EMAIL: Email for authentication
|
|
56
|
+
- AMSDAL_API_CHECK_PASSWORD: Password for authentication
|
|
57
|
+
|
|
58
|
+
If the token is invalid and no credentials are provided, the command will exit with an error.
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
|
|
62
|
+
1. Save logs to a file without comparison:
|
|
63
|
+
```
|
|
64
|
+
amsdal api-check https://api.example.com --compare-url https://api.example.com --output logs.json
|
|
65
|
+
```
|
|
66
|
+
This uses the same URL for both target and comparison, which skips the comparison
|
|
67
|
+
but still runs the API checks and saves the logs.
|
|
68
|
+
|
|
69
|
+
2. Compare a URL with previously saved logs:
|
|
70
|
+
```
|
|
71
|
+
amsdal api-check https://api.example.com --compare-logs previous-logs.json
|
|
72
|
+
```
|
|
73
|
+
This runs API checks against the target URL and compares the results with
|
|
74
|
+
the logs stored in previous-logs.json.
|
|
75
|
+
|
|
76
|
+
3. Compare two different URLs:
|
|
77
|
+
```
|
|
78
|
+
amsdal api-check https://api-prod.example.com --compare-url https://api-staging.example.com
|
|
79
|
+
```
|
|
80
|
+
This runs API checks against both URLs and compares the results.
|
|
81
|
+
|
|
82
|
+
You can combine these options as needed:
|
|
83
|
+
```
|
|
84
|
+
amsdal api-check https://api-prod.example.com --compare-url https://api-staging.example.com \
|
|
85
|
+
--output comparison.json
|
|
86
|
+
```
|
|
87
|
+
This compares the two URLs and also saves the logs from the target URL.
|
|
88
|
+
"""
|
|
89
|
+
if not compare_url and not compare_logs:
|
|
90
|
+
msg = 'Either --compare-url or --compare-logs must be provided'
|
|
91
|
+
raise typer.BadParameter(msg)
|
|
92
|
+
|
|
93
|
+
if compare_url and compare_logs:
|
|
94
|
+
msg = 'Cannot use both --compare-url and --compare-logs simultaneously'
|
|
95
|
+
raise typer.BadParameter(msg)
|
|
96
|
+
|
|
97
|
+
# Load configuration using the class method
|
|
98
|
+
config = ApiCheckConfig.load_from_file(config_file)
|
|
99
|
+
|
|
100
|
+
# Create runner with the loaded config
|
|
101
|
+
target_runner = ApiRunner(target_url, config)
|
|
102
|
+
target_logs_data = target_runner.run()
|
|
103
|
+
has_errors = False
|
|
104
|
+
|
|
105
|
+
if compare_url != target_url:
|
|
106
|
+
if compare_url:
|
|
107
|
+
compare_runner = ApiRunner(compare_url, config)
|
|
108
|
+
compare_logs_data = compare_runner.run()
|
|
109
|
+
else:
|
|
110
|
+
compare_logs_data = load_operation_logs(compare_logs) # type: ignore[arg-type]
|
|
111
|
+
|
|
112
|
+
has_errors = check(target_logs_data, compare_logs_data)
|
|
113
|
+
|
|
114
|
+
if output_logs:
|
|
115
|
+
save(target_logs_data, destination=output_logs)
|
|
116
|
+
|
|
117
|
+
if has_errors:
|
|
118
|
+
raise typer.Exit(code=1)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from typing import ClassVar
|
|
8
|
+
from typing import Literal
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
import yaml
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
from pydantic import Field
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TransactionData(BaseModel):
|
|
19
|
+
transaction_name: str
|
|
20
|
+
input_params: dict[str, Any] = Field(default_factory=dict)
|
|
21
|
+
expected_response: Any = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ApiCheckConfig(BaseModel):
|
|
25
|
+
# Class variable to store the config file path
|
|
26
|
+
_config_file: ClassVar[Optional[Path]] = None
|
|
27
|
+
|
|
28
|
+
items_per_list: tuple[int, int, int] = (5, 5, 5)
|
|
29
|
+
headers: dict[str, str] = Field(default_factory=dict)
|
|
30
|
+
auth_headers: dict[str, str] = Field(default_factory=dict)
|
|
31
|
+
request_timeout: int = 600
|
|
32
|
+
extend_output: bool = True
|
|
33
|
+
|
|
34
|
+
# Authentication
|
|
35
|
+
email: Optional[str] = None
|
|
36
|
+
password: Optional[str] = None
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def token(self) -> Optional[str]:
|
|
40
|
+
"""
|
|
41
|
+
Get the token from auth_headers.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Optional[str]: The token or None if not set
|
|
45
|
+
"""
|
|
46
|
+
if not self.auth_headers or 'Authorization' not in self.auth_headers:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
return self.auth_headers['Authorization']
|
|
50
|
+
|
|
51
|
+
@token.setter
|
|
52
|
+
def token(self, value: Optional[str]) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Set the token in auth_headers.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
value: The token value
|
|
58
|
+
"""
|
|
59
|
+
if value is None:
|
|
60
|
+
if 'Authorization' in self.auth_headers:
|
|
61
|
+
del self.auth_headers['Authorization']
|
|
62
|
+
else:
|
|
63
|
+
self.auth_headers['Authorization'] = value
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def token_expiry(self) -> Optional[int]:
|
|
67
|
+
"""
|
|
68
|
+
Get the token expiry from the token.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Optional[int]: The token expiry timestamp, or None if not available
|
|
72
|
+
"""
|
|
73
|
+
if not self.token:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
import jwt
|
|
78
|
+
|
|
79
|
+
decoded = jwt.decode(self.token, options={'verify_signature': False})
|
|
80
|
+
return decoded.get('exp')
|
|
81
|
+
except Exception as e:
|
|
82
|
+
logger.warning(f'Failed to decode token: {e}')
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def env_authorization(self) -> Optional[str]:
|
|
87
|
+
"""Get authorization token from environment variable."""
|
|
88
|
+
return os.environ.get('AMSDAL_API_CHECK_AUTHORIZATION')
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def env_email(self) -> Optional[str]:
|
|
92
|
+
"""Get email from environment variable."""
|
|
93
|
+
return os.environ.get('AMSDAL_API_CHECK_EMAIL')
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def env_password(self) -> Optional[str]:
|
|
97
|
+
"""Get password from environment variable."""
|
|
98
|
+
return os.environ.get('AMSDAL_API_CHECK_PASSWORD')
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def load_from_file(cls, config_file: str | Path) -> 'ApiCheckConfig':
|
|
102
|
+
"""
|
|
103
|
+
Load configuration from a file.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
config_file: Path to the configuration file (YAML or JSON)
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
ApiCheckConfig: The loaded configuration
|
|
110
|
+
"""
|
|
111
|
+
config_path = Path(config_file)
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
with open(config_path) as f:
|
|
115
|
+
# Determine file format based on extension
|
|
116
|
+
if config_path.suffix.lower() in ['.yaml', '.yml']:
|
|
117
|
+
config_raw = yaml.safe_load(f)
|
|
118
|
+
elif config_path.suffix.lower() == '.json':
|
|
119
|
+
config_raw = json.load(f)
|
|
120
|
+
else:
|
|
121
|
+
# Default to YAML if extension is not recognized
|
|
122
|
+
config_raw = yaml.safe_load(f)
|
|
123
|
+
|
|
124
|
+
# Create config instance
|
|
125
|
+
config = cls(**config_raw)
|
|
126
|
+
# Store the config file path
|
|
127
|
+
cls._config_file = config_path
|
|
128
|
+
|
|
129
|
+
logger.info(f'Configuration loaded from {config_path}')
|
|
130
|
+
return config
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logger.error(f'Failed to load configuration from {config_path}: {e}')
|
|
133
|
+
raise
|
|
134
|
+
|
|
135
|
+
def save(self, config_file: Optional[str | Path] = None) -> None:
|
|
136
|
+
"""
|
|
137
|
+
Save the current configuration to a file.
|
|
138
|
+
|
|
139
|
+
Email and password values provided through environment variables
|
|
140
|
+
(AMSDAL_API_CHECK_EMAIL, AMSDAL_API_CHECK_PASSWORD) will not be saved to the file.
|
|
141
|
+
Only the token and other configuration values will be persisted.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
config_file: Path to save the configuration to. If not provided,
|
|
145
|
+
uses the path from which the config was loaded.
|
|
146
|
+
"""
|
|
147
|
+
# Use provided path or fall back to the stored path
|
|
148
|
+
save_path = Path(config_file) if config_file else self.__class__._config_file
|
|
149
|
+
|
|
150
|
+
if not save_path:
|
|
151
|
+
logger.warning('No config file specified, cannot save configuration')
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
# Convert config to dict
|
|
156
|
+
config_dict = self.model_dump()
|
|
157
|
+
|
|
158
|
+
# Don't save email and password if they were provided through environment variables
|
|
159
|
+
if self.env_email and self.email == self.env_email:
|
|
160
|
+
config_dict.pop('email', None)
|
|
161
|
+
|
|
162
|
+
if self.env_password and self.password == self.env_password:
|
|
163
|
+
config_dict.pop('password', None)
|
|
164
|
+
|
|
165
|
+
# No need to handle token and token_expiry as they are now properties
|
|
166
|
+
# and not included in the model_dump()
|
|
167
|
+
|
|
168
|
+
# Write to file
|
|
169
|
+
with open(save_path, 'w') as f:
|
|
170
|
+
json.dump(config_dict, f, indent=2)
|
|
171
|
+
|
|
172
|
+
logger.info(f'Configuration saved to {save_path}')
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.error(f'Failed to save configuration: {e}')
|
|
175
|
+
|
|
176
|
+
# classes
|
|
177
|
+
exclude_classes: list[str] | Literal['ALL'] = Field(default_factory=list)
|
|
178
|
+
|
|
179
|
+
# objects
|
|
180
|
+
exclude_objects_for_classes: list[str] = Field(default_factory=list)
|
|
181
|
+
objects_list_params_options: list[dict[str, Any]] = Field(default_factory=list)
|
|
182
|
+
object_detail_params_options: list[dict[str, Any]] = Field(default_factory=list)
|
|
183
|
+
object_write_operations_enabled: bool = Field(default=False)
|
|
184
|
+
exclude_object_write_operations_for_classes: list[str] = Field(default_factory=list)
|
|
185
|
+
pre_object_create_hook: Callable[[dict[str, Any]], dict[str, Any]] | dict[str, Any] = Field(default_factory=dict)
|
|
186
|
+
pre_object_update_hook: Callable[[dict[str, Any]], dict[str, Any]] | dict[str, Any] = Field(default_factory=dict)
|
|
187
|
+
|
|
188
|
+
# transactions
|
|
189
|
+
ignore_transaction_execution_errors: bool = Field(default=True)
|
|
190
|
+
exclude_transactions: list[str] | Literal['ALL'] = Field(default_factory=list)
|
|
191
|
+
exclude_execute_transactions: list[str] | Literal['ALL'] = Field(default_factory=list)
|
|
192
|
+
transactions_data: list[TransactionData] = Field(default_factory=list)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
from json import JSONEncoder
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BytesJSONEncoder(JSONEncoder):
|
|
12
|
+
def default(self, o: Any) -> Any:
|
|
13
|
+
if isinstance(o, bytes):
|
|
14
|
+
return base64.b64encode(o).decode('utf-8')
|
|
15
|
+
return super().default(o)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OperationLog(BaseModel):
|
|
19
|
+
method: str
|
|
20
|
+
uri: str
|
|
21
|
+
headers: dict[str, str] = Field(default_factory=dict)
|
|
22
|
+
params: dict[str, str] | None = None
|
|
23
|
+
data: Any
|
|
24
|
+
status_code: int
|
|
25
|
+
response_data: Any
|
|
26
|
+
response_headers: dict[str, str] = Field(default_factory=dict)
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def id(self) -> str:
|
|
30
|
+
_params = json.dumps(self.params, cls=BytesJSONEncoder) if self.params else None
|
|
31
|
+
_data = json.dumps(self.data, cls=BytesJSONEncoder) if self.data else None
|
|
32
|
+
return f'{self.method} {self.uri} {_params} {_data}'
|
|
33
|
+
|
|
34
|
+
def __str__(self) -> str:
|
|
35
|
+
_response = (
|
|
36
|
+
json.dumps(self.response_data, cls=BytesJSONEncoder) if not isinstance(self.response_data, str) else None
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
return f'{self.id} {self.status_code} {_response}'
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def from_response(
|
|
43
|
+
cls,
|
|
44
|
+
response: Any,
|
|
45
|
+
auth_headers: dict[str, Any] | None = None,
|
|
46
|
+
*,
|
|
47
|
+
ignore_object_version: bool = False,
|
|
48
|
+
ignore_class_version: bool = False,
|
|
49
|
+
) -> 'OperationLog':
|
|
50
|
+
request_headers = {key.lower(): value for key, value in response.request.headers.items()}
|
|
51
|
+
|
|
52
|
+
if auth_headers:
|
|
53
|
+
request_headers.update({key.lower(): '*****' for key in auth_headers})
|
|
54
|
+
|
|
55
|
+
return cls(
|
|
56
|
+
method=response.request.method,
|
|
57
|
+
uri=response.request.url.path,
|
|
58
|
+
headers=request_headers,
|
|
59
|
+
params=dict(response.request.url.params.items()),
|
|
60
|
+
data=response.request.content,
|
|
61
|
+
status_code=response.status_code,
|
|
62
|
+
response_data=cls._process_response_data(
|
|
63
|
+
response.text,
|
|
64
|
+
ignore_object_version=ignore_object_version,
|
|
65
|
+
ignore_class_version=ignore_class_version,
|
|
66
|
+
),
|
|
67
|
+
response_headers=response.headers,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def _process_response_data(cls, text: str, *, ignore_object_version: bool, ignore_class_version: bool) -> Any:
|
|
72
|
+
if ignore_object_version:
|
|
73
|
+
text = re.sub(r'"object_version": "(?!(?:ALL|LATEST)\b).*?"', '"object_version": "ignore"', text)
|
|
74
|
+
|
|
75
|
+
if ignore_class_version:
|
|
76
|
+
text = re.sub(r'"class_version": "(?!(?:ALL|LATEST)\b).*?"', '"class_version": "ignore"', text)
|
|
77
|
+
|
|
78
|
+
return text
|