hap-cli 0.8.15__tar.gz → 0.8.17__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.
- {hap_cli-0.8.15 → hap_cli-0.8.17}/PKG-INFO +1 -1
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/__init__.py +1 -1
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/node_cmd.py +11 -3
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/worksheet_cmd.py +14 -3
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/flow_node.py +73 -7
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/workflow_node_dsl.py +14 -7
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/worksheet.py +23 -2
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/locale/messages.json +7 -4
- hap_cli-0.8.17/hap_cli/tests/test_bug_036750.py +130 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_core.py +9 -4
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_workflow_v3_semantic_cli.py +1 -1
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/PKG-INFO +1 -1
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/SOURCES.txt +1 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/MANIFEST.in +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/README.md +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/README.md +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/README_CN.md +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/chat_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/context.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/record.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/session.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/update.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/hap_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/i18n.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/charts.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/config.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/errors.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/executor.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/fields.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/hap.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/schema.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/step.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/steps.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/store.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/setup.cfg +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/setup.py +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/skills/cli/hap-cli-app-editor/scripts/editspec/component.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/skills/cli/hap-cli-app-editor/scripts/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/skills/cli/hap-cli-app-editor/scripts/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/skills/cli/hap-cli-app-editor/scripts/editspec/field.schema.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.15 → hap_cli-0.8.17}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -313,13 +313,21 @@ def node_test_code(ctx, process_id, node_id, code, input_json):
|
|
|
313
313
|
@click.argument("process_id")
|
|
314
314
|
@click.argument("node_id")
|
|
315
315
|
@click.option("--url", "-u", required=True, help="Target URL")
|
|
316
|
-
@click.option("--method", "-m", default="POST",
|
|
316
|
+
@click.option("--method", "-m", default="POST",
|
|
317
|
+
help="HTTP method: GET, POST, PUT, DELETE, HEAD, or PATCH.")
|
|
317
318
|
@click.option("--body", "-b", default="", help="Request body (JSON string)")
|
|
318
319
|
@click.option("--headers", "-H", default="", help="Headers JSON: [{name,value}]")
|
|
319
|
-
@click.option("--content-type", default="
|
|
320
|
+
@click.option("--content-type", default="json",
|
|
321
|
+
help="Body format: json, text, form-data, "
|
|
322
|
+
"x-www-form-urlencoded, or file.")
|
|
320
323
|
@pass_context
|
|
321
324
|
def node_test_webhook(ctx, process_id, node_id, url, method, body, headers, content_type):
|
|
322
|
-
"""Test a
|
|
325
|
+
"""Run the "Test API" action of a Send Custom Request node.
|
|
326
|
+
|
|
327
|
+
Issues the request the node is configured to make and prints the
|
|
328
|
+
response. Works for any outbound API call the node performs, not just
|
|
329
|
+
webhook callbacks.
|
|
330
|
+
"""
|
|
323
331
|
try:
|
|
324
332
|
session = ctx.get_session()
|
|
325
333
|
headers_list = json.loads(headers) if headers else None
|
|
@@ -189,12 +189,23 @@ def worksheet_create(ctx, app_id, name, org_id, section_id, icon, icon_color,
|
|
|
189
189
|
@click.option("--app-id", "-a", default="", help="Application ID")
|
|
190
190
|
@org_id_option()
|
|
191
191
|
@click.option("--copy-rows", is_flag=True, default=False, help="Copy rows as well")
|
|
192
|
+
@click.option("--section-id", default="",
|
|
193
|
+
help="Sidebar group the copy lands in. Auto-resolved from the "
|
|
194
|
+
"source worksheet's group when omitted (requires --app-id).")
|
|
192
195
|
@pass_context
|
|
193
|
-
def worksheet_copy(ctx, worksheet_id, name, app_id, org_id, copy_rows):
|
|
194
|
-
"""Copy a worksheet.
|
|
196
|
+
def worksheet_copy(ctx, worksheet_id, name, app_id, org_id, copy_rows, section_id):
|
|
197
|
+
"""Copy a worksheet into the same sidebar group as the original.
|
|
198
|
+
|
|
199
|
+
Pass --app-id so the target group can be resolved, or set --section-id
|
|
200
|
+
to place the copy in a specific group.
|
|
201
|
+
"""
|
|
195
202
|
try:
|
|
196
203
|
session = ctx.get_session()
|
|
197
|
-
data = ws_mod.copy_worksheet(
|
|
204
|
+
data = ws_mod.copy_worksheet(
|
|
205
|
+
session, worksheet_id, name, app_id,
|
|
206
|
+
require_api_project_id(session, org_id), copy_rows,
|
|
207
|
+
section_id=section_id,
|
|
208
|
+
)
|
|
198
209
|
ctx.output(data, lambda d: output_json(d))
|
|
199
210
|
except Exception as e:
|
|
200
211
|
ctx.handle_error(e)
|
|
@@ -455,6 +455,66 @@ def test_code(
|
|
|
455
455
|
return session.workflow_call("flowNode/codeTest", data)
|
|
456
456
|
|
|
457
457
|
|
|
458
|
+
# flowNode/webHookTestRequest wants integer enums, not strings. Source of
|
|
459
|
+
# truth: pd-openweb src/pages/workflow/WorkflowSettings/enum.js (METHODS_TYPE)
|
|
460
|
+
# and src/pages/workflow/WorkflowSettings/Detail/WebHook/index.jsx
|
|
461
|
+
# (contentTypes + the raw JSON/Text sub-dropdown). Sending "POST" /
|
|
462
|
+
# "application/json" verbatim makes the server answer 400.
|
|
463
|
+
_WEBHOOK_METHODS = {
|
|
464
|
+
"GET": 1,
|
|
465
|
+
"POST": 2,
|
|
466
|
+
"PUT": 3,
|
|
467
|
+
"DELETE": 14,
|
|
468
|
+
"HEAD": 5,
|
|
469
|
+
"PATCH": 6,
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
_WEBHOOK_CONTENT_TYPES = {
|
|
473
|
+
"x-www-form-urlencoded": 1,
|
|
474
|
+
"urlencoded": 1,
|
|
475
|
+
"json": 2,
|
|
476
|
+
"application/json": 2,
|
|
477
|
+
"text": 3,
|
|
478
|
+
"form-data": 4,
|
|
479
|
+
"file": 5,
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def _encode_webhook_method(method: Any) -> int:
|
|
484
|
+
"""Map a friendly HTTP method name to its webHookTestRequest enum int.
|
|
485
|
+
|
|
486
|
+
Accepts an int (passed through) or a case-insensitive method name.
|
|
487
|
+
"""
|
|
488
|
+
if isinstance(method, int):
|
|
489
|
+
return method
|
|
490
|
+
key = str(method).strip()
|
|
491
|
+
if key.isdigit():
|
|
492
|
+
return int(key)
|
|
493
|
+
code = _WEBHOOK_METHODS.get(key.upper())
|
|
494
|
+
if code is None:
|
|
495
|
+
raise ValueError(
|
|
496
|
+
f"Unknown HTTP method {method!r}; expected one of "
|
|
497
|
+
f"{', '.join(_WEBHOOK_METHODS)}."
|
|
498
|
+
)
|
|
499
|
+
return code
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _encode_webhook_content_type(content_type: Any) -> int:
|
|
503
|
+
"""Map a friendly body format name to its webHookTestRequest enum int."""
|
|
504
|
+
if isinstance(content_type, int):
|
|
505
|
+
return content_type
|
|
506
|
+
key = str(content_type).strip()
|
|
507
|
+
if key.isdigit():
|
|
508
|
+
return int(key)
|
|
509
|
+
code = _WEBHOOK_CONTENT_TYPES.get(key.lower())
|
|
510
|
+
if code is None:
|
|
511
|
+
raise ValueError(
|
|
512
|
+
f"Unknown content type {content_type!r}; expected one of "
|
|
513
|
+
"json, text, form-data, x-www-form-urlencoded, file."
|
|
514
|
+
)
|
|
515
|
+
return code
|
|
516
|
+
|
|
517
|
+
|
|
458
518
|
def test_webhook(
|
|
459
519
|
session: Session,
|
|
460
520
|
process_id: str,
|
|
@@ -463,22 +523,28 @@ def test_webhook(
|
|
|
463
523
|
method: str = "POST",
|
|
464
524
|
headers: Optional[list] = None,
|
|
465
525
|
body: str = "",
|
|
466
|
-
content_type: str = "
|
|
526
|
+
content_type: str = "json",
|
|
467
527
|
params: Optional[list] = None,
|
|
468
528
|
auth_id: str = "",
|
|
469
529
|
settings: Optional[dict] = None,
|
|
470
530
|
) -> dict[str, Any]:
|
|
471
|
-
"""
|
|
531
|
+
"""Send the HTTP request configured on a "Send Custom Request" node.
|
|
532
|
+
|
|
533
|
+
This drives the node's "Test API" action (flowNode/webHookTestRequest):
|
|
534
|
+
it issues the configured outbound request and returns the response —
|
|
535
|
+
it works for any API call the node makes, not just webhook callbacks.
|
|
472
536
|
|
|
473
537
|
Args:
|
|
474
538
|
session: Active session
|
|
475
539
|
process_id: Process ID
|
|
476
|
-
node_id:
|
|
540
|
+
node_id: Send-Custom-Request node ID
|
|
477
541
|
url: Target URL
|
|
478
|
-
method: HTTP method
|
|
542
|
+
method: HTTP method name (GET/POST/PUT/DELETE/HEAD/PATCH) or its
|
|
543
|
+
enum int. Mapped to the integer the endpoint requires.
|
|
479
544
|
headers: Request headers [{name, value}]
|
|
480
545
|
body: Request body (JSON string)
|
|
481
|
-
content_type:
|
|
546
|
+
content_type: Body format — json, text, form-data,
|
|
547
|
+
x-www-form-urlencoded, or file — or its enum int.
|
|
482
548
|
params: URL parameters [{name, value}]
|
|
483
549
|
auth_id: Authentication config ID
|
|
484
550
|
settings: Additional settings
|
|
@@ -490,8 +556,8 @@ def test_webhook(
|
|
|
490
556
|
"processId": process_id,
|
|
491
557
|
"nodeId": node_id,
|
|
492
558
|
"url": url,
|
|
493
|
-
"method": method,
|
|
494
|
-
"contentType": content_type,
|
|
559
|
+
"method": _encode_webhook_method(method),
|
|
560
|
+
"contentType": _encode_webhook_content_type(content_type),
|
|
495
561
|
}
|
|
496
562
|
if headers:
|
|
497
563
|
data["headers"] = headers
|
|
@@ -684,17 +684,24 @@ def get_trigger_ref(session, process_id: str) -> dict[str, str]:
|
|
|
684
684
|
|
|
685
685
|
|
|
686
686
|
# Worksheet-event trigger event codes (triggerId on the flowNodeType-0
|
|
687
|
-
# node).
|
|
688
|
-
#
|
|
687
|
+
# node). Authoritative values from pd-openweb TRIGGER_ID enum
|
|
688
|
+
# (src/pages/workflow/WorkflowSettings/enum.js) and the trigger radio
|
|
689
|
+
# options in Detail/Start/WorksheetContent.jsx:
|
|
690
|
+
# ADD='1' (仅新增记录), EDIT='2' (当新增或更新记录), DELETE='3' (删除记录),
|
|
691
|
+
# ONLY_EDIT='4' (仅更新记录).
|
|
692
|
+
# Note the non-sequential mapping: create_or_update is '2' and delete is
|
|
693
|
+
# '3' — do NOT "tidy" these into 1/2/3/4 order. (Earlier code had
|
|
694
|
+
# create_or_update='3', which the backend interprets as 删除记录 — that was
|
|
695
|
+
# the cause of bug: "创建或更新" workflows showing up as 记录删除时触发.)
|
|
689
696
|
WORKSHEET_TRIGGER_EVENTS = {
|
|
690
|
-
"create": "1",
|
|
691
|
-
"update": "
|
|
692
|
-
"create_or_update": "
|
|
693
|
-
"delete": "
|
|
697
|
+
"create": "1", # 仅新增记录 (TRIGGER_ID.ADD)
|
|
698
|
+
"update": "4", # 仅更新记录 (TRIGGER_ID.ONLY_EDIT)
|
|
699
|
+
"create_or_update": "2", # 当新增或更新记录 (TRIGGER_ID.EDIT)
|
|
700
|
+
"delete": "3", # 删除记录 (TRIGGER_ID.DELETE)
|
|
694
701
|
# Design-vocabulary aliases (mcp_workflow_build_tool.json#create_process
|
|
695
702
|
# trigger.config.event uses the backend database values).
|
|
696
703
|
"add": "1",
|
|
697
|
-
"add_or_update": "
|
|
704
|
+
"add_or_update": "2",
|
|
698
705
|
}
|
|
699
706
|
|
|
700
707
|
|
|
@@ -351,13 +351,34 @@ def copy_worksheet(
|
|
|
351
351
|
app_id: str = "",
|
|
352
352
|
project_id: str = "",
|
|
353
353
|
copy_rows: bool = False,
|
|
354
|
+
section_id: str = "",
|
|
354
355
|
) -> dict[str, Any]:
|
|
355
|
-
"""Copy a worksheet.
|
|
356
|
-
|
|
356
|
+
"""Copy a worksheet.
|
|
357
|
+
|
|
358
|
+
CopyWorksheet needs ``appSectionId`` — the sidebar group the new
|
|
359
|
+
worksheet should land in. Without it the server answers "服务异常"
|
|
360
|
+
(evidence: pd-openweb src/pages/worksheet/redux/actions/sheetList.js
|
|
361
|
+
copySheet + WorkSheetLeft/MoreOperation.jsx, both of which always send
|
|
362
|
+
``appSectionId``). When ``section_id`` is omitted but ``app_id`` is
|
|
363
|
+
given, resolve it from the source worksheet's own section so the copy
|
|
364
|
+
lands beside the original.
|
|
365
|
+
"""
|
|
366
|
+
data: dict[str, Any] = {
|
|
367
|
+
"worksheetId": worksheet_id,
|
|
368
|
+
"name": name,
|
|
369
|
+
"relationControlIds": [],
|
|
370
|
+
}
|
|
357
371
|
if app_id:
|
|
358
372
|
data["appId"] = app_id
|
|
359
373
|
if project_id:
|
|
360
374
|
data["projectId"] = project_id
|
|
375
|
+
if not section_id and app_id:
|
|
376
|
+
from hap_cli.core import app as _app
|
|
377
|
+
section_id, _ = _app.find_worksheet_section(
|
|
378
|
+
session, app_id, worksheet_id,
|
|
379
|
+
)
|
|
380
|
+
if section_id:
|
|
381
|
+
data["appSectionId"] = section_id
|
|
361
382
|
data["isCopyRows"] = copy_rows
|
|
362
383
|
return session.api_call("Worksheet", "CopyWorksheet", data)
|
|
363
384
|
|
|
@@ -2599,19 +2599,19 @@
|
|
|
2599
2599
|
"en": "Input data JSON: [{name,value,type}]"
|
|
2600
2600
|
},
|
|
2601
2601
|
"workflow node test-webhook": {
|
|
2602
|
-
"en": "Test a
|
|
2602
|
+
"en": "Run the \"Test API\" action of a Send Custom Request node."
|
|
2603
2603
|
},
|
|
2604
2604
|
"workflow node test-webhook --body": {
|
|
2605
2605
|
"en": "Request body (JSON string)"
|
|
2606
2606
|
},
|
|
2607
2607
|
"workflow node test-webhook --content-type": {
|
|
2608
|
-
"en": "
|
|
2608
|
+
"en": "Body format: json, text, form-data, x-www-form-urlencoded, or file."
|
|
2609
2609
|
},
|
|
2610
2610
|
"workflow node test-webhook --headers": {
|
|
2611
2611
|
"en": "Headers JSON: [{name,value}]"
|
|
2612
2612
|
},
|
|
2613
2613
|
"workflow node test-webhook --method": {
|
|
2614
|
-
"en": "HTTP method"
|
|
2614
|
+
"en": "HTTP method: GET, POST, PUT, DELETE, HEAD, or PATCH."
|
|
2615
2615
|
},
|
|
2616
2616
|
"workflow node test-webhook --url": {
|
|
2617
2617
|
"en": "Target URL"
|
|
@@ -2713,7 +2713,7 @@
|
|
|
2713
2713
|
"en": "Worksheet operations."
|
|
2714
2714
|
},
|
|
2715
2715
|
"worksheet copy": {
|
|
2716
|
-
"en": "Copy a worksheet."
|
|
2716
|
+
"en": "Copy a worksheet into the same sidebar group as the original."
|
|
2717
2717
|
},
|
|
2718
2718
|
"worksheet copy --app-id": {
|
|
2719
2719
|
"en": "Application ID"
|
|
@@ -2724,6 +2724,9 @@
|
|
|
2724
2724
|
"worksheet copy --org-id": {
|
|
2725
2725
|
"en": "Organization ID"
|
|
2726
2726
|
},
|
|
2727
|
+
"worksheet copy --section-id": {
|
|
2728
|
+
"en": "Sidebar group the copy lands in. Auto-resolved from the source worksheet's group when omitted (requires --app-id)."
|
|
2729
|
+
},
|
|
2727
2730
|
"worksheet create": {
|
|
2728
2731
|
"en": "Create a worksheet with the full v3 field-type set including Attachment."
|
|
2729
2732
|
},
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Bugfix coverage for bug #036750.
|
|
2
|
+
|
|
3
|
+
Two reproducible sub-issues are fixed here (traced from pd-openweb):
|
|
4
|
+
|
|
5
|
+
1. ``workflow node test-webhook``: the underlying flowNode/webHookTestRequest
|
|
6
|
+
endpoint wants integer enums for ``method`` and ``contentType``
|
|
7
|
+
(METHODS_TYPE in src/pages/workflow/WorkflowSettings/enum.js;
|
|
8
|
+
contentTypes in .../Detail/WebHook/index.jsx). The old wrapper forwarded
|
|
9
|
+
the friendly strings "POST" / "application/json" verbatim, so the server
|
|
10
|
+
answered "400 Client Error". The command also described itself as a
|
|
11
|
+
webhook-only test; it actually drives the "Test API" action of a Send
|
|
12
|
+
Custom Request node and works for any outbound call.
|
|
13
|
+
|
|
14
|
+
2. ``worksheet copy``: CopyWorksheet needs ``appSectionId`` (the sidebar
|
|
15
|
+
group). The old wrapper never sent it, so the server answered "服务异常".
|
|
16
|
+
It is now sent — auto-resolved from the source worksheet's own section
|
|
17
|
+
when ``--app-id`` is given, or supplied via ``--section-id``.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from unittest.mock import MagicMock, patch
|
|
21
|
+
|
|
22
|
+
import pytest
|
|
23
|
+
|
|
24
|
+
from hap_cli.core import flow_node as node_mod
|
|
25
|
+
from hap_cli.core import worksheet as ws_mod
|
|
26
|
+
from hap_cli.core.session import Session
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _mock_response(data, state=1):
|
|
30
|
+
resp = MagicMock()
|
|
31
|
+
resp.status_code = 200
|
|
32
|
+
resp.json.return_value = {"data": data, "state": state}
|
|
33
|
+
resp.raise_for_status = MagicMock()
|
|
34
|
+
return resp
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def mock_session():
|
|
39
|
+
return Session(server_url="https://test.mingdao.com", auth_token="tok123")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ── Bug 1: test-webhook enum encoding ────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
class TestWebhookEnumEncoding:
|
|
45
|
+
@patch("hap_cli.core.session.requests.post")
|
|
46
|
+
def test_method_name_mapped_to_int(self, mock_post, mock_session):
|
|
47
|
+
mock_post.return_value = _mock_response({"status": 1})
|
|
48
|
+
node_mod.test_webhook(
|
|
49
|
+
mock_session, "p1", "n1", "https://api.example.com",
|
|
50
|
+
method="POST", content_type="json",
|
|
51
|
+
body='{"name":"x"}',
|
|
52
|
+
)
|
|
53
|
+
body = mock_post.call_args[1]["json"]
|
|
54
|
+
assert body["method"] == 2
|
|
55
|
+
assert body["contentType"] == 2
|
|
56
|
+
assert body["body"] == '{"name":"x"}'
|
|
57
|
+
|
|
58
|
+
@patch("hap_cli.core.session.requests.post")
|
|
59
|
+
def test_all_method_names(self, mock_post, mock_session):
|
|
60
|
+
mock_post.return_value = _mock_response({"status": 1})
|
|
61
|
+
expected = {"GET": 1, "POST": 2, "PUT": 3, "DELETE": 14,
|
|
62
|
+
"HEAD": 5, "PATCH": 6}
|
|
63
|
+
for name, code in expected.items():
|
|
64
|
+
node_mod.test_webhook(
|
|
65
|
+
mock_session, "p1", "n1", "https://api.example.com",
|
|
66
|
+
method=name,
|
|
67
|
+
)
|
|
68
|
+
assert mock_post.call_args[1]["json"]["method"] == code
|
|
69
|
+
|
|
70
|
+
@patch("hap_cli.core.session.requests.post")
|
|
71
|
+
def test_content_type_names(self, mock_post, mock_session):
|
|
72
|
+
mock_post.return_value = _mock_response({"status": 1})
|
|
73
|
+
expected = {
|
|
74
|
+
"json": 2, "application/json": 2, "text": 3,
|
|
75
|
+
"form-data": 4, "x-www-form-urlencoded": 1, "file": 5,
|
|
76
|
+
}
|
|
77
|
+
for name, code in expected.items():
|
|
78
|
+
node_mod.test_webhook(
|
|
79
|
+
mock_session, "p1", "n1", "https://api.example.com",
|
|
80
|
+
content_type=name,
|
|
81
|
+
)
|
|
82
|
+
assert mock_post.call_args[1]["json"]["contentType"] == code
|
|
83
|
+
|
|
84
|
+
@patch("hap_cli.core.session.requests.post")
|
|
85
|
+
def test_lowercase_and_int_passthrough(self, mock_post, mock_session):
|
|
86
|
+
mock_post.return_value = _mock_response({"status": 1})
|
|
87
|
+
node_mod.test_webhook(
|
|
88
|
+
mock_session, "p1", "n1", "https://api.example.com",
|
|
89
|
+
method="get", content_type=3,
|
|
90
|
+
)
|
|
91
|
+
body = mock_post.call_args[1]["json"]
|
|
92
|
+
assert body["method"] == 1
|
|
93
|
+
assert body["contentType"] == 3
|
|
94
|
+
|
|
95
|
+
def test_unknown_method_raises(self, mock_session):
|
|
96
|
+
with pytest.raises(ValueError):
|
|
97
|
+
node_mod.test_webhook(
|
|
98
|
+
mock_session, "p1", "n1", "https://api.example.com",
|
|
99
|
+
method="FETCH",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ── Bug 2: copy worksheet sends appSectionId ─────────────────────────────
|
|
104
|
+
|
|
105
|
+
class TestCopyWorksheetSection:
|
|
106
|
+
@patch("hap_cli.core.session.requests.post")
|
|
107
|
+
def test_explicit_section_id_sent(self, mock_post, mock_session):
|
|
108
|
+
mock_post.return_value = _mock_response("new-ws-id")
|
|
109
|
+
ws_mod.copy_worksheet(
|
|
110
|
+
mock_session, "ws1", "Copy", app_id="app1",
|
|
111
|
+
section_id="sec-123",
|
|
112
|
+
)
|
|
113
|
+
body = mock_post.call_args[1]["json"]
|
|
114
|
+
assert body["appSectionId"] == "sec-123"
|
|
115
|
+
assert body["worksheetId"] == "ws1"
|
|
116
|
+
assert body["name"] == "Copy"
|
|
117
|
+
|
|
118
|
+
@patch("hap_cli.core.app.find_worksheet_section")
|
|
119
|
+
@patch("hap_cli.core.session.requests.post")
|
|
120
|
+
def test_section_auto_resolved_from_app(
|
|
121
|
+
self, mock_post, mock_find, mock_session,
|
|
122
|
+
):
|
|
123
|
+
mock_find.return_value = ("resolved-sec", "原表")
|
|
124
|
+
mock_post.return_value = _mock_response("new-ws-id")
|
|
125
|
+
ws_mod.copy_worksheet(
|
|
126
|
+
mock_session, "ws1", "Copy", app_id="app1",
|
|
127
|
+
)
|
|
128
|
+
mock_find.assert_called_once_with(mock_session, "app1", "ws1")
|
|
129
|
+
body = mock_post.call_args[1]["json"]
|
|
130
|
+
assert body["appSectionId"] == "resolved-sec"
|
|
@@ -1352,7 +1352,9 @@ class TestFlowNode:
|
|
|
1352
1352
|
)
|
|
1353
1353
|
body = mock_post.call_args[1]["json"]
|
|
1354
1354
|
assert body["url"] == "https://example.com/api"
|
|
1355
|
-
|
|
1355
|
+
# webHookTestRequest wants the integer enum, not the method name.
|
|
1356
|
+
assert body["method"] == 1
|
|
1357
|
+
assert body["contentType"] == 2
|
|
1356
1358
|
|
|
1357
1359
|
@patch("hap_cli.core.session.requests.post")
|
|
1358
1360
|
def test_test_aigc(self, mock_post, mock_session):
|
|
@@ -8818,10 +8820,13 @@ class TestLiveWireFixes:
|
|
|
8818
8820
|
|
|
8819
8821
|
def test_worksheet_trigger_event_codes(self):
|
|
8820
8822
|
from hap_cli.core import workflow_node_dsl as dsl
|
|
8823
|
+
# Authoritative TRIGGER_ID enum: ADD=1, EDIT(create_or_update)=2,
|
|
8824
|
+
# DELETE=3, ONLY_EDIT(update)=4. The mapping is intentionally
|
|
8825
|
+
# non-sequential — see WORKSHEET_TRIGGER_EVENTS comment.
|
|
8821
8826
|
assert dsl.WORKSHEET_TRIGGER_EVENTS["create"] == "1"
|
|
8822
|
-
assert dsl.WORKSHEET_TRIGGER_EVENTS["update"] == "
|
|
8823
|
-
assert dsl.WORKSHEET_TRIGGER_EVENTS["create_or_update"] == "
|
|
8824
|
-
assert dsl.WORKSHEET_TRIGGER_EVENTS["delete"] == "
|
|
8827
|
+
assert dsl.WORKSHEET_TRIGGER_EVENTS["update"] == "4"
|
|
8828
|
+
assert dsl.WORKSHEET_TRIGGER_EVENTS["create_or_update"] == "2"
|
|
8829
|
+
assert dsl.WORKSHEET_TRIGGER_EVENTS["delete"] == "3"
|
|
8825
8830
|
|
|
8826
8831
|
|
|
8827
8832
|
class TestRolePermBuilder:
|
|
@@ -452,7 +452,7 @@ class TestTriggerSpecLowering:
|
|
|
452
452
|
assert args["trigger_fields"] == ["f1"]
|
|
453
453
|
assert args["trigger_filter"] == {"logic": "and", "items": []}
|
|
454
454
|
assert dsl.WORKSHEET_TRIGGER_EVENTS["add"] == "1"
|
|
455
|
-
assert dsl.WORKSHEET_TRIGGER_EVENTS["add_or_update"] == "
|
|
455
|
+
assert dsl.WORKSHEET_TRIGGER_EVENTS["add_or_update"] == "2"
|
|
456
456
|
|
|
457
457
|
def test_schedule(self):
|
|
458
458
|
args = dsl.v3_trigger_to_batch_args({
|
|
@@ -147,6 +147,7 @@ hap_cli/tests/test_app_editor.py
|
|
|
147
147
|
hap_cli/tests/test_app_export_usage.py
|
|
148
148
|
hap_cli/tests/test_auth_prerelease.py
|
|
149
149
|
hap_cli/tests/test_bug_036430.py
|
|
150
|
+
hap_cli/tests/test_bug_036750.py
|
|
150
151
|
hap_cli/tests/test_chart.py
|
|
151
152
|
hap_cli/tests/test_cli_access.py
|
|
152
153
|
hap_cli/tests/test_config_cmd.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|