testit-cli 2.11.1__tar.gz → 2.12.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.
- {testit_cli-2.11.1 → testit_cli-2.12.0}/PKG-INFO +63 -1
- {testit_cli-2.11.1 → testit_cli-2.12.0}/README.md +62 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/setup.py +1 -1
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/click_commands.py +96 -8
- testit_cli-2.12.0/src/testit_cli/launch_filter.py +57 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/config.py +3 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/service.py +48 -1
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/service_factory.py +3 -1
- testit_cli-2.12.0/src/testit_cli/v2_client.py +207 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/validation.py +7 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/PKG-INFO +63 -1
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/SOURCES.txt +4 -0
- testit_cli-2.12.0/tests/test_launch.py +204 -0
- testit_cli-2.12.0/tests/test_launch_filter.py +68 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/LICENSE +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/setup.cfg +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/__main__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/attachments_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/auto_tests_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/configurations_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/custom_attributes_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/parameters_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/project_attributes_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/project_sections_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/project_work_items_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/projects_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/sections_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/test_results_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/test_runs_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/work_items_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api/workflows_api.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/api_client.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/apis/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/configuration.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/exceptions.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_auto_tests_id_work_items_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_auto_tests_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_auto_tests_put_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_auto_tests_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_configurations_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_custom_attributes_global_id_put_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_custom_attributes_global_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_custom_attributes_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_parameters_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_parameters_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_projects_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_projects_project_id_attributes_put_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_projects_project_id_attributes_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_projects_project_id_work_items_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_projects_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_sections_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_test_results_id_put_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_test_results_search_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_test_runs_id_reruns_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_test_runs_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_test_runs_put_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/adapters_work_items_post_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/assign_attachment_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/assign_auto_test_case_id_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/assign_iteration_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/attachment_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/attachment_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/attachment_put_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/attachment_put_model_auto_test_step_results_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/attachment_update_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_api_result_layer.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_case_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_create_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_create_api_model_layer.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_filter_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_id_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_model_last_test_result_configuration.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_model_last_test_result_status.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_result_reason_short.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_results_for_test_run_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_search_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_search_api_model_filter.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_search_api_model_includes.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_search_include_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_step_result_update_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_update_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/auto_test_work_item_identifier_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/available_test_result_outcome.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/configuration_filter_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/configuration_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/configuration_short_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_empty_test_run_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_link_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_parameter_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_project_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_step_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/create_work_item_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_option_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_option_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_option_post_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_option_update_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_put_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_search_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_search_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/custom_attribute_types_enum.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/date_time_range_selector_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/deletion_state.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/detailed_project_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/detailed_project_api_result_workflow.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/failure_category_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/global_custom_attribute_post_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/global_custom_attribute_update_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/guid_extraction_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/image_resize_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/int32_range_selector_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/int64_range_selector_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/iteration_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/iteration_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/label_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/label_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/label_short_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/layer_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/layer_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/layer_source.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_create_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_post_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_put_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_short_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/link_update_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_select_test_results_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_select_test_results_api_model_extraction_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_select_test_results_api_model_filter.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_test_result_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/manual_rerun_test_result_api_model_test_result_ids.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/operation.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/parameter_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/parameter_iteration_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/parameter_short_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/parameter_short_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/parameters_filter_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/problem_details.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/project_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/project_attributes_filter_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/project_shortest_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/project_type_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model_autotests_count.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model_checklists_count.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model_created_date.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model_shared_steps_count.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/projects_filter_model_test_cases_count.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/section_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/section_post_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/section_shared_step.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/section_with_steps_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/shared_step_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/shared_step_result_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/step_comment_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/step_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/step_post_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/step_result_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/tag_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_link_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_outcome.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_response.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_short_response.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_short_response_status.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_step_comment_update_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_result_update_request.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_results_filter_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_results_filter_api_model_duration.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_run_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_run_api_result_status.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_run_state.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_status_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_status_api_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_status_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/test_status_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/update_empty_test_run_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/update_link_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/validation_problem_details.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_entity_type_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_filter_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_filter_api_model_duration.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_id_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_parameter_key_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_parameter_key_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_priority_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_priority_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_select_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_select_api_model_filter.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_short_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_source_type_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_state_api_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_states.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/work_item_type_model.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/workflow_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model/workflow_status_api_result.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/model_utils.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/models/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/adapters_api/rest.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/apiclient.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/autotests_filter.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/converter.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/dir_worker.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/file_worker.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/filter_factory.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/html_escape_utils.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/http_retry.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/importer.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/logger.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/__init__.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/mode.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/status_type.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/testcase.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/testrun.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/models/testrun_link.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/parser.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli/testrun_metadata.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/dependency_links.txt +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/entry_points.txt +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/requires.txt +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/src/testit_cli.egg-info/top_level.txt +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/tests/test_autotest_layer.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/tests/test_click.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/tests/test_service.py +0 -0
- {testit_cli-2.11.1 → testit_cli-2.12.0}/tests/test_testrun_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testit-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12.0
|
|
4
4
|
Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
|
|
5
5
|
Home-page: https://pypi.org/project/testit-cli/
|
|
6
6
|
Author: Integration team
|
|
@@ -65,6 +65,68 @@ You can see more information in [official documentation](https://docs.testit.sof
|
|
|
65
65
|
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
66
66
|
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
67
67
|
|
|
68
|
+
## Launch a filled test run (`testrun create launch`)
|
|
69
|
+
|
|
70
|
+
Unlike `testrun create` (empty run), `testrun create launch` creates a **filled** test run.
|
|
71
|
+
|
|
72
|
+
Provide **exactly one** source:
|
|
73
|
+
|
|
74
|
+
| Source | Flag | Behaviour |
|
|
75
|
+
|-------------------|----------------------------------------|---------------------------------------------------|
|
|
76
|
+
| Test plan | `--test-plan-id` / `-tpi` | Search automated test points in the TMS test plan |
|
|
77
|
+
| Tags | `--filter tags=smoke,nightly` | Search autotests in TMS |
|
|
78
|
+
| External IDs file | `--autotest-external-ids-file` / `-af` | One external ID per line in file |
|
|
79
|
+
|
|
80
|
+
Required: `--url`, `--token`, `--project-id`, `--configuration-id`. Optional: `--testrun-name`, `--output` (also write ID to a file).
|
|
81
|
+
|
|
82
|
+
The command prints `testRunId` to **stdout** (suitable for `export TMS_TEST_RUN_ID=$(...)`).
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
export TMS_TEST_RUN_ID=$(testit testrun create launch \
|
|
86
|
+
--url "$TMS_URL" \
|
|
87
|
+
--token "$TMS_TOKEN" \
|
|
88
|
+
--project-id "$TMS_PROJECT_ID" \
|
|
89
|
+
--configuration-id "$TMS_CONFIGURATION_ID" \
|
|
90
|
+
--filter tags=smoke \
|
|
91
|
+
--testrun-name "CI smoke")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
From a test plan:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
testit testrun create launch \
|
|
98
|
+
-u "$TMS_URL" -t "$TMS_TOKEN" \
|
|
99
|
+
-pi "$TMS_PROJECT_ID" -ci "$TMS_CONFIGURATION_ID" \
|
|
100
|
+
--test-plan-id "$TMS_TEST_PLAN_ID" \
|
|
101
|
+
-o ./testrun.id
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Autotest external IDs file
|
|
105
|
+
|
|
106
|
+
`--autotest-external-ids-file` / `-af` expects a plain-text file of **autotest external IDs** (the same values as in TMS / `autoTestExternalIds`, not internal UUIDs or global IDs):
|
|
107
|
+
|
|
108
|
+
- one external ID per line;
|
|
109
|
+
- empty lines are ignored;
|
|
110
|
+
- lines starting with `#` are comments;
|
|
111
|
+
- duplicate IDs are ignored.
|
|
112
|
+
|
|
113
|
+
Example `autotest-external-ids.txt`:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
# smoke suite
|
|
117
|
+
login-test-ext-id
|
|
118
|
+
checkout-test-ext-id
|
|
119
|
+
|
|
120
|
+
payment-test-ext-id
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
testit testrun create launch \
|
|
125
|
+
-u "$TMS_URL" -t "$TMS_TOKEN" \
|
|
126
|
+
-pi "$TMS_PROJECT_ID" -ci "$TMS_CONFIGURATION_ID" \
|
|
127
|
+
-af ./autotest-external-ids.txt
|
|
128
|
+
```
|
|
129
|
+
|
|
68
130
|
## Test run tags and links
|
|
69
131
|
|
|
70
132
|
You can attach **test run** tags and links (for example a CI job URL) via CLI flags or environment variables.
|
|
@@ -31,6 +31,68 @@ You can see more information in [official documentation](https://docs.testit.sof
|
|
|
31
31
|
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
32
32
|
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
33
33
|
|
|
34
|
+
## Launch a filled test run (`testrun create launch`)
|
|
35
|
+
|
|
36
|
+
Unlike `testrun create` (empty run), `testrun create launch` creates a **filled** test run.
|
|
37
|
+
|
|
38
|
+
Provide **exactly one** source:
|
|
39
|
+
|
|
40
|
+
| Source | Flag | Behaviour |
|
|
41
|
+
|-------------------|----------------------------------------|---------------------------------------------------|
|
|
42
|
+
| Test plan | `--test-plan-id` / `-tpi` | Search automated test points in the TMS test plan |
|
|
43
|
+
| Tags | `--filter tags=smoke,nightly` | Search autotests in TMS |
|
|
44
|
+
| External IDs file | `--autotest-external-ids-file` / `-af` | One external ID per line in file |
|
|
45
|
+
|
|
46
|
+
Required: `--url`, `--token`, `--project-id`, `--configuration-id`. Optional: `--testrun-name`, `--output` (also write ID to a file).
|
|
47
|
+
|
|
48
|
+
The command prints `testRunId` to **stdout** (suitable for `export TMS_TEST_RUN_ID=$(...)`).
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export TMS_TEST_RUN_ID=$(testit testrun create launch \
|
|
52
|
+
--url "$TMS_URL" \
|
|
53
|
+
--token "$TMS_TOKEN" \
|
|
54
|
+
--project-id "$TMS_PROJECT_ID" \
|
|
55
|
+
--configuration-id "$TMS_CONFIGURATION_ID" \
|
|
56
|
+
--filter tags=smoke \
|
|
57
|
+
--testrun-name "CI smoke")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
From a test plan:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
testit testrun create launch \
|
|
64
|
+
-u "$TMS_URL" -t "$TMS_TOKEN" \
|
|
65
|
+
-pi "$TMS_PROJECT_ID" -ci "$TMS_CONFIGURATION_ID" \
|
|
66
|
+
--test-plan-id "$TMS_TEST_PLAN_ID" \
|
|
67
|
+
-o ./testrun.id
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Autotest external IDs file
|
|
71
|
+
|
|
72
|
+
`--autotest-external-ids-file` / `-af` expects a plain-text file of **autotest external IDs** (the same values as in TMS / `autoTestExternalIds`, not internal UUIDs or global IDs):
|
|
73
|
+
|
|
74
|
+
- one external ID per line;
|
|
75
|
+
- empty lines are ignored;
|
|
76
|
+
- lines starting with `#` are comments;
|
|
77
|
+
- duplicate IDs are ignored.
|
|
78
|
+
|
|
79
|
+
Example `autotest-external-ids.txt`:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
# smoke suite
|
|
83
|
+
login-test-ext-id
|
|
84
|
+
checkout-test-ext-id
|
|
85
|
+
|
|
86
|
+
payment-test-ext-id
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
testit testrun create launch \
|
|
91
|
+
-u "$TMS_URL" -t "$TMS_TOKEN" \
|
|
92
|
+
-pi "$TMS_PROJECT_ID" -ci "$TMS_CONFIGURATION_ID" \
|
|
93
|
+
-af ./autotest-external-ids.txt
|
|
94
|
+
```
|
|
95
|
+
|
|
34
96
|
## Test run tags and links
|
|
35
97
|
|
|
36
98
|
You can attach **test run** tags and links (for example a CI job URL) via CLI flags or environment variables.
|
|
@@ -3,10 +3,11 @@ from itertools import chain
|
|
|
3
3
|
|
|
4
4
|
import click
|
|
5
5
|
|
|
6
|
+
from .launch_filter import LaunchFilterError, parse_launch_filter, read_autotest_external_ids_file
|
|
6
7
|
from .models.config import Config
|
|
7
8
|
from .service_factory import ServiceFactory
|
|
8
9
|
from .testrun_metadata import parse_testrun_links, parse_testrun_tags
|
|
9
|
-
from .validation import validate_url, validate_uuid
|
|
10
|
+
from .validation import validate_url, validate_url_optional, validate_uuid
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@click.group()
|
|
@@ -178,19 +179,71 @@ def testrun():
|
|
|
178
179
|
pass
|
|
179
180
|
|
|
180
181
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
def _require_create_options(**required_options):
|
|
183
|
+
"""Validate empty-create required options when no subcommand is invoked."""
|
|
184
|
+
for flag, value in required_options.items():
|
|
185
|
+
if value is None or value == "":
|
|
186
|
+
raise click.UsageError(f"Missing option '{flag}'.")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _require_exactly_one_launch_source(
|
|
190
|
+
test_plan_id: typing.Optional[str],
|
|
191
|
+
launch_filter: typing.Optional[str],
|
|
192
|
+
autotest_external_ids_file: typing.Optional[str],
|
|
193
|
+
) -> None:
|
|
194
|
+
sources = [
|
|
195
|
+
bool(test_plan_id),
|
|
196
|
+
bool(launch_filter),
|
|
197
|
+
bool(autotest_external_ids_file),
|
|
198
|
+
]
|
|
199
|
+
if sum(sources) != 1:
|
|
200
|
+
raise click.UsageError(
|
|
201
|
+
"Provide exactly one of: --test-plan-id, --filter, or --autotest-external-ids-file"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _parse_launch_tags(launch_filter: typing.Optional[str]) -> typing.Optional[typing.List[str]]:
|
|
206
|
+
if not launch_filter:
|
|
207
|
+
return None
|
|
208
|
+
try:
|
|
209
|
+
return parse_launch_filter(launch_filter)
|
|
210
|
+
except LaunchFilterError as exc:
|
|
211
|
+
raise click.BadParameter(str(exc), param_hint="--filter") from exc
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _load_autotest_external_ids(path: typing.Optional[str]) -> typing.Optional[typing.List[str]]:
|
|
215
|
+
if not path:
|
|
216
|
+
return None
|
|
217
|
+
autotest_external_ids = read_autotest_external_ids_file(path)
|
|
218
|
+
if not autotest_external_ids:
|
|
219
|
+
raise click.BadParameter(
|
|
220
|
+
"Autotest external ids file is empty (no external IDs)",
|
|
221
|
+
param_hint="--autotest-external-ids-file",
|
|
222
|
+
)
|
|
223
|
+
return autotest_external_ids
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@testrun.group("create", invoke_without_command=True)
|
|
227
|
+
@click.pass_context
|
|
228
|
+
@click.option("-u", "--url", type=str, envvar='TMS_URL', default=None, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url_optional)
|
|
229
|
+
@click.option("-t", "--token", type=str, envvar='TMS_TOKEN', default=None, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
|
|
230
|
+
@click.option("-pi", "--project-id", type=str, envvar='TMS_PROJECT_ID', default=None, help="Set project id (5236eb3f-7c05-46f9-a609-dc0278896464)", callback=validate_uuid)
|
|
231
|
+
@click.option("-tn", "--testrun-name", type=str, envvar='TMS_TEST_RUN_NAME', default=None, help="Set test run name (TestRun01)")
|
|
186
232
|
@click.option("-trt", "--testruntags", type=str, envvar='TMS_TEST_RUN_TAGS', default=None, help=_TESTRUN_TAGS_HELP)
|
|
187
233
|
@click.option("-trl", "--testrunlinks", type=str, envvar='TMS_TEST_RUN_LINKS', default=None, help=_TESTRUN_LINKS_HELP)
|
|
188
|
-
@click.option("-o", "--output", type=str,
|
|
234
|
+
@click.option("-o", "--output", type=str, default=None, help="Set file path for output (FILE)")
|
|
189
235
|
@click.option("-a", "--attachments", multiple=True, type=list, help="Path to attachments for test run (multiple)", default=[], cls=ExtraArgsForOption)
|
|
190
236
|
@click.option("-d", "--debug", is_flag=True, help="Set debug logs")
|
|
191
237
|
@click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
|
|
192
|
-
def create_test_run(url, token, project_id, testrun_name, testruntags, testrunlinks, output, debug, attachments, disable_cert_validation):
|
|
238
|
+
def create_test_run(ctx, url, token, project_id, testrun_name, testruntags, testrunlinks, output, debug, attachments, disable_cert_validation):
|
|
193
239
|
"""Creating a new test run"""
|
|
240
|
+
if ctx.invoked_subcommand is not None:
|
|
241
|
+
return
|
|
242
|
+
|
|
243
|
+
_require_create_options(
|
|
244
|
+
**{"--url": url, "--token": token, "--project-id": project_id, "--output": output}
|
|
245
|
+
)
|
|
246
|
+
|
|
194
247
|
config = Config(
|
|
195
248
|
url=url,
|
|
196
249
|
token=token,
|
|
@@ -208,6 +261,41 @@ def create_test_run(url, token, project_id, testrun_name, testruntags, testrunli
|
|
|
208
261
|
service.create_test_run()
|
|
209
262
|
|
|
210
263
|
|
|
264
|
+
@create_test_run.command("launch")
|
|
265
|
+
@click.option("-u", "--url", type=str, envvar='TMS_URL', required=True, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url)
|
|
266
|
+
@click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
|
|
267
|
+
@click.option("-pi", "--project-id", type=str, envvar='TMS_PROJECT_ID', required=True, help="Set project id (5236eb3f-7c05-46f9-a609-dc0278896464)", callback=validate_uuid)
|
|
268
|
+
@click.option("-ci", "--configuration-id", type=str, envvar='TMS_CONFIGURATION_ID', required=True, help="Set configuration id (15dbb164-c1aa-4cbf-830c-8c01ae14f4fb)", callback=validate_uuid)
|
|
269
|
+
@click.option("-tpi", "--test-plan-id", type=str, envvar='TMS_TEST_PLAN_ID', default=None, help="Create run from test plan (UUID)", callback=validate_uuid)
|
|
270
|
+
@click.option("-f", "--filter", "launch_filter", type=str, default=None, help="TMS filter, e.g. tags=smoke,nightly")
|
|
271
|
+
@click.option("-af", "--autotest-external-ids-file", type=click.Path(exists=True, dir_okay=False, readable=True), default=None, help="File with autotest external IDs (one per line)")
|
|
272
|
+
@click.option("-tn", "--testrun-name", type=str, envvar='TMS_TEST_RUN_NAME', help="Set test run name (TestRun01)", default=None)
|
|
273
|
+
@click.option("-o", "--output", type=str, default=None, help="Optional file path to write test run id")
|
|
274
|
+
@click.option("-d", "--debug", is_flag=True, help="Set debug logs")
|
|
275
|
+
@click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
|
|
276
|
+
def create_launch(url, token, project_id, configuration_id, test_plan_id, launch_filter, autotest_external_ids_file, testrun_name, output, debug, disable_cert_validation):
|
|
277
|
+
"""Create and fill a test run (by plan, tags, or external IDs)"""
|
|
278
|
+
_require_exactly_one_launch_source(test_plan_id, launch_filter, autotest_external_ids_file)
|
|
279
|
+
launch_tags = _parse_launch_tags(launch_filter)
|
|
280
|
+
autotest_external_ids = _load_autotest_external_ids(autotest_external_ids_file)
|
|
281
|
+
|
|
282
|
+
config = Config(
|
|
283
|
+
url=url,
|
|
284
|
+
token=token,
|
|
285
|
+
project_id=project_id,
|
|
286
|
+
configuration_id=configuration_id,
|
|
287
|
+
test_plan_id=test_plan_id,
|
|
288
|
+
launch_tags=launch_tags,
|
|
289
|
+
autotest_external_ids=autotest_external_ids,
|
|
290
|
+
testrun_name=testrun_name,
|
|
291
|
+
is_debug=debug,
|
|
292
|
+
output=output or "",
|
|
293
|
+
disable_cert_validation=disable_cert_validation,
|
|
294
|
+
)
|
|
295
|
+
service = ServiceFactory().get(config)
|
|
296
|
+
service.launch_test_run()
|
|
297
|
+
|
|
298
|
+
|
|
211
299
|
@testrun.command("complete")
|
|
212
300
|
@click.option("-u", "--url", type=str, envvar='TMS_URL', required=True, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url)
|
|
213
301
|
@click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Parsers for `testrun create launch` filter and autotest external ids file."""
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LaunchFilterError(ValueError):
|
|
6
|
+
"""Invalid --filter or external ids file content."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def parse_launch_filter(raw: str) -> typing.List[str]:
|
|
10
|
+
"""
|
|
11
|
+
Parse `--filter tags=tag1,tag2` into a list of tags.
|
|
12
|
+
|
|
13
|
+
Only the `tags=` key is supported.
|
|
14
|
+
"""
|
|
15
|
+
if raw is None:
|
|
16
|
+
raise LaunchFilterError("Filter value is required")
|
|
17
|
+
|
|
18
|
+
value = str(raw).strip()
|
|
19
|
+
if not value:
|
|
20
|
+
raise LaunchFilterError("Filter value is empty")
|
|
21
|
+
|
|
22
|
+
if "=" not in value:
|
|
23
|
+
raise LaunchFilterError(
|
|
24
|
+
f'Unsupported filter "{value}". Expected format: tags=tag1,tag2'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
key, _, rest = value.partition("=")
|
|
28
|
+
key = key.strip().lower()
|
|
29
|
+
if key != "tags":
|
|
30
|
+
raise LaunchFilterError(
|
|
31
|
+
f'Unsupported filter key "{key}". Only tags=... is supported'
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
tags = [t.strip() for t in rest.split(",") if t.strip()]
|
|
35
|
+
if not tags:
|
|
36
|
+
raise LaunchFilterError("Filter tags=... must list at least one tag")
|
|
37
|
+
return tags
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def read_autotest_external_ids_file(path: str) -> typing.List[str]:
|
|
41
|
+
"""
|
|
42
|
+
Read autotest external IDs from a file: one ID per line.
|
|
43
|
+
Empty lines and lines starting with # are ignored.
|
|
44
|
+
"""
|
|
45
|
+
ids: typing.List[str] = []
|
|
46
|
+
seen = set()
|
|
47
|
+
|
|
48
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
49
|
+
for line in handle:
|
|
50
|
+
stripped = line.strip()
|
|
51
|
+
if not stripped or stripped.startswith("#"):
|
|
52
|
+
continue
|
|
53
|
+
if stripped not in seen:
|
|
54
|
+
seen.add(stripped)
|
|
55
|
+
ids.append(stripped)
|
|
56
|
+
|
|
57
|
+
return ids
|
|
@@ -38,3 +38,6 @@ class Config:
|
|
|
38
38
|
framework: str = ""
|
|
39
39
|
ignore_flaky_failure: bool = False
|
|
40
40
|
autotest_layer: typing.Optional[str] = None
|
|
41
|
+
test_plan_id: typing.Optional[str] = None
|
|
42
|
+
launch_tags: typing.Optional[list[str]] = None
|
|
43
|
+
autotest_external_ids: typing.Optional[list[str]] = None
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
+
import click
|
|
4
5
|
from adapters_api.model.assign_attachment_api_model import AssignAttachmentApiModel
|
|
5
6
|
from adapters_api.model.attachment_put_model import AttachmentPutModel
|
|
6
7
|
from .apiclient import ApiClient
|
|
@@ -13,6 +14,7 @@ from .models.config import Config
|
|
|
13
14
|
from .models.testrun import TestRun
|
|
14
15
|
from .parser import Parser
|
|
15
16
|
from .testrun_metadata import merge_links, merge_tags, to_create_link_models, to_update_link_models
|
|
17
|
+
from .v2_client import V2Client
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class Service:
|
|
@@ -22,13 +24,15 @@ class Service:
|
|
|
22
24
|
api_client: ApiClient,
|
|
23
25
|
parser: Parser,
|
|
24
26
|
importer: Importer,
|
|
25
|
-
autotests_filter: AutotestsFilter
|
|
27
|
+
autotests_filter: AutotestsFilter,
|
|
28
|
+
v2_client: typing.Optional[V2Client] = None,
|
|
26
29
|
):
|
|
27
30
|
self.__config = config
|
|
28
31
|
self.__api_client = api_client
|
|
29
32
|
self.__parser = parser
|
|
30
33
|
self.__importer = importer
|
|
31
34
|
self.__autotests_filter = autotests_filter
|
|
35
|
+
self.__v2_client = v2_client
|
|
32
36
|
|
|
33
37
|
def import_results(self):
|
|
34
38
|
self.__upload_results()
|
|
@@ -43,6 +47,49 @@ class Service:
|
|
|
43
47
|
|
|
44
48
|
self.__write_to_output(test_run.id)
|
|
45
49
|
|
|
50
|
+
def launch_test_run(self) -> None:
|
|
51
|
+
if self.__v2_client is None:
|
|
52
|
+
raise RuntimeError("V2Client is required for testrun create launch")
|
|
53
|
+
|
|
54
|
+
if self.__config.test_plan_id:
|
|
55
|
+
work_item_ids = self.__v2_client.search_test_point_work_item_ids(
|
|
56
|
+
self.__config.test_plan_id,
|
|
57
|
+
self.__config.configuration_id,
|
|
58
|
+
)
|
|
59
|
+
if not work_item_ids:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
"No automated work items found for the given test plan and configuration"
|
|
62
|
+
)
|
|
63
|
+
test_run_id = self.__v2_client.create_run_by_work_items(
|
|
64
|
+
self.__config.project_id,
|
|
65
|
+
self.__config.test_plan_id,
|
|
66
|
+
self.__config.configuration_id,
|
|
67
|
+
work_item_ids,
|
|
68
|
+
name=self.__config.testrun_name,
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
external_ids = self.__config.autotest_external_ids
|
|
72
|
+
if external_ids is None and self.__config.launch_tags:
|
|
73
|
+
external_ids = self.__v2_client.search_autotest_external_ids(
|
|
74
|
+
self.__config.project_id,
|
|
75
|
+
self.__config.launch_tags,
|
|
76
|
+
)
|
|
77
|
+
if not external_ids:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
"No autotest external IDs resolved for launch "
|
|
80
|
+
"(empty search result or empty ids file)"
|
|
81
|
+
)
|
|
82
|
+
test_run_id = self.__v2_client.create_run_by_auto_tests(
|
|
83
|
+
self.__config.project_id,
|
|
84
|
+
self.__config.configuration_id,
|
|
85
|
+
external_ids,
|
|
86
|
+
name=self.__config.testrun_name,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
click.echo(test_run_id)
|
|
90
|
+
if self.__config.output:
|
|
91
|
+
self.__write_to_output(test_run_id)
|
|
92
|
+
|
|
46
93
|
def rerun_test_run(self) -> None:
|
|
47
94
|
self.__api_client.rerun_test_run(
|
|
48
95
|
self.__config.testrun_id,
|
|
@@ -5,6 +5,7 @@ from .logger import Logger
|
|
|
5
5
|
from .models.config import Config
|
|
6
6
|
from .parser import Parser
|
|
7
7
|
from .service import Service
|
|
8
|
+
from .v2_client import V2Client
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class ServiceFactory:
|
|
@@ -13,8 +14,9 @@ class ServiceFactory:
|
|
|
13
14
|
Logger.register_logger(config.is_debug)
|
|
14
15
|
|
|
15
16
|
api_client = ApiClient(config.url, config.token, config.disable_cert_validation)
|
|
17
|
+
v2_client = V2Client(config.url, config.token, config.disable_cert_validation)
|
|
16
18
|
parser = Parser(config)
|
|
17
19
|
importer = Importer(api_client, config)
|
|
18
20
|
autotests_filter = AutotestsFilter(api_client, config)
|
|
19
21
|
|
|
20
|
-
return Service(config, api_client, parser, importer, autotests_filter)
|
|
22
|
+
return Service(config, api_client, parser, importer, autotests_filter, v2_client)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Thin public v2 API client for testrun create launch (urllib3, no testit-api-client)."""
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import typing
|
|
5
|
+
from urllib.parse import urljoin
|
|
6
|
+
|
|
7
|
+
import urllib3
|
|
8
|
+
|
|
9
|
+
from .http_retry import with_http_retries
|
|
10
|
+
|
|
11
|
+
_PAGE_SIZE = 100
|
|
12
|
+
_LAUNCH_SOURCE = "testit-cli"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class V2ApiError(Exception):
|
|
16
|
+
"""Raised when a v2 API call returns a non-success status."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, status: int, body: str, path: str):
|
|
19
|
+
self.status = status
|
|
20
|
+
self.body = body
|
|
21
|
+
self.path = path
|
|
22
|
+
super().__init__(f"v2 {path} failed with HTTP {status}: {body}")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class V2Client:
|
|
26
|
+
"""HTTP client for selected /api/v2 endpoints used by `testrun create launch`."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, url: str, token: str, disable_cert_validation: bool = False):
|
|
29
|
+
base = url.rstrip("/") + "/"
|
|
30
|
+
self.__base_url = base
|
|
31
|
+
self.__headers = {
|
|
32
|
+
"Authorization": f"PrivateToken {token}",
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
"Accept": "application/json",
|
|
35
|
+
}
|
|
36
|
+
self.__http = urllib3.PoolManager(
|
|
37
|
+
cert_reqs="CERT_NONE" if disable_cert_validation else "CERT_REQUIRED",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def search_autotest_external_ids(
|
|
41
|
+
self,
|
|
42
|
+
project_id: str,
|
|
43
|
+
tags: typing.List[str],
|
|
44
|
+
) -> typing.List[str]:
|
|
45
|
+
"""Paginate POST /api/v2/autoTests/search; return unique externalIds."""
|
|
46
|
+
filter_body = {
|
|
47
|
+
"filter": {
|
|
48
|
+
"projectIds": [project_id],
|
|
49
|
+
"tags": tags,
|
|
50
|
+
"isDeleted": False,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
external_ids: typing.List[str] = []
|
|
54
|
+
seen = set()
|
|
55
|
+
skip = 0
|
|
56
|
+
|
|
57
|
+
while True:
|
|
58
|
+
page = self.__post_json(
|
|
59
|
+
"/api/v2/autoTests/search",
|
|
60
|
+
filter_body,
|
|
61
|
+
query={"skip": skip, "take": _PAGE_SIZE},
|
|
62
|
+
label="Search autotests",
|
|
63
|
+
)
|
|
64
|
+
if not isinstance(page, list) or not page:
|
|
65
|
+
break
|
|
66
|
+
for item in page:
|
|
67
|
+
external_id = item.get("externalId") if isinstance(item, dict) else None
|
|
68
|
+
if external_id and external_id not in seen:
|
|
69
|
+
seen.add(external_id)
|
|
70
|
+
external_ids.append(external_id)
|
|
71
|
+
if len(page) < _PAGE_SIZE:
|
|
72
|
+
break
|
|
73
|
+
skip += _PAGE_SIZE
|
|
74
|
+
|
|
75
|
+
logging.info("Found %s autotest external id(s) by tags=%s", len(external_ids), tags)
|
|
76
|
+
return external_ids
|
|
77
|
+
|
|
78
|
+
def search_test_point_work_item_ids(
|
|
79
|
+
self,
|
|
80
|
+
test_plan_id: str,
|
|
81
|
+
configuration_id: str,
|
|
82
|
+
) -> typing.List[str]:
|
|
83
|
+
"""Paginate POST /api/v2/testPoints/search; return unique workItemIds."""
|
|
84
|
+
# Body is TestPointFilterModel fields at the top level (not nested under "filter").
|
|
85
|
+
filter_body = {
|
|
86
|
+
"testPlanIds": [test_plan_id],
|
|
87
|
+
"configurationIds": [configuration_id],
|
|
88
|
+
"isAutomated": True,
|
|
89
|
+
}
|
|
90
|
+
work_item_ids: typing.List[str] = []
|
|
91
|
+
seen = set()
|
|
92
|
+
skip = 0
|
|
93
|
+
|
|
94
|
+
while True:
|
|
95
|
+
page = self.__post_json(
|
|
96
|
+
"/api/v2/testPoints/search",
|
|
97
|
+
filter_body,
|
|
98
|
+
query={"skip": skip, "take": _PAGE_SIZE},
|
|
99
|
+
label="Search test points",
|
|
100
|
+
)
|
|
101
|
+
if not isinstance(page, list) or not page:
|
|
102
|
+
break
|
|
103
|
+
for item in page:
|
|
104
|
+
work_item_id = item.get("workItemId") if isinstance(item, dict) else None
|
|
105
|
+
if work_item_id and work_item_id not in seen:
|
|
106
|
+
seen.add(work_item_id)
|
|
107
|
+
work_item_ids.append(work_item_id)
|
|
108
|
+
if len(page) < _PAGE_SIZE:
|
|
109
|
+
break
|
|
110
|
+
skip += _PAGE_SIZE
|
|
111
|
+
|
|
112
|
+
logging.info(
|
|
113
|
+
"Found %s work item id(s) for test plan %s / configuration %s",
|
|
114
|
+
len(work_item_ids),
|
|
115
|
+
test_plan_id,
|
|
116
|
+
configuration_id,
|
|
117
|
+
)
|
|
118
|
+
return work_item_ids
|
|
119
|
+
|
|
120
|
+
def create_run_by_auto_tests(
|
|
121
|
+
self,
|
|
122
|
+
project_id: str,
|
|
123
|
+
configuration_id: str,
|
|
124
|
+
auto_test_external_ids: typing.List[str],
|
|
125
|
+
name: typing.Optional[str] = None,
|
|
126
|
+
) -> str:
|
|
127
|
+
"""POST /api/v2/testRuns/byAutoTests; return test run id."""
|
|
128
|
+
body: typing.Dict[str, typing.Any] = {
|
|
129
|
+
"projectId": project_id,
|
|
130
|
+
"configurationIds": [configuration_id],
|
|
131
|
+
"autoTestExternalIds": auto_test_external_ids,
|
|
132
|
+
"launchSource": _LAUNCH_SOURCE,
|
|
133
|
+
}
|
|
134
|
+
if name:
|
|
135
|
+
body["name"] = name
|
|
136
|
+
|
|
137
|
+
result = self.__post_json(
|
|
138
|
+
"/api/v2/testRuns/byAutoTests",
|
|
139
|
+
body,
|
|
140
|
+
label="Create test run by auto tests",
|
|
141
|
+
)
|
|
142
|
+
run_id = result.get("id") if isinstance(result, dict) else None
|
|
143
|
+
if not run_id:
|
|
144
|
+
raise V2ApiError(200, str(result), "/api/v2/testRuns/byAutoTests")
|
|
145
|
+
logging.info("Created testrun by auto tests (ID: %s)", run_id)
|
|
146
|
+
return run_id
|
|
147
|
+
|
|
148
|
+
def create_run_by_work_items(
|
|
149
|
+
self,
|
|
150
|
+
project_id: str,
|
|
151
|
+
test_plan_id: str,
|
|
152
|
+
configuration_id: str,
|
|
153
|
+
work_item_ids: typing.List[str],
|
|
154
|
+
name: typing.Optional[str] = None,
|
|
155
|
+
) -> str:
|
|
156
|
+
"""POST /api/v2/testRuns/byWorkItems; return test run id."""
|
|
157
|
+
body: typing.Dict[str, typing.Any] = {
|
|
158
|
+
"projectId": project_id,
|
|
159
|
+
"testPlanId": test_plan_id,
|
|
160
|
+
"configurationIds": [configuration_id],
|
|
161
|
+
"workItemIds": work_item_ids,
|
|
162
|
+
"launchSource": _LAUNCH_SOURCE,
|
|
163
|
+
}
|
|
164
|
+
if name:
|
|
165
|
+
body["name"] = name
|
|
166
|
+
|
|
167
|
+
result = self.__post_json(
|
|
168
|
+
"/api/v2/testRuns/byWorkItems",
|
|
169
|
+
body,
|
|
170
|
+
label="Create test run by work items",
|
|
171
|
+
)
|
|
172
|
+
run_id = result.get("id") if isinstance(result, dict) else None
|
|
173
|
+
if not run_id:
|
|
174
|
+
raise V2ApiError(200, str(result), "/api/v2/testRuns/byWorkItems")
|
|
175
|
+
logging.info("Created testrun by work items (ID: %s)", run_id)
|
|
176
|
+
return run_id
|
|
177
|
+
|
|
178
|
+
def __post_json(
|
|
179
|
+
self,
|
|
180
|
+
path: str,
|
|
181
|
+
body: typing.Dict[str, typing.Any],
|
|
182
|
+
query: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
183
|
+
label: str = "v2 request",
|
|
184
|
+
) -> typing.Any:
|
|
185
|
+
url = urljoin(self.__base_url, path.lstrip("/"))
|
|
186
|
+
if query:
|
|
187
|
+
qs = "&".join(f"{k}={v}" for k, v in query.items())
|
|
188
|
+
url = f"{url}?{qs}"
|
|
189
|
+
|
|
190
|
+
encoded = json.dumps(body).encode("utf-8")
|
|
191
|
+
logging.debug("%s POST %s body=%s", label, url, body)
|
|
192
|
+
|
|
193
|
+
def _do_request():
|
|
194
|
+
response = self.__http.request(
|
|
195
|
+
"POST",
|
|
196
|
+
url,
|
|
197
|
+
body=encoded,
|
|
198
|
+
headers=self.__headers,
|
|
199
|
+
)
|
|
200
|
+
raw = response.data.decode("utf-8") if response.data else ""
|
|
201
|
+
if response.status < 200 or response.status >= 300:
|
|
202
|
+
raise V2ApiError(response.status, raw, path)
|
|
203
|
+
if not raw:
|
|
204
|
+
return None
|
|
205
|
+
return json.loads(raw)
|
|
206
|
+
|
|
207
|
+
return with_http_retries(_do_request, label=label)
|
|
@@ -27,3 +27,10 @@ def validate_url(ctx, param, value):
|
|
|
27
27
|
return value[:-1]
|
|
28
28
|
|
|
29
29
|
return value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate_url_optional(ctx, param, value):
|
|
33
|
+
"""Like validate_url, but allows missing value (optional group options)."""
|
|
34
|
+
if value is None:
|
|
35
|
+
return value
|
|
36
|
+
return validate_url(ctx, param, value)
|