cumulusci-plus 5.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of cumulusci-plus might be problematic. Click here for more details.
- cumulusci/__about__.py +1 -0
- cumulusci/__init__.py +22 -0
- cumulusci/__main__.py +3 -0
- cumulusci/cli/__init__.py +0 -0
- cumulusci/cli/cci.py +244 -0
- cumulusci/cli/error.py +125 -0
- cumulusci/cli/flow.py +185 -0
- cumulusci/cli/logger.py +72 -0
- cumulusci/cli/org.py +692 -0
- cumulusci/cli/plan.py +181 -0
- cumulusci/cli/project.py +391 -0
- cumulusci/cli/robot.py +116 -0
- cumulusci/cli/runtime.py +190 -0
- cumulusci/cli/service.py +521 -0
- cumulusci/cli/task.py +295 -0
- cumulusci/cli/tests/__init__.py +0 -0
- cumulusci/cli/tests/test_cci.py +545 -0
- cumulusci/cli/tests/test_error.py +170 -0
- cumulusci/cli/tests/test_flow.py +276 -0
- cumulusci/cli/tests/test_logger.py +25 -0
- cumulusci/cli/tests/test_org.py +1438 -0
- cumulusci/cli/tests/test_plan.py +245 -0
- cumulusci/cli/tests/test_project.py +235 -0
- cumulusci/cli/tests/test_robot.py +177 -0
- cumulusci/cli/tests/test_runtime.py +197 -0
- cumulusci/cli/tests/test_service.py +853 -0
- cumulusci/cli/tests/test_task.py +266 -0
- cumulusci/cli/tests/test_ui.py +310 -0
- cumulusci/cli/tests/test_utils.py +122 -0
- cumulusci/cli/tests/utils.py +52 -0
- cumulusci/cli/ui.py +234 -0
- cumulusci/cli/utils.py +150 -0
- cumulusci/conftest.py +181 -0
- cumulusci/core/__init__.py +0 -0
- cumulusci/core/config/BaseConfig.py +5 -0
- cumulusci/core/config/BaseTaskFlowConfig.py +5 -0
- cumulusci/core/config/OrgConfig.py +5 -0
- cumulusci/core/config/ScratchOrgConfig.py +5 -0
- cumulusci/core/config/__init__.py +125 -0
- cumulusci/core/config/base_config.py +111 -0
- cumulusci/core/config/base_task_flow_config.py +82 -0
- cumulusci/core/config/marketing_cloud_service_config.py +83 -0
- cumulusci/core/config/oauth2_service_config.py +17 -0
- cumulusci/core/config/org_config.py +604 -0
- cumulusci/core/config/project_config.py +782 -0
- cumulusci/core/config/scratch_org_config.py +251 -0
- cumulusci/core/config/sfdx_org_config.py +220 -0
- cumulusci/core/config/tests/_test_config_backwards_compatibility.py +33 -0
- cumulusci/core/config/tests/test_config.py +1895 -0
- cumulusci/core/config/tests/test_config_expensive.py +839 -0
- cumulusci/core/config/tests/test_config_util.py +91 -0
- cumulusci/core/config/universal_config.py +88 -0
- cumulusci/core/config/util.py +18 -0
- cumulusci/core/datasets.py +303 -0
- cumulusci/core/debug.py +33 -0
- cumulusci/core/dependencies/__init__.py +55 -0
- cumulusci/core/dependencies/base.py +561 -0
- cumulusci/core/dependencies/dependencies.py +273 -0
- cumulusci/core/dependencies/github.py +177 -0
- cumulusci/core/dependencies/github_resolvers.py +244 -0
- cumulusci/core/dependencies/resolvers.py +580 -0
- cumulusci/core/dependencies/tests/__init__.py +0 -0
- cumulusci/core/dependencies/tests/conftest.py +385 -0
- cumulusci/core/dependencies/tests/test_dependencies.py +950 -0
- cumulusci/core/dependencies/tests/test_github.py +83 -0
- cumulusci/core/dependencies/tests/test_resolvers.py +1027 -0
- cumulusci/core/dependencies/utils.py +13 -0
- cumulusci/core/enums.py +11 -0
- cumulusci/core/exceptions.py +311 -0
- cumulusci/core/flowrunner.py +888 -0
- cumulusci/core/github.py +665 -0
- cumulusci/core/keychain/__init__.py +24 -0
- cumulusci/core/keychain/base_project_keychain.py +441 -0
- cumulusci/core/keychain/encrypted_file_project_keychain.py +945 -0
- cumulusci/core/keychain/environment_project_keychain.py +7 -0
- cumulusci/core/keychain/serialization.py +152 -0
- cumulusci/core/keychain/subprocess_keychain.py +24 -0
- cumulusci/core/keychain/tests/conftest.py +50 -0
- cumulusci/core/keychain/tests/test_base_project_keychain.py +299 -0
- cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py +1228 -0
- cumulusci/core/metadeploy/__init__.py +0 -0
- cumulusci/core/metadeploy/api.py +88 -0
- cumulusci/core/metadeploy/plans.py +25 -0
- cumulusci/core/metadeploy/tests/test_api.py +276 -0
- cumulusci/core/runtime.py +115 -0
- cumulusci/core/sfdx.py +162 -0
- cumulusci/core/source/__init__.py +16 -0
- cumulusci/core/source/github.py +50 -0
- cumulusci/core/source/local_folder.py +35 -0
- cumulusci/core/source_transforms/__init__.py +0 -0
- cumulusci/core/source_transforms/tests/test_transforms.py +1091 -0
- cumulusci/core/source_transforms/transforms.py +532 -0
- cumulusci/core/tasks.py +404 -0
- cumulusci/core/template_utils.py +59 -0
- cumulusci/core/tests/__init__.py +0 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_e2e.yaml +215 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_extract_standard_objects.yaml +199 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_read_explicit_extract_declaration.yaml +3 -0
- cumulusci/core/tests/fake_remote_repo/cumulusci.yml +32 -0
- cumulusci/core/tests/fake_remote_repo/tasks/directory/example_2.py +6 -0
- cumulusci/core/tests/fake_remote_repo/tasks/example.py +43 -0
- cumulusci/core/tests/fake_remote_repo_2/cumulusci.yml +11 -0
- cumulusci/core/tests/fake_remote_repo_2/tasks/example_3.py +6 -0
- cumulusci/core/tests/test_datasets_e2e.py +386 -0
- cumulusci/core/tests/test_exceptions.py +11 -0
- cumulusci/core/tests/test_flowrunner.py +836 -0
- cumulusci/core/tests/test_github.py +942 -0
- cumulusci/core/tests/test_sfdx.py +138 -0
- cumulusci/core/tests/test_source.py +678 -0
- cumulusci/core/tests/test_tasks.py +262 -0
- cumulusci/core/tests/test_utils.py +141 -0
- cumulusci/core/tests/test_utils_merge_config.py +276 -0
- cumulusci/core/tests/test_versions.py +76 -0
- cumulusci/core/tests/untrusted_repo_child/cumulusci.yml +7 -0
- cumulusci/core/tests/untrusted_repo_child/tasks/untrusted_child.py +6 -0
- cumulusci/core/tests/untrusted_repo_parent/cumulusci.yml +26 -0
- cumulusci/core/tests/untrusted_repo_parent/tasks/untrusted_parent.py +6 -0
- cumulusci/core/tests/utils.py +116 -0
- cumulusci/core/tests/yaml/global.yaml +0 -0
- cumulusci/core/utils.py +402 -0
- cumulusci/core/versions.py +149 -0
- cumulusci/cumulusci.yml +1621 -0
- cumulusci/files/admin_profile.xml +20 -0
- cumulusci/files/delete_excludes.txt +424 -0
- cumulusci/files/templates/project/README.md +12 -0
- cumulusci/files/templates/project/cumulusci.yml +63 -0
- cumulusci/files/templates/project/dot-gitignore +60 -0
- cumulusci/files/templates/project/mapping.yml +45 -0
- cumulusci/files/templates/project/scratch_def.json +25 -0
- cumulusci/oauth/__init__.py +0 -0
- cumulusci/oauth/client.py +400 -0
- cumulusci/oauth/exceptions.py +9 -0
- cumulusci/oauth/salesforce.py +95 -0
- cumulusci/oauth/tests/__init__.py +0 -0
- cumulusci/oauth/tests/cassettes/test_get_device_code.yaml +22 -0
- cumulusci/oauth/tests/cassettes/test_get_device_oauth_token.yaml +74 -0
- cumulusci/oauth/tests/test_client.py +308 -0
- cumulusci/oauth/tests/test_salesforce.py +46 -0
- cumulusci/plugins/__init__.py +3 -0
- cumulusci/plugins/plugin_base.py +93 -0
- cumulusci/plugins/plugin_loader.py +59 -0
- cumulusci/robotframework/CumulusCI.py +340 -0
- cumulusci/robotframework/CumulusCI.robot +7 -0
- cumulusci/robotframework/Performance.py +165 -0
- cumulusci/robotframework/Salesforce.py +936 -0
- cumulusci/robotframework/Salesforce.robot +192 -0
- cumulusci/robotframework/SalesforceAPI.py +416 -0
- cumulusci/robotframework/SalesforcePlaywright.py +220 -0
- cumulusci/robotframework/SalesforcePlaywright.robot +40 -0
- cumulusci/robotframework/__init__.py +2 -0
- cumulusci/robotframework/base_library.py +39 -0
- cumulusci/robotframework/faker_mixin.py +89 -0
- cumulusci/robotframework/form_handlers.py +222 -0
- cumulusci/robotframework/javascript/cci_init.js +34 -0
- cumulusci/robotframework/javascript/cumulusci.js +4 -0
- cumulusci/robotframework/locator_manager.py +197 -0
- cumulusci/robotframework/locators_56.py +88 -0
- cumulusci/robotframework/locators_57.py +5 -0
- cumulusci/robotframework/pageobjects/BasePageObjects.py +433 -0
- cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +246 -0
- cumulusci/robotframework/pageobjects/PageObjectLibrary.py +45 -0
- cumulusci/robotframework/pageobjects/PageObjects.py +351 -0
- cumulusci/robotframework/pageobjects/__init__.py +12 -0
- cumulusci/robotframework/pageobjects/baseobjects.py +120 -0
- cumulusci/robotframework/perftests/short/collection_perf.robot +105 -0
- cumulusci/robotframework/tests/CustomObjectTestPage.py +10 -0
- cumulusci/robotframework/tests/FooTestPage.py +8 -0
- cumulusci/robotframework/tests/cumulusci/base.robot +40 -0
- cumulusci/robotframework/tests/cumulusci/bulkdata.robot +38 -0
- cumulusci/robotframework/tests/cumulusci/communities.robot +57 -0
- cumulusci/robotframework/tests/cumulusci/datagen.robot +84 -0
- cumulusci/robotframework/tests/salesforce/TestLibraryA.py +24 -0
- cumulusci/robotframework/tests/salesforce/TestLibraryB.py +20 -0
- cumulusci/robotframework/tests/salesforce/TestListener.py +93 -0
- cumulusci/robotframework/tests/salesforce/api.robot +178 -0
- cumulusci/robotframework/tests/salesforce/browsers.robot +143 -0
- cumulusci/robotframework/tests/salesforce/classic.robot +51 -0
- cumulusci/robotframework/tests/salesforce/create_contact.robot +59 -0
- cumulusci/robotframework/tests/salesforce/faker.robot +68 -0
- cumulusci/robotframework/tests/salesforce/forms.robot +172 -0
- cumulusci/robotframework/tests/salesforce/label_locator.robot +244 -0
- cumulusci/robotframework/tests/salesforce/labels.html +33 -0
- cumulusci/robotframework/tests/salesforce/locators.robot +149 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/base_pageobjects.robot +100 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/example_page_object.py +25 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/listing_page.robot +115 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/objectmanager.robot +74 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/pageobjects.robot +171 -0
- cumulusci/robotframework/tests/salesforce/performance.robot +109 -0
- cumulusci/robotframework/tests/salesforce/playwright/javascript_keywords.robot +33 -0
- cumulusci/robotframework/tests/salesforce/playwright/open_test_browser.robot +48 -0
- cumulusci/robotframework/tests/salesforce/playwright/playwright.robot +24 -0
- cumulusci/robotframework/tests/salesforce/playwright/ui.robot +32 -0
- cumulusci/robotframework/tests/salesforce/populate.robot +89 -0
- cumulusci/robotframework/tests/salesforce/test_testlistener.py +37 -0
- cumulusci/robotframework/tests/salesforce/ui.robot +361 -0
- cumulusci/robotframework/tests/test_cumulusci_library.py +304 -0
- cumulusci/robotframework/tests/test_locator_manager.py +158 -0
- cumulusci/robotframework/tests/test_pageobjects.py +291 -0
- cumulusci/robotframework/tests/test_performance.py +38 -0
- cumulusci/robotframework/tests/test_salesforce.py +79 -0
- cumulusci/robotframework/tests/test_salesforce_locators.py +73 -0
- cumulusci/robotframework/tests/test_template_util.py +53 -0
- cumulusci/robotframework/tests/test_utils.py +106 -0
- cumulusci/robotframework/utils.py +283 -0
- cumulusci/salesforce_api/__init__.py +0 -0
- cumulusci/salesforce_api/exceptions.py +23 -0
- cumulusci/salesforce_api/filterable_objects.py +96 -0
- cumulusci/salesforce_api/mc_soap_envelopes.py +89 -0
- cumulusci/salesforce_api/metadata.py +721 -0
- cumulusci/salesforce_api/org_schema.py +571 -0
- cumulusci/salesforce_api/org_schema_models.py +226 -0
- cumulusci/salesforce_api/package_install.py +265 -0
- cumulusci/salesforce_api/package_zip.py +301 -0
- cumulusci/salesforce_api/rest_deploy.py +148 -0
- cumulusci/salesforce_api/retrieve_profile_api.py +301 -0
- cumulusci/salesforce_api/soap_envelopes.py +177 -0
- cumulusci/salesforce_api/tests/__init__.py +0 -0
- cumulusci/salesforce_api/tests/metadata_test_strings.py +24 -0
- cumulusci/salesforce_api/tests/test_metadata.py +1015 -0
- cumulusci/salesforce_api/tests/test_package_install.py +219 -0
- cumulusci/salesforce_api/tests/test_package_zip.py +380 -0
- cumulusci/salesforce_api/tests/test_rest_deploy.py +264 -0
- cumulusci/salesforce_api/tests/test_retrieve_profile_api.py +337 -0
- cumulusci/salesforce_api/tests/test_utils.py +124 -0
- cumulusci/salesforce_api/utils.py +51 -0
- cumulusci/schema/cumulusci.jsonschema.json +782 -0
- cumulusci/tasks/__init__.py +0 -0
- cumulusci/tasks/apex/__init__.py +0 -0
- cumulusci/tasks/apex/anon.py +157 -0
- cumulusci/tasks/apex/batch.py +180 -0
- cumulusci/tasks/apex/testrunner.py +835 -0
- cumulusci/tasks/apex/tests/cassettes/ManualEditTestApexIntegrationTests.test_run_tests__integration_test.yaml +703 -0
- cumulusci/tasks/apex/tests/test_apex_tasks.py +1558 -0
- cumulusci/tasks/base_source_control_task.py +17 -0
- cumulusci/tasks/bulkdata/__init__.py +15 -0
- cumulusci/tasks/bulkdata/base_generate_data_task.py +96 -0
- cumulusci/tasks/bulkdata/dates.py +97 -0
- cumulusci/tasks/bulkdata/delete.py +156 -0
- cumulusci/tasks/bulkdata/extract.py +441 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/calculate_dependencies.py +117 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +123 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py +49 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +283 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +142 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_synthesize_extract_declarations.py +575 -0
- cumulusci/tasks/bulkdata/factory_utils.py +134 -0
- cumulusci/tasks/bulkdata/generate.py +4 -0
- cumulusci/tasks/bulkdata/generate_and_load_data.py +232 -0
- cumulusci/tasks/bulkdata/generate_and_load_data_from_yaml.py +19 -0
- cumulusci/tasks/bulkdata/generate_from_yaml.py +183 -0
- cumulusci/tasks/bulkdata/generate_mapping.py +434 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/dependency_map.py +169 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/extract_mapping_file_generator.py +45 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/generate_mapping_from_declarations.py +121 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/load_mapping_file_generator.py +127 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_generator_post_processes.py +53 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_transforms.py +139 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_extract_mapping_from_declarations.py +135 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_load_mapping_from_declarations.py +330 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_generator_post_processes.py +60 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_transforms.py +188 -0
- cumulusci/tasks/bulkdata/load.py +1196 -0
- cumulusci/tasks/bulkdata/mapping_parser.py +811 -0
- cumulusci/tasks/bulkdata/query_transformers.py +264 -0
- cumulusci/tasks/bulkdata/select_utils.py +792 -0
- cumulusci/tasks/bulkdata/snowfakery.py +753 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/queue_manager.py +478 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_run_until.py +141 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_working_directory.py +53 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/subtask_configurator.py +64 -0
- cumulusci/tasks/bulkdata/step.py +1242 -0
- cumulusci/tasks/bulkdata/tests/__init__.py +0 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_random_strategy.yaml +147 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_annoy_strategy.yaml +123 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy.yaml +313 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy_bulk.yaml +550 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_strategy.yaml +175 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_standard_strategy.yaml +147 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__multiple_needed.yaml +69 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__none_needed.yaml +22 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__one_needed.yaml +24 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_snowfakery_query_salesforce.yaml +25 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpdatesIntegrationTests.test_updates_task.yaml +80 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_simple_upsert__rest.yaml +270 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert__rest.yaml +267 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field__rest.yaml +369 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field_rest__duplicate_error.yaml +204 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_fields__bulk.yaml +675 -0
- cumulusci/tasks/bulkdata/tests/dummy_data_factory.py +36 -0
- cumulusci/tasks/bulkdata/tests/integration_test_utils.py +49 -0
- cumulusci/tasks/bulkdata/tests/mapping-oid.yml +87 -0
- cumulusci/tasks/bulkdata/tests/mapping_after.yml +38 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly.yml +34 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly_incomplete.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly_wrong.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_strategy.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_number.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_strategy.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__non_float.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_missing_priority_fields.yml +22 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_no_priority_fields.yml +18 -0
- cumulusci/tasks/bulkdata/tests/mapping_simple.yml +27 -0
- cumulusci/tasks/bulkdata/tests/mapping_v1.yml +28 -0
- cumulusci/tasks/bulkdata/tests/mapping_v2.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_v3.yml +32 -0
- cumulusci/tasks/bulkdata/tests/mapping_vanilla_sf.yml +69 -0
- cumulusci/tasks/bulkdata/tests/mock_data_factory_without_mapping.py +12 -0
- cumulusci/tasks/bulkdata/tests/person_accounts.yml +23 -0
- cumulusci/tasks/bulkdata/tests/person_accounts_minimal.yml +15 -0
- cumulusci/tasks/bulkdata/tests/recordtypes.yml +8 -0
- cumulusci/tasks/bulkdata/tests/recordtypes_2.yml +6 -0
- cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml +8 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/child/child2.yml +3 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/child.yml +4 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/gen_npsp_standard_objects.recipe.yml +89 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/include_parent.yml +3 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/npsp_standard_objects_macros.yml +34 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/options.recipe.yml +6 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/query_snowfakery.recipe.yml +16 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/sf_standard_object_macros.yml +83 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.load.yml +2 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.recipe.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_2.load.yml +5 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.load.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.recipe.yml +12 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels_2.load.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/unique_values.recipe.yml +4 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert.recipe.yml +23 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert_2.recipe.yml +29 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert_before.yml +10 -0
- cumulusci/tasks/bulkdata/tests/test_base_generate_data_tasks.py +61 -0
- cumulusci/tasks/bulkdata/tests/test_dates.py +99 -0
- cumulusci/tasks/bulkdata/tests/test_delete.py +404 -0
- cumulusci/tasks/bulkdata/tests/test_extract.py +1311 -0
- cumulusci/tasks/bulkdata/tests/test_factory_utils.py +55 -0
- cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +252 -0
- cumulusci/tasks/bulkdata/tests/test_generate_from_snowfakery_task.py +343 -0
- cumulusci/tasks/bulkdata/tests/test_generatemapping.py +1039 -0
- cumulusci/tasks/bulkdata/tests/test_load.py +3175 -0
- cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +1658 -0
- cumulusci/tasks/bulkdata/tests/test_query_db__joins_self_lookups.yml +12 -0
- cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups.yml +26 -0
- cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups_select.yml +48 -0
- cumulusci/tasks/bulkdata/tests/test_select.py +171 -0
- cumulusci/tasks/bulkdata/tests/test_select_utils.py +1057 -0
- cumulusci/tasks/bulkdata/tests/test_snowfakery.py +1153 -0
- cumulusci/tasks/bulkdata/tests/test_step.py +3957 -0
- cumulusci/tasks/bulkdata/tests/test_updates.py +513 -0
- cumulusci/tasks/bulkdata/tests/test_upsert.py +1015 -0
- cumulusci/tasks/bulkdata/tests/test_utils.py +158 -0
- cumulusci/tasks/bulkdata/tests/testdata.db +0 -0
- cumulusci/tasks/bulkdata/tests/update_describe.py +50 -0
- cumulusci/tasks/bulkdata/tests/update_person_accounts.yml +23 -0
- cumulusci/tasks/bulkdata/tests/utils.py +114 -0
- cumulusci/tasks/bulkdata/update_data.py +260 -0
- cumulusci/tasks/bulkdata/upsert_utils.py +130 -0
- cumulusci/tasks/bulkdata/utils.py +249 -0
- cumulusci/tasks/command.py +178 -0
- cumulusci/tasks/connectedapp.py +186 -0
- cumulusci/tasks/create_package_version.py +778 -0
- cumulusci/tasks/datadictionary.py +745 -0
- cumulusci/tasks/dx_convert_from.py +26 -0
- cumulusci/tasks/github/__init__.py +17 -0
- cumulusci/tasks/github/base.py +16 -0
- cumulusci/tasks/github/commit_status.py +13 -0
- cumulusci/tasks/github/merge.py +11 -0
- cumulusci/tasks/github/publish.py +11 -0
- cumulusci/tasks/github/pull_request.py +11 -0
- cumulusci/tasks/github/release.py +11 -0
- cumulusci/tasks/github/release_report.py +11 -0
- cumulusci/tasks/github/tag.py +11 -0
- cumulusci/tasks/github/tests/__init__.py +0 -0
- cumulusci/tasks/github/tests/test_util.py +202 -0
- cumulusci/tasks/github/tests/test_vcs_migration.py +44 -0
- cumulusci/tasks/github/tests/util_github_api.py +666 -0
- cumulusci/tasks/github/util.py +252 -0
- cumulusci/tasks/marketing_cloud/__init__.py +0 -0
- cumulusci/tasks/marketing_cloud/api.py +188 -0
- cumulusci/tasks/marketing_cloud/base.py +38 -0
- cumulusci/tasks/marketing_cloud/deploy.py +345 -0
- cumulusci/tasks/marketing_cloud/get_user_info.py +40 -0
- cumulusci/tasks/marketing_cloud/mc_constants.py +1 -0
- cumulusci/tasks/marketing_cloud/tests/__init__.py +0 -0
- cumulusci/tasks/marketing_cloud/tests/conftest.py +46 -0
- cumulusci/tasks/marketing_cloud/tests/expected-payload.json +110 -0
- cumulusci/tasks/marketing_cloud/tests/test_api.py +97 -0
- cumulusci/tasks/marketing_cloud/tests/test_api_soap_envelopes.py +145 -0
- cumulusci/tasks/marketing_cloud/tests/test_base.py +14 -0
- cumulusci/tasks/marketing_cloud/tests/test_deploy.py +400 -0
- cumulusci/tasks/marketing_cloud/tests/test_get_user_info.py +141 -0
- cumulusci/tasks/marketing_cloud/tests/validation-response.json +39 -0
- cumulusci/tasks/metadata/__init__.py +0 -0
- cumulusci/tasks/metadata/ee_src.py +94 -0
- cumulusci/tasks/metadata/managed_src.py +100 -0
- cumulusci/tasks/metadata/metadata_map.yml +868 -0
- cumulusci/tasks/metadata/modify.py +99 -0
- cumulusci/tasks/metadata/package.py +684 -0
- cumulusci/tasks/metadata/tests/__init__.py +0 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/.hidden/.keep +0 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/destructiveChanges.xml +9 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package.xml +9 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package_install_uninstall.xml +11 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/reports/namespace__TestFolder/TestReport.report +3 -0
- cumulusci/tasks/metadata/tests/sample_package.xml +9 -0
- cumulusci/tasks/metadata/tests/test_ee_src.py +112 -0
- cumulusci/tasks/metadata/tests/test_managed_src.py +111 -0
- cumulusci/tasks/metadata/tests/test_modify.py +123 -0
- cumulusci/tasks/metadata/tests/test_package.py +476 -0
- cumulusci/tasks/metadata_etl/__init__.py +29 -0
- cumulusci/tasks/metadata_etl/base.py +436 -0
- cumulusci/tasks/metadata_etl/duplicate_rules.py +24 -0
- cumulusci/tasks/metadata_etl/field_sets.py +70 -0
- cumulusci/tasks/metadata_etl/help_text.py +92 -0
- cumulusci/tasks/metadata_etl/layouts.py +550 -0
- cumulusci/tasks/metadata_etl/objects.py +68 -0
- cumulusci/tasks/metadata_etl/permissions.py +167 -0
- cumulusci/tasks/metadata_etl/picklists.py +221 -0
- cumulusci/tasks/metadata_etl/remote_site_settings.py +99 -0
- cumulusci/tasks/metadata_etl/sharing.py +138 -0
- cumulusci/tasks/metadata_etl/tests/test_base.py +512 -0
- cumulusci/tasks/metadata_etl/tests/test_duplicate_rules.py +22 -0
- cumulusci/tasks/metadata_etl/tests/test_field_sets.py +156 -0
- cumulusci/tasks/metadata_etl/tests/test_help_text.py +387 -0
- cumulusci/tasks/metadata_etl/tests/test_ip_ranges.py +85 -0
- cumulusci/tasks/metadata_etl/tests/test_layouts.py +858 -0
- cumulusci/tasks/metadata_etl/tests/test_objects.py +236 -0
- cumulusci/tasks/metadata_etl/tests/test_permissions.py +223 -0
- cumulusci/tasks/metadata_etl/tests/test_picklists.py +547 -0
- cumulusci/tasks/metadata_etl/tests/test_remote_site_settings.py +46 -0
- cumulusci/tasks/metadata_etl/tests/test_sharing.py +333 -0
- cumulusci/tasks/metadata_etl/tests/test_value_sets.py +298 -0
- cumulusci/tasks/metadata_etl/value_sets.py +106 -0
- cumulusci/tasks/metadeploy.py +393 -0
- cumulusci/tasks/metaxml.py +88 -0
- cumulusci/tasks/preflight/__init__.py +0 -0
- cumulusci/tasks/preflight/dataset_load.py +49 -0
- cumulusci/tasks/preflight/licenses.py +86 -0
- cumulusci/tasks/preflight/packages.py +14 -0
- cumulusci/tasks/preflight/permsets.py +23 -0
- cumulusci/tasks/preflight/recordtypes.py +16 -0
- cumulusci/tasks/preflight/retrieve_tasks.py +30 -0
- cumulusci/tasks/preflight/settings.py +77 -0
- cumulusci/tasks/preflight/sobjects.py +202 -0
- cumulusci/tasks/preflight/tests/test_dataset_load.py +85 -0
- cumulusci/tasks/preflight/tests/test_licenses.py +174 -0
- cumulusci/tasks/preflight/tests/test_packages.py +14 -0
- cumulusci/tasks/preflight/tests/test_permset_preflights.py +51 -0
- cumulusci/tasks/preflight/tests/test_recordtypes.py +30 -0
- cumulusci/tasks/preflight/tests/test_retrieve_tasks.py +62 -0
- cumulusci/tasks/preflight/tests/test_settings.py +130 -0
- cumulusci/tasks/preflight/tests/test_sobjects.py +231 -0
- cumulusci/tasks/push/README.md +59 -0
- cumulusci/tasks/push/__init__.py +0 -0
- cumulusci/tasks/push/push_api.py +659 -0
- cumulusci/tasks/push/pushfails.py +136 -0
- cumulusci/tasks/push/tasks.py +476 -0
- cumulusci/tasks/push/tests/conftest.py +263 -0
- cumulusci/tasks/push/tests/test_push_api.py +951 -0
- cumulusci/tasks/push/tests/test_push_tasks.py +659 -0
- cumulusci/tasks/release_notes/README.md +63 -0
- cumulusci/tasks/release_notes/__init__.py +0 -0
- cumulusci/tasks/release_notes/exceptions.py +5 -0
- cumulusci/tasks/release_notes/generator.py +137 -0
- cumulusci/tasks/release_notes/parser.py +232 -0
- cumulusci/tasks/release_notes/provider.py +44 -0
- cumulusci/tasks/release_notes/task.py +300 -0
- cumulusci/tasks/release_notes/tests/__init__.py +0 -0
- cumulusci/tasks/release_notes/tests/change_notes/full/example1.md +17 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/1.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/2.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/3.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/single/1.txt +1 -0
- cumulusci/tasks/release_notes/tests/test_generator.py +582 -0
- cumulusci/tasks/release_notes/tests/test_parser.py +867 -0
- cumulusci/tasks/release_notes/tests/test_provider.py +512 -0
- cumulusci/tasks/release_notes/tests/test_task.py +461 -0
- cumulusci/tasks/release_notes/tests/utils.py +153 -0
- cumulusci/tasks/robotframework/__init__.py +3 -0
- cumulusci/tasks/robotframework/debugger/DebugListener.py +100 -0
- cumulusci/tasks/robotframework/debugger/__init__.py +10 -0
- cumulusci/tasks/robotframework/debugger/model.py +87 -0
- cumulusci/tasks/robotframework/debugger/ui.py +259 -0
- cumulusci/tasks/robotframework/libdoc.py +269 -0
- cumulusci/tasks/robotframework/robotframework.py +392 -0
- cumulusci/tasks/robotframework/stylesheet.css +130 -0
- cumulusci/tasks/robotframework/template.html +109 -0
- cumulusci/tasks/robotframework/tests/TestLibrary.py +18 -0
- cumulusci/tasks/robotframework/tests/TestPageObjects.py +31 -0
- cumulusci/tasks/robotframework/tests/TestResource.robot +8 -0
- cumulusci/tasks/robotframework/tests/failing_tests.robot +16 -0
- cumulusci/tasks/robotframework/tests/performance.robot +23 -0
- cumulusci/tasks/robotframework/tests/test_browser_proxies.py +137 -0
- cumulusci/tasks/robotframework/tests/test_debugger.py +360 -0
- cumulusci/tasks/robotframework/tests/test_robot_parallel.py +141 -0
- cumulusci/tasks/robotframework/tests/test_robotframework.py +860 -0
- cumulusci/tasks/salesforce/BaseRetrieveMetadata.py +58 -0
- cumulusci/tasks/salesforce/BaseSalesforceApiTask.py +45 -0
- cumulusci/tasks/salesforce/BaseSalesforceMetadataApiTask.py +18 -0
- cumulusci/tasks/salesforce/BaseSalesforceTask.py +4 -0
- cumulusci/tasks/salesforce/BaseUninstallMetadata.py +41 -0
- cumulusci/tasks/salesforce/CreateCommunity.py +124 -0
- cumulusci/tasks/salesforce/CreatePackage.py +29 -0
- cumulusci/tasks/salesforce/Deploy.py +240 -0
- cumulusci/tasks/salesforce/DeployBundles.py +88 -0
- cumulusci/tasks/salesforce/DescribeMetadataTypes.py +26 -0
- cumulusci/tasks/salesforce/EnsureRecordTypes.py +202 -0
- cumulusci/tasks/salesforce/GetInstalledPackages.py +8 -0
- cumulusci/tasks/salesforce/ListCommunities.py +40 -0
- cumulusci/tasks/salesforce/ListCommunityTemplates.py +19 -0
- cumulusci/tasks/salesforce/PublishCommunity.py +62 -0
- cumulusci/tasks/salesforce/RetrievePackaged.py +41 -0
- cumulusci/tasks/salesforce/RetrieveReportsAndDashboards.py +82 -0
- cumulusci/tasks/salesforce/RetrieveUnpackaged.py +36 -0
- cumulusci/tasks/salesforce/SOQLQuery.py +39 -0
- cumulusci/tasks/salesforce/UninstallLocal.py +15 -0
- cumulusci/tasks/salesforce/UninstallLocalBundles.py +28 -0
- cumulusci/tasks/salesforce/UninstallLocalNamespacedBundles.py +58 -0
- cumulusci/tasks/salesforce/UninstallPackage.py +32 -0
- cumulusci/tasks/salesforce/UninstallPackaged.py +56 -0
- cumulusci/tasks/salesforce/UpdateAdminProfile.py +8 -0
- cumulusci/tasks/salesforce/__init__.py +79 -0
- cumulusci/tasks/salesforce/activate_flow.py +74 -0
- cumulusci/tasks/salesforce/check_components.py +324 -0
- cumulusci/tasks/salesforce/composite.py +142 -0
- cumulusci/tasks/salesforce/create_permission_sets.py +35 -0
- cumulusci/tasks/salesforce/custom_settings.py +134 -0
- cumulusci/tasks/salesforce/custom_settings_wait.py +132 -0
- cumulusci/tasks/salesforce/enable_prediction.py +107 -0
- cumulusci/tasks/salesforce/insert_record.py +40 -0
- cumulusci/tasks/salesforce/install_package_version.py +242 -0
- cumulusci/tasks/salesforce/license_preflights.py +8 -0
- cumulusci/tasks/salesforce/network_member_group.py +178 -0
- cumulusci/tasks/salesforce/nonsourcetracking.py +228 -0
- cumulusci/tasks/salesforce/org_settings.py +193 -0
- cumulusci/tasks/salesforce/package_upload.py +328 -0
- cumulusci/tasks/salesforce/profiles.py +74 -0
- cumulusci/tasks/salesforce/promote_package_version.py +376 -0
- cumulusci/tasks/salesforce/retrieve_profile.py +195 -0
- cumulusci/tasks/salesforce/salesforce_files.py +244 -0
- cumulusci/tasks/salesforce/sourcetracking.py +507 -0
- cumulusci/tasks/salesforce/tests/__init__.py +3 -0
- cumulusci/tasks/salesforce/tests/test_CreateCommunity.py +278 -0
- cumulusci/tasks/salesforce/tests/test_CreatePackage.py +22 -0
- cumulusci/tasks/salesforce/tests/test_Deploy.py +470 -0
- cumulusci/tasks/salesforce/tests/test_DeployBundles.py +76 -0
- cumulusci/tasks/salesforce/tests/test_EnsureRecordTypes.py +345 -0
- cumulusci/tasks/salesforce/tests/test_ListCommunities.py +84 -0
- cumulusci/tasks/salesforce/tests/test_ListCommunityTemplates.py +49 -0
- cumulusci/tasks/salesforce/tests/test_PackageUpload.py +547 -0
- cumulusci/tasks/salesforce/tests/test_ProfileGrantAllAccess.py +699 -0
- cumulusci/tasks/salesforce/tests/test_PublishCommunity.py +181 -0
- cumulusci/tasks/salesforce/tests/test_RetrievePackaged.py +24 -0
- cumulusci/tasks/salesforce/tests/test_RetrieveReportsAndDashboards.py +56 -0
- cumulusci/tasks/salesforce/tests/test_RetrieveUnpackaged.py +21 -0
- cumulusci/tasks/salesforce/tests/test_SOQLQuery.py +30 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocal.py +15 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocalBundles.py +19 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocalNamespacedBundles.py +22 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackage.py +19 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackaged.py +66 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackagedIncremental.py +127 -0
- cumulusci/tasks/salesforce/tests/test_activate_flow.py +132 -0
- cumulusci/tasks/salesforce/tests/test_base_tasks.py +110 -0
- cumulusci/tasks/salesforce/tests/test_check_components.py +445 -0
- cumulusci/tasks/salesforce/tests/test_composite.py +250 -0
- cumulusci/tasks/salesforce/tests/test_create_permission_sets.py +41 -0
- cumulusci/tasks/salesforce/tests/test_custom_settings.py +227 -0
- cumulusci/tasks/salesforce/tests/test_custom_settings_wait.py +174 -0
- cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py +18 -0
- cumulusci/tasks/salesforce/tests/test_enable_prediction.py +240 -0
- cumulusci/tasks/salesforce/tests/test_insert_record.py +110 -0
- cumulusci/tasks/salesforce/tests/test_install_package_version.py +464 -0
- cumulusci/tasks/salesforce/tests/test_network_member_group.py +444 -0
- cumulusci/tasks/salesforce/tests/test_nonsourcetracking.py +235 -0
- cumulusci/tasks/salesforce/tests/test_org_settings.py +407 -0
- cumulusci/tasks/salesforce/tests/test_profiles.py +202 -0
- cumulusci/tasks/salesforce/tests/test_retrieve_profile.py +287 -0
- cumulusci/tasks/salesforce/tests/test_salesforce_files.py +228 -0
- cumulusci/tasks/salesforce/tests/test_sourcetracking.py +350 -0
- cumulusci/tasks/salesforce/tests/test_trigger_handlers.py +300 -0
- cumulusci/tasks/salesforce/tests/test_update_dependencies.py +509 -0
- cumulusci/tasks/salesforce/tests/util.py +79 -0
- cumulusci/tasks/salesforce/trigger_handlers.py +119 -0
- cumulusci/tasks/salesforce/uninstall_packaged_incremental.py +136 -0
- cumulusci/tasks/salesforce/update_dependencies.py +290 -0
- cumulusci/tasks/salesforce/update_profile.py +339 -0
- cumulusci/tasks/salesforce/users/permsets.py +227 -0
- cumulusci/tasks/salesforce/users/photos.py +162 -0
- cumulusci/tasks/salesforce/users/tests/photo.mock.txt +1 -0
- cumulusci/tasks/salesforce/users/tests/test_permsets.py +950 -0
- cumulusci/tasks/salesforce/users/tests/test_photos.py +373 -0
- cumulusci/tasks/sample_data/capture_sample_data.py +77 -0
- cumulusci/tasks/sample_data/load_sample_data.py +85 -0
- cumulusci/tasks/sample_data/test_capture_sample_data.py +117 -0
- cumulusci/tasks/sample_data/test_load_sample_data.py +121 -0
- cumulusci/tasks/sfdx.py +83 -0
- cumulusci/tasks/tests/__init__.py +1 -0
- cumulusci/tasks/tests/conftest.py +30 -0
- cumulusci/tasks/tests/test_command.py +129 -0
- cumulusci/tasks/tests/test_connectedapp.py +236 -0
- cumulusci/tasks/tests/test_create_package_version.py +847 -0
- cumulusci/tasks/tests/test_datadictionary.py +1575 -0
- cumulusci/tasks/tests/test_dx_convert_from.py +60 -0
- cumulusci/tasks/tests/test_metadeploy.py +624 -0
- cumulusci/tasks/tests/test_metaxml.py +99 -0
- cumulusci/tasks/tests/test_promote_package_version.py +488 -0
- cumulusci/tasks/tests/test_pushfails.py +96 -0
- cumulusci/tasks/tests/test_salesforce.py +72 -0
- cumulusci/tasks/tests/test_sfdx.py +105 -0
- cumulusci/tasks/tests/test_util.py +207 -0
- cumulusci/tasks/util.py +261 -0
- cumulusci/tasks/vcs/__init__.py +19 -0
- cumulusci/tasks/vcs/commit_status.py +58 -0
- cumulusci/tasks/vcs/create_commit_status.py +37 -0
- cumulusci/tasks/vcs/download_extract.py +199 -0
- cumulusci/tasks/vcs/merge.py +298 -0
- cumulusci/tasks/vcs/publish.py +207 -0
- cumulusci/tasks/vcs/pull_request.py +9 -0
- cumulusci/tasks/vcs/release.py +134 -0
- cumulusci/tasks/vcs/release_report.py +105 -0
- cumulusci/tasks/vcs/tag.py +31 -0
- cumulusci/tasks/vcs/tests/github/test_commit_status.py +196 -0
- cumulusci/tasks/vcs/tests/github/test_download_extract.py +896 -0
- cumulusci/tasks/vcs/tests/github/test_merge.py +1118 -0
- cumulusci/tasks/vcs/tests/github/test_publish.py +823 -0
- cumulusci/tasks/vcs/tests/github/test_pull_request.py +29 -0
- cumulusci/tasks/vcs/tests/github/test_release.py +390 -0
- cumulusci/tasks/vcs/tests/github/test_release_report.py +109 -0
- cumulusci/tasks/vcs/tests/github/test_tag.py +90 -0
- cumulusci/tasks/vlocity/exceptions.py +2 -0
- cumulusci/tasks/vlocity/tests/test_vlocity.py +283 -0
- cumulusci/tasks/vlocity/vlocity.py +342 -0
- cumulusci/tests/__init__.py +1 -0
- cumulusci/tests/cassettes/GET_sobjects_Account_PersonAccount_describe.yaml +18 -0
- cumulusci/tests/cassettes/TestIntegrationInfrastructure.test_integration_tests.yaml +19 -0
- cumulusci/tests/pytest_plugins/pytest_sf_orgconnect.py +307 -0
- cumulusci/tests/pytest_plugins/pytest_sf_vcr.py +275 -0
- cumulusci/tests/pytest_plugins/pytest_sf_vcr_serializer.py +160 -0
- cumulusci/tests/pytest_plugins/pytest_typeguard.py +5 -0
- cumulusci/tests/pytest_plugins/test_vcr_string_compressor.py +49 -0
- cumulusci/tests/pytest_plugins/vcr_string_compressor.py +97 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Account_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Case_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Contact_describe.yaml +4838 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Custom__c_describe.yaml +242 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Event_describe.yaml +19 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Global_describe.yaml +1338 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Lead_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_OpportunityContactRole_describe.yaml +34 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Opportunity_describe.yaml +1261 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Organization.yaml +49 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfoList_xml.tpl +15 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfo_xml.tpl +13 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_insert_xml.tpl +24 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_upsert_xml.tpl +25 -0
- cumulusci/tests/test_entry_points.py +20 -0
- cumulusci/tests/test_integration_infrastructure.py +131 -0
- cumulusci/tests/test_main.py +9 -0
- cumulusci/tests/test_schema.py +32 -0
- cumulusci/tests/test_utils.py +657 -0
- cumulusci/tests/test_vcr_serializer.py +134 -0
- cumulusci/tests/uncompressed_cassette.yaml +83 -0
- cumulusci/tests/util.py +344 -0
- cumulusci/utils/__init__.py +731 -0
- cumulusci/utils/classutils.py +9 -0
- cumulusci/utils/collections.py +32 -0
- cumulusci/utils/deprecation.py +11 -0
- cumulusci/utils/encryption.py +31 -0
- cumulusci/utils/fileutils.py +295 -0
- cumulusci/utils/git.py +142 -0
- cumulusci/utils/http/multi_request.py +214 -0
- cumulusci/utils/http/requests_utils.py +103 -0
- cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +32 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_composite_parallel_salesforce.yaml +65 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_errors.yaml +24 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_reference_ids.yaml +49 -0
- cumulusci/utils/http/tests/test_multi_request.py +255 -0
- cumulusci/utils/iterators.py +21 -0
- cumulusci/utils/logging.py +128 -0
- cumulusci/utils/metaprogramming.py +10 -0
- cumulusci/utils/options.py +138 -0
- cumulusci/utils/parallel/queries_in_parallel/run_queries_in_parallel.py +29 -0
- cumulusci/utils/parallel/queries_in_parallel/tests/test_run_queries_in_parallel.py +50 -0
- cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +238 -0
- cumulusci/utils/parallel/task_worker_queues/parallel_worker_queue.py +243 -0
- cumulusci/utils/parallel/task_worker_queues/tests/test_parallel_worker.py +353 -0
- cumulusci/utils/salesforce/count_sobjects.py +46 -0
- cumulusci/utils/salesforce/soql.py +17 -0
- cumulusci/utils/salesforce/tests/cassettes/ManualEdit_TestCountSObjects.test_count_sobjects__network_errors.yaml +23 -0
- cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects__errors.yaml +33 -0
- cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects_simple.yaml +29 -0
- cumulusci/utils/salesforce/tests/test_count_sobjects.py +29 -0
- cumulusci/utils/salesforce/tests/test_soql.py +30 -0
- cumulusci/utils/tests/cassettes/ManualEditTestDescribeOrg.test_minimal_schema.yaml +36 -0
- cumulusci/utils/tests/cassettes/ManualEdit_test_describe_to_sql.yaml +191 -0
- cumulusci/utils/tests/test_fileutils.py +284 -0
- cumulusci/utils/tests/test_git.py +85 -0
- cumulusci/utils/tests/test_logging.py +70 -0
- cumulusci/utils/tests/test_option_parsing.py +188 -0
- cumulusci/utils/tests/test_org_schema.py +691 -0
- cumulusci/utils/tests/test_org_schema_models.py +79 -0
- cumulusci/utils/tests/test_waiting.py +25 -0
- cumulusci/utils/version_strings.py +391 -0
- cumulusci/utils/waiting.py +42 -0
- cumulusci/utils/xml/__init__.py +91 -0
- cumulusci/utils/xml/metadata_tree.py +299 -0
- cumulusci/utils/xml/robot_xml.py +114 -0
- cumulusci/utils/xml/salesforce_encoding.py +100 -0
- cumulusci/utils/xml/test/test_metadata_tree.py +251 -0
- cumulusci/utils/xml/test/test_salesforce_encoding.py +173 -0
- cumulusci/utils/yaml/cumulusci_yml.py +401 -0
- cumulusci/utils/yaml/model_parser.py +156 -0
- cumulusci/utils/yaml/safer_loader.py +74 -0
- cumulusci/utils/yaml/tests/bad_cci.yml +5 -0
- cumulusci/utils/yaml/tests/cassettes/TestCumulusciYml.test_validate_url__with_errors.yaml +20 -0
- cumulusci/utils/yaml/tests/test_cumulusci_yml.py +286 -0
- cumulusci/utils/yaml/tests/test_model_parser.py +175 -0
- cumulusci/utils/yaml/tests/test_safer_loader.py +88 -0
- cumulusci/utils/ziputils.py +61 -0
- cumulusci/vcs/base.py +143 -0
- cumulusci/vcs/bootstrap.py +272 -0
- cumulusci/vcs/github/__init__.py +24 -0
- cumulusci/vcs/github/adapter.py +689 -0
- cumulusci/vcs/github/release_notes/generator.py +219 -0
- cumulusci/vcs/github/release_notes/parser.py +151 -0
- cumulusci/vcs/github/release_notes/provider.py +143 -0
- cumulusci/vcs/github/service.py +569 -0
- cumulusci/vcs/github/tests/test_adapter.py +138 -0
- cumulusci/vcs/github/tests/test_service.py +408 -0
- cumulusci/vcs/models.py +586 -0
- cumulusci/vcs/tests/conftest.py +41 -0
- cumulusci/vcs/tests/dummy_service.py +241 -0
- cumulusci/vcs/tests/test_vcs_base.py +687 -0
- cumulusci/vcs/tests/test_vcs_bootstrap.py +727 -0
- cumulusci/vcs/utils/__init__.py +31 -0
- cumulusci/vcs/vcs_source.py +287 -0
- cumulusci_plus-5.0.0.dist-info/METADATA +145 -0
- cumulusci_plus-5.0.0.dist-info/RECORD +744 -0
- cumulusci_plus-5.0.0.dist-info/WHEEL +4 -0
- cumulusci_plus-5.0.0.dist-info/entry_points.txt +3 -0
- cumulusci_plus-5.0.0.dist-info/licenses/AUTHORS.rst +41 -0
- cumulusci_plus-5.0.0.dist-info/licenses/LICENSE +30 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import os
|
|
3
|
+
import os.path
|
|
4
|
+
import re
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import jinja2
|
|
9
|
+
import robot.utils
|
|
10
|
+
from robot.libdocpkg.builder import DocumentationBuilder
|
|
11
|
+
from robot.libdocpkg.robotbuilder import LibraryDocBuilder, ResourceDocBuilder
|
|
12
|
+
from robot.libraries.BuiltIn import RobotNotRunningError
|
|
13
|
+
from robot.utils import Importer
|
|
14
|
+
|
|
15
|
+
import cumulusci
|
|
16
|
+
from cumulusci.core.exceptions import TaskOptionsError
|
|
17
|
+
from cumulusci.core.tasks import BaseTask
|
|
18
|
+
from cumulusci.core.utils import process_bool_arg, process_glob_list_arg
|
|
19
|
+
from cumulusci.robotframework import PageObjects
|
|
20
|
+
from cumulusci.utils.fileutils import view_file
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RobotLibDoc(BaseTask):
|
|
24
|
+
task_options = {
|
|
25
|
+
"path": {
|
|
26
|
+
"description": (
|
|
27
|
+
"The path to one or more keyword libraries to be documented. "
|
|
28
|
+
"The path can be single a python file, a .robot file, a python "
|
|
29
|
+
"module (eg: cumulusci.robotframework.Salesforce) or a comma "
|
|
30
|
+
"separated list of any of those. Glob patterns are supported "
|
|
31
|
+
"for filenames (eg: ``robot/SAL/doc/*PageObject.py``). The order "
|
|
32
|
+
"of the files will be preserved in the generated documentation. "
|
|
33
|
+
"The result of pattern expansion will be sorted"
|
|
34
|
+
),
|
|
35
|
+
"required": True,
|
|
36
|
+
},
|
|
37
|
+
"output": {
|
|
38
|
+
"description": (
|
|
39
|
+
"The output file where the documentation will be written. "
|
|
40
|
+
"Normally an HTML file will be generated. If the filename "
|
|
41
|
+
"ends with '.csv' then a csv file will be generated instead."
|
|
42
|
+
),
|
|
43
|
+
"required": True,
|
|
44
|
+
},
|
|
45
|
+
"title": {
|
|
46
|
+
"description": "A string to use as the title of the generated output",
|
|
47
|
+
"required": False,
|
|
48
|
+
},
|
|
49
|
+
"preview": {
|
|
50
|
+
"description": (
|
|
51
|
+
"If True, automatically open a window to view the "
|
|
52
|
+
"generated data when the task is successful"
|
|
53
|
+
),
|
|
54
|
+
"required": False,
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def _validate_options(self):
|
|
59
|
+
super(RobotLibDoc, self)._validate_options()
|
|
60
|
+
self.options["path"] = process_glob_list_arg(self.options["path"])
|
|
61
|
+
|
|
62
|
+
# Attempt to collect all files that don't match existing
|
|
63
|
+
# files. Note: "path" could be a library module path (for example,
|
|
64
|
+
# cumulusci.robotframework.CumulusCI) so we only do this check for
|
|
65
|
+
# files that end in known library suffixes (.py, .robot, .resource).
|
|
66
|
+
bad_files = []
|
|
67
|
+
for path in self.options["path"]:
|
|
68
|
+
name, extension = os.path.splitext(path)
|
|
69
|
+
if extension in (".py", ".robot", ".resource") and not os.path.exists(path):
|
|
70
|
+
bad_files.append(path)
|
|
71
|
+
|
|
72
|
+
if bad_files:
|
|
73
|
+
if len(bad_files) == 1:
|
|
74
|
+
error_message = "Unable to find the input file '{}'".format(
|
|
75
|
+
bad_files[0]
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
78
|
+
files = ", ".join(["'{}'".format(filename) for filename in bad_files])
|
|
79
|
+
error_message = "Unable to find the following input files: {}".format(
|
|
80
|
+
files
|
|
81
|
+
)
|
|
82
|
+
raise TaskOptionsError(error_message)
|
|
83
|
+
|
|
84
|
+
self.options["preview"] = process_bool_arg(self.options.get("preview", False))
|
|
85
|
+
|
|
86
|
+
def is_pageobject_library(self, path):
|
|
87
|
+
"""Return True if the file looks like a page object library"""
|
|
88
|
+
if path.endswith(".py"):
|
|
89
|
+
with open(path, "r") as f:
|
|
90
|
+
data = f.read()
|
|
91
|
+
if re.search(r"@pageobject\(", data):
|
|
92
|
+
return True
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
def _run_task(self):
|
|
96
|
+
kwfiles = []
|
|
97
|
+
processed_files = []
|
|
98
|
+
for library_name in self.options["path"]:
|
|
99
|
+
kwfile = KeywordFile(library_name)
|
|
100
|
+
try:
|
|
101
|
+
if self.is_pageobject_library(library_name):
|
|
102
|
+
PageObjects._reset()
|
|
103
|
+
module = Importer().import_class_or_module_by_path(
|
|
104
|
+
os.path.abspath(library_name)
|
|
105
|
+
)
|
|
106
|
+
kwfile.doc = module.__doc__
|
|
107
|
+
if hasattr(module, "TITLE"):
|
|
108
|
+
kwfile.title = module.TITLE
|
|
109
|
+
|
|
110
|
+
for pobj_name, pobj in sorted(PageObjects.registry.items()):
|
|
111
|
+
pobj = PageObjects.registry[pobj_name]
|
|
112
|
+
libname = "{}.{}".format(pobj.__module__, pobj.__name__)
|
|
113
|
+
libdoc = LibraryDocBuilder().build(libname)
|
|
114
|
+
libdoc.src = os.path.basename(library_name)
|
|
115
|
+
libdoc.pobj = libname
|
|
116
|
+
kwfile.add_keywords(libdoc, pobj_name)
|
|
117
|
+
|
|
118
|
+
else:
|
|
119
|
+
# this test necessary due to a backwards-incompatible change
|
|
120
|
+
# in robot 6.x where .robot files get unconditionally passed
|
|
121
|
+
# to SuiteBuilder which then generates an error on keyword
|
|
122
|
+
# files since they don't have test cases.
|
|
123
|
+
if library_name.endswith(".robot"):
|
|
124
|
+
libdoc = ResourceDocBuilder().build(library_name)
|
|
125
|
+
else:
|
|
126
|
+
libdoc = DocumentationBuilder().build(library_name)
|
|
127
|
+
kwfile.add_keywords(libdoc)
|
|
128
|
+
|
|
129
|
+
# if we get here, we were able to process the file correctly
|
|
130
|
+
kwfiles.append(kwfile)
|
|
131
|
+
processed_files.append(library_name)
|
|
132
|
+
|
|
133
|
+
except RobotNotRunningError as e:
|
|
134
|
+
# oddly, robot's exception has a traceback embedded in the message, so we'll
|
|
135
|
+
# only print out the first line to hide most of the noise
|
|
136
|
+
self.logger.warning(
|
|
137
|
+
"unexpected error: {}".format(str(e).split("\n")[0])
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
if self.options["output"].endswith(".csv"):
|
|
142
|
+
data = self._convert_to_tuples(kwfiles)
|
|
143
|
+
with open(self.options["output"], "w", newline="") as f:
|
|
144
|
+
csv_writer = csv.writer(f, quoting=csv.QUOTE_ALL)
|
|
145
|
+
csv_writer.writerows(data)
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
html = self._convert_to_html(kwfiles)
|
|
149
|
+
with open(self.options["output"], "w") as f:
|
|
150
|
+
f.write(html)
|
|
151
|
+
self.logger.info("created {}".format(self.options["output"]))
|
|
152
|
+
|
|
153
|
+
if self.options["preview"]:
|
|
154
|
+
view_file(self.options["output"])
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
raise TaskOptionsError(
|
|
158
|
+
"Unable to create output file '{}' ({})".format(
|
|
159
|
+
self.options["output"], str(e)
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return {"files": processed_files}
|
|
164
|
+
|
|
165
|
+
def _convert_to_tuples(self, kwfiles):
|
|
166
|
+
"""Convert the list of keyword files into a list of tuples
|
|
167
|
+
|
|
168
|
+
The first element in the list will be a list of column headings.
|
|
169
|
+
"""
|
|
170
|
+
rows = []
|
|
171
|
+
for kwfile in kwfiles:
|
|
172
|
+
rows.extend(kwfile.to_tuples())
|
|
173
|
+
rows = sorted(set(rows))
|
|
174
|
+
rows.insert(0, KeywordFile.get_header())
|
|
175
|
+
return rows
|
|
176
|
+
|
|
177
|
+
def _convert_to_html(self, kwfiles):
|
|
178
|
+
"""Convert the list of keyword files into html"""
|
|
179
|
+
|
|
180
|
+
title = self.options.get("title", "Keyword Documentation")
|
|
181
|
+
date = time.strftime("%A %B %d, %I:%M %p")
|
|
182
|
+
cci_version = cumulusci.__version__
|
|
183
|
+
|
|
184
|
+
stylesheet_path = os.path.join(os.path.dirname(__file__), "stylesheet.css")
|
|
185
|
+
with open(stylesheet_path) as f:
|
|
186
|
+
stylesheet = f.read()
|
|
187
|
+
|
|
188
|
+
jinjaenv = jinja2.Environment(
|
|
189
|
+
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), autoescape=False
|
|
190
|
+
)
|
|
191
|
+
jinjaenv.filters["robot_html"] = robot.utils.html_format
|
|
192
|
+
template = jinjaenv.get_template("template.html")
|
|
193
|
+
return template.render(
|
|
194
|
+
libraries=kwfiles,
|
|
195
|
+
title=title,
|
|
196
|
+
cci_version=cci_version,
|
|
197
|
+
stylesheet=stylesheet,
|
|
198
|
+
date=date,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class KeywordFile:
|
|
203
|
+
"""Helper class which represents a file and its keywords
|
|
204
|
+
|
|
205
|
+
A file may have just a bunch of keywords, or groups of
|
|
206
|
+
keywords organized as page objects. Each group of keywords
|
|
207
|
+
is stored in self.keywords, with the page object metadata
|
|
208
|
+
as a key.
|
|
209
|
+
|
|
210
|
+
For normal libraries, the key is an empty tuple.
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
def __init__(self, path):
|
|
214
|
+
if os.path.exists(path):
|
|
215
|
+
self.filename = os.path.basename(path)
|
|
216
|
+
else:
|
|
217
|
+
# if it's not a file, it must be a module
|
|
218
|
+
self.filename = path.split(".")[-1]
|
|
219
|
+
self.title = self.filename
|
|
220
|
+
self.path = path
|
|
221
|
+
self.keywords = {}
|
|
222
|
+
|
|
223
|
+
@classmethod
|
|
224
|
+
def get_header(cls):
|
|
225
|
+
return ["Name", "Source", "Line#", "po type", "po_object", "Documentation"]
|
|
226
|
+
|
|
227
|
+
def add_keywords(self, libdoc, page_object=tuple()):
|
|
228
|
+
self.keywords[page_object] = libdoc
|
|
229
|
+
|
|
230
|
+
def to_tuples(self):
|
|
231
|
+
"""Convert the dictionary of keyword data to a set of tuples"""
|
|
232
|
+
rows = []
|
|
233
|
+
cwd = Path.cwd()
|
|
234
|
+
base_pageobjects_path = os.path.join(
|
|
235
|
+
"cumulusci", "robotframework", "pageobjects"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
for po, libdoc in self.keywords.items():
|
|
239
|
+
(po_type, po_object) = po if po else ("", "")
|
|
240
|
+
for keyword in libdoc.keywords:
|
|
241
|
+
# we don't want to see the same base pageobject
|
|
242
|
+
# keywords a kajillion times. This should probably
|
|
243
|
+
# be configurable, but I don't need it to be right now.
|
|
244
|
+
if base_pageobjects_path in str(keyword.source):
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
path = Path(keyword.source)
|
|
248
|
+
if path.is_absolute():
|
|
249
|
+
try:
|
|
250
|
+
path = path.relative_to(cwd)
|
|
251
|
+
except ValueError:
|
|
252
|
+
# ok, fine. We'll use the path as-is.
|
|
253
|
+
pass
|
|
254
|
+
path = str(path)
|
|
255
|
+
|
|
256
|
+
# make sure that if you change the list of columns here
|
|
257
|
+
# that you modify the `get_header` property too!
|
|
258
|
+
row = (
|
|
259
|
+
keyword.name,
|
|
260
|
+
path,
|
|
261
|
+
keyword.lineno,
|
|
262
|
+
po_type,
|
|
263
|
+
po_object,
|
|
264
|
+
keyword.doc,
|
|
265
|
+
)
|
|
266
|
+
rows.append(row)
|
|
267
|
+
|
|
268
|
+
rows = set(rows)
|
|
269
|
+
return rows
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import fnmatch
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import shlex
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from robot import run as robot_run
|
|
10
|
+
from robot.testdoc import testdoc
|
|
11
|
+
|
|
12
|
+
import cumulusci.robotframework
|
|
13
|
+
from cumulusci.core.exceptions import (
|
|
14
|
+
NamespaceNotFoundError,
|
|
15
|
+
RobotTestFailure,
|
|
16
|
+
TaskOptionsError,
|
|
17
|
+
)
|
|
18
|
+
from cumulusci.core.tasks import BaseTask
|
|
19
|
+
from cumulusci.core.utils import (
|
|
20
|
+
process_bool_arg,
|
|
21
|
+
process_list_arg,
|
|
22
|
+
process_list_of_pairs_dict_arg,
|
|
23
|
+
)
|
|
24
|
+
from cumulusci.robotframework.utils import set_pdb_trace
|
|
25
|
+
from cumulusci.tasks.robotframework.debugger import DebugListener
|
|
26
|
+
from cumulusci.tasks.salesforce import BaseSalesforceTask
|
|
27
|
+
from cumulusci.utils.xml.robot_xml import log_perf_summary_from_xml
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Robot(BaseSalesforceTask):
|
|
31
|
+
task_docs = """
|
|
32
|
+
Runs Robot test cases using a browser, if
|
|
33
|
+
necessary and stores its results in a directory. The
|
|
34
|
+
path to the directory can be retrieved from the
|
|
35
|
+
``robot_outputdir`` return variable."""
|
|
36
|
+
|
|
37
|
+
task_options = {
|
|
38
|
+
"suites": {
|
|
39
|
+
"description": 'Paths to test case files/directories to be executed similarly as when running the robot command on the command line. Defaults to "tests" to run all tests in the tests directory',
|
|
40
|
+
"required": True,
|
|
41
|
+
},
|
|
42
|
+
"test": {
|
|
43
|
+
"description": "Run only tests matching name patterns. Can be comma separated and use robot wildcards like *"
|
|
44
|
+
},
|
|
45
|
+
"include": {"description": "Includes tests with a given tag pattern"},
|
|
46
|
+
"exclude": {
|
|
47
|
+
"description": "Excludes tests with a given tag pattern. "
|
|
48
|
+
"Excluded tests will not appear in the logs and reports."
|
|
49
|
+
},
|
|
50
|
+
"skip": {
|
|
51
|
+
"description": "Do not run tests with the given tag pattern. Similar to 'exclude', "
|
|
52
|
+
"but skipped tests will appear in the logs and reports with the status of SKIP."
|
|
53
|
+
},
|
|
54
|
+
"vars": {
|
|
55
|
+
"description": "Pass values to override variables in the format VAR1:foo,VAR2:bar"
|
|
56
|
+
},
|
|
57
|
+
"xunit": {"description": "Set an XUnit format output file for test results"},
|
|
58
|
+
"sources": {
|
|
59
|
+
"description": "List of sources defined in cumulusci.yml that are required by the robot task.",
|
|
60
|
+
"required": False,
|
|
61
|
+
},
|
|
62
|
+
"options": {
|
|
63
|
+
"description": "A dictionary of options to robot.run method. "
|
|
64
|
+
"In simple cases this can be specified on the comand line using "
|
|
65
|
+
"name:value,name:value syntax. More complex cases can be specified "
|
|
66
|
+
"in cumulusci.yml using YAML dictionary syntax."
|
|
67
|
+
},
|
|
68
|
+
"name": {"description": "Sets the name of the top level test suite"},
|
|
69
|
+
"pdb": {"description": "If true, run the Python debugger when tests fail."},
|
|
70
|
+
"verbose": {"description": "If true, log each keyword as it runs."},
|
|
71
|
+
"robot_debug": {
|
|
72
|
+
"description": "If true, enable the `breakpoint` keyword to enable the robot debugger"
|
|
73
|
+
},
|
|
74
|
+
"ordering": {
|
|
75
|
+
"description": (
|
|
76
|
+
"Path to a file which defines the order in which parallel tests are run. "
|
|
77
|
+
"This maps directly to the pabot option of the same name. It is ignored "
|
|
78
|
+
"unless the processes argument is set to 2 or greater."
|
|
79
|
+
),
|
|
80
|
+
},
|
|
81
|
+
"processes": {
|
|
82
|
+
"description": (
|
|
83
|
+
"*experimental* Number of processes to use for running tests in parallel. "
|
|
84
|
+
"If this value is set to a number larger than 1 the tests will run using the "
|
|
85
|
+
"open source tool pabot rather than robotframework. For example, -o parallel "
|
|
86
|
+
"2 will run half of the tests in one process and half in another. If not "
|
|
87
|
+
"provided, all tests will run in a single process using the standard robot "
|
|
88
|
+
"test runner. See https://pabot.org/ for more information on pabot."
|
|
89
|
+
),
|
|
90
|
+
"default": "1",
|
|
91
|
+
},
|
|
92
|
+
"testlevelsplit": {
|
|
93
|
+
"description": (
|
|
94
|
+
"If true, split parallel execution at the test level rather "
|
|
95
|
+
"than the suite level. This option is ignored unless the "
|
|
96
|
+
"processes option is set to 2 or greater. Note: this option "
|
|
97
|
+
"requires a boolean value even though the pabot option of the "
|
|
98
|
+
"same name does not. "
|
|
99
|
+
),
|
|
100
|
+
"default": "false",
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
def _init_options(self, kwargs):
|
|
105
|
+
super(Robot, self)._init_options(kwargs)
|
|
106
|
+
|
|
107
|
+
for option in (
|
|
108
|
+
"test",
|
|
109
|
+
"include",
|
|
110
|
+
"exclude",
|
|
111
|
+
"vars",
|
|
112
|
+
"sources",
|
|
113
|
+
"suites",
|
|
114
|
+
"skip",
|
|
115
|
+
):
|
|
116
|
+
if option in self.options:
|
|
117
|
+
self.options[option] = process_list_arg(self.options[option])
|
|
118
|
+
if "vars" not in self.options:
|
|
119
|
+
self.options["vars"] = []
|
|
120
|
+
|
|
121
|
+
# Initialize options as a dict
|
|
122
|
+
if "options" in self.options:
|
|
123
|
+
self.options["options"] = process_list_of_pairs_dict_arg(
|
|
124
|
+
self.options["options"]
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
self.options["options"] = {}
|
|
128
|
+
|
|
129
|
+
# processes needs to be an integer.
|
|
130
|
+
try:
|
|
131
|
+
self.options["processes"] = int(self.options.get("processes", 1))
|
|
132
|
+
except (TypeError, ValueError):
|
|
133
|
+
raise TaskOptionsError(
|
|
134
|
+
"Please specify an integer for the `processes` option."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if self.options["processes"] > 1:
|
|
138
|
+
self.options["testlevelsplit"] = process_bool_arg(
|
|
139
|
+
self.options.get("testlevelsplit", False)
|
|
140
|
+
)
|
|
141
|
+
else:
|
|
142
|
+
# ignore these. Why not throw an error? This lets the user
|
|
143
|
+
# turn off parallel processing on the command line without
|
|
144
|
+
# having to also remove these options.
|
|
145
|
+
self.options.pop("testlevelsplit", None)
|
|
146
|
+
self.options.pop("ordering", None)
|
|
147
|
+
|
|
148
|
+
# There are potentially many robot options that are or could
|
|
149
|
+
# be lists. The only ones we currently care about are the
|
|
150
|
+
# listener and tagstatexlude options since we may need to
|
|
151
|
+
# append additional values onto it.
|
|
152
|
+
for option in ("listener", "tagstatexclude"):
|
|
153
|
+
if option in self.options["options"]:
|
|
154
|
+
self.options["options"][option] = process_list_arg(
|
|
155
|
+
self.options["options"][option]
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
listeners = self.options["options"].setdefault("listener", [])
|
|
159
|
+
|
|
160
|
+
if process_bool_arg(self.options.get("verbose") or False):
|
|
161
|
+
listeners.append(KeywordLogger())
|
|
162
|
+
|
|
163
|
+
if process_bool_arg(self.options.get("robot_debug") or False):
|
|
164
|
+
listeners.append(DebugListener())
|
|
165
|
+
|
|
166
|
+
if process_bool_arg(self.options.get("pdb") or False):
|
|
167
|
+
patch_statusreporter()
|
|
168
|
+
|
|
169
|
+
self.options.setdefault("sources", [])
|
|
170
|
+
|
|
171
|
+
def _run_task(self):
|
|
172
|
+
self.options["vars"].append("org:{}".format(self.org_config.name))
|
|
173
|
+
options = self.options["options"].copy()
|
|
174
|
+
for option in ("test", "include", "exclude", "xunit", "name", "skip"):
|
|
175
|
+
if option in self.options:
|
|
176
|
+
options[option] = self.options[option]
|
|
177
|
+
options["variable"] = self.options.get("vars") or []
|
|
178
|
+
output_dir = Path(self.working_path) / options.get("outputdir", ".")
|
|
179
|
+
options["outputdir"] = str(output_dir.resolve())
|
|
180
|
+
|
|
181
|
+
options["tagstatexclude"] = options.get(
|
|
182
|
+
"tagstatexclude", []
|
|
183
|
+
) + self.options.get("tagstatexclude", [])
|
|
184
|
+
options["tagstatexclude"].append("cci_metric_elapsed_time")
|
|
185
|
+
options["tagstatexclude"].append("cci_metric")
|
|
186
|
+
# Set as a return value so other things that want to use
|
|
187
|
+
# this file (e.g. MetaCI) know where it is
|
|
188
|
+
self.return_values["robot_outputdir"] = options["outputdir"]
|
|
189
|
+
|
|
190
|
+
# get_namespace will potentially download sources that have
|
|
191
|
+
# yet to be downloaded. For these downloaded sources we'll add
|
|
192
|
+
# the cached directories to PYTHONPATH before running.
|
|
193
|
+
source_paths = {}
|
|
194
|
+
for source in self.options["sources"]:
|
|
195
|
+
try:
|
|
196
|
+
source_config = self.project_config.get_namespace(source)
|
|
197
|
+
source_paths[source] = source_config.repo_root
|
|
198
|
+
except NamespaceNotFoundError:
|
|
199
|
+
raise TaskOptionsError(f"robot source '{source}' could not be found")
|
|
200
|
+
|
|
201
|
+
# replace namespace prefixes with path to cached folder
|
|
202
|
+
for i, path in enumerate(self.options["suites"]):
|
|
203
|
+
prefix, _, path = path.rpartition(":")
|
|
204
|
+
if prefix in source_paths:
|
|
205
|
+
self.options["suites"][i] = os.path.join(source_paths[prefix], path)
|
|
206
|
+
|
|
207
|
+
# this is necessary so that javascript-based keywords have access
|
|
208
|
+
# to at least some of the org info
|
|
209
|
+
cci_context = json.dumps(
|
|
210
|
+
{
|
|
211
|
+
"project_config": {
|
|
212
|
+
"repo_name": self.project_config.repo_name,
|
|
213
|
+
"repo_root": self.project_config.repo_root,
|
|
214
|
+
},
|
|
215
|
+
"org": {
|
|
216
|
+
"name": self.org_config.name,
|
|
217
|
+
"instance_url": self.org_config.instance_url,
|
|
218
|
+
"org_id": self.org_config.org_id,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
os.environ["CCI_CONTEXT"] = cci_context
|
|
223
|
+
os.environ["NODE_PATH"] = str(
|
|
224
|
+
Path(cumulusci.robotframework.__path__[0]) / "javascript"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if self.options["processes"] > 1:
|
|
228
|
+
# Since pabot runs multiple robot processes, and because
|
|
229
|
+
# those processes aren't cci tasks, we have to set up the
|
|
230
|
+
# environment to match what we do with a cci task. Specifically,
|
|
231
|
+
# we need to add the repo root to PYTHONPATH (via the --pythonpath
|
|
232
|
+
# option). Otherwise robot won't be able to find libraries and
|
|
233
|
+
# resource files referenced as relative to the repo root
|
|
234
|
+
cmd = [
|
|
235
|
+
sys.executable,
|
|
236
|
+
"-m",
|
|
237
|
+
"pabot.pabot",
|
|
238
|
+
"--pabotlib",
|
|
239
|
+
"--processes",
|
|
240
|
+
str(self.options["processes"]),
|
|
241
|
+
]
|
|
242
|
+
# the pabot option `--testlevelsplit` takes no arguments,
|
|
243
|
+
# so we'll only add it if it's set to true and then remove
|
|
244
|
+
# it from options so it doesn't get added later.
|
|
245
|
+
if self.options.pop("testlevelsplit", False):
|
|
246
|
+
cmd.append("--testlevelsplit")
|
|
247
|
+
|
|
248
|
+
# the ordering option is pabot-specific and must come before
|
|
249
|
+
# all robot options:
|
|
250
|
+
if self.options.get("ordering", None):
|
|
251
|
+
cmd.extend(["--ordering", self.options.pop("ordering")])
|
|
252
|
+
|
|
253
|
+
# this has to come after the pabot-specific options.
|
|
254
|
+
cmd.extend(["--pythonpath", str(self.project_config.repo_root)])
|
|
255
|
+
|
|
256
|
+
# We need to convert options to their commandline equivalent
|
|
257
|
+
for option, value in options.items():
|
|
258
|
+
if isinstance(value, list):
|
|
259
|
+
for item in value:
|
|
260
|
+
cmd.extend([f"--{option}", str(item)])
|
|
261
|
+
else:
|
|
262
|
+
cmd.extend([f"--{option}", str(value)])
|
|
263
|
+
|
|
264
|
+
# Add each source to pythonpath. Use --pythonpath since
|
|
265
|
+
# pybot will need to use that option for each process that
|
|
266
|
+
# it spawns.
|
|
267
|
+
for path in source_paths.values():
|
|
268
|
+
cmd.extend(["--pythonpath", path])
|
|
269
|
+
|
|
270
|
+
cmd.extend(self.options["suites"])
|
|
271
|
+
self.logger.info(
|
|
272
|
+
f"pabot command: {' '.join([shlex.quote(x) for x in cmd])}"
|
|
273
|
+
)
|
|
274
|
+
result = subprocess.run(cmd)
|
|
275
|
+
num_failed = result.returncode
|
|
276
|
+
|
|
277
|
+
else:
|
|
278
|
+
# Save it so that we can restore it later
|
|
279
|
+
orig_sys_path = sys.path.copy()
|
|
280
|
+
|
|
281
|
+
for path in source_paths.values():
|
|
282
|
+
add_path(path, end=True)
|
|
283
|
+
|
|
284
|
+
# Make sure the path to the repo root is on sys.path. Normally
|
|
285
|
+
# it will be, but if we're running this task from another repo
|
|
286
|
+
# it might not be.
|
|
287
|
+
#
|
|
288
|
+
# Note: we can't just set the pythonpath option; that
|
|
289
|
+
# option is specifically called out as not being supported
|
|
290
|
+
# by robot.run. Plus, robot recommends we call a special
|
|
291
|
+
# function instead of directly modifying sys.path
|
|
292
|
+
if self.project_config.repo_root not in sys.path:
|
|
293
|
+
add_path(self.project_config.repo_root)
|
|
294
|
+
|
|
295
|
+
options["stdout"] = sys.stdout
|
|
296
|
+
options["stderr"] = sys.stderr
|
|
297
|
+
try:
|
|
298
|
+
num_failed = robot_run(*self.options["suites"], **options)
|
|
299
|
+
finally:
|
|
300
|
+
sys.path = orig_sys_path
|
|
301
|
+
|
|
302
|
+
output_xml = Path(options["outputdir"]) / "output.xml"
|
|
303
|
+
if num_failed <= 250 and output_xml.exists():
|
|
304
|
+
log_perf_summary_from_xml(output_xml, self.logger.info)
|
|
305
|
+
|
|
306
|
+
# These numbers are from the robot framework user guide:
|
|
307
|
+
# http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes
|
|
308
|
+
if 0 < num_failed < 250:
|
|
309
|
+
raise RobotTestFailure(
|
|
310
|
+
f"{num_failed} test{'' if num_failed == 1 else 's'} failed."
|
|
311
|
+
)
|
|
312
|
+
elif num_failed == 250:
|
|
313
|
+
raise RobotTestFailure("250 or more tests failed.")
|
|
314
|
+
elif num_failed == 251:
|
|
315
|
+
raise RobotTestFailure("Help or version information printed.")
|
|
316
|
+
elif num_failed == 252:
|
|
317
|
+
raise RobotTestFailure("Invalid test data or command line options.")
|
|
318
|
+
elif num_failed == 253:
|
|
319
|
+
raise RobotTestFailure("Test execution stopped by user.")
|
|
320
|
+
elif num_failed >= 255:
|
|
321
|
+
raise RobotTestFailure("Unexpected internal error")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class RobotTestDoc(BaseTask):
|
|
325
|
+
task_options = {
|
|
326
|
+
"path": {
|
|
327
|
+
"description": "The path containing .robot test files",
|
|
328
|
+
"required": True,
|
|
329
|
+
},
|
|
330
|
+
"output": {
|
|
331
|
+
"description": "The output html file where the documentation will be written",
|
|
332
|
+
"required": True,
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
def _run_task(self):
|
|
337
|
+
return testdoc(self.options["path"], self.options["output"])
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class KeywordLogger(object):
|
|
341
|
+
ROBOT_LISTENER_API_VERSION = 2
|
|
342
|
+
|
|
343
|
+
def start_keyword(self, name, attrs):
|
|
344
|
+
sys.stdout.write(" {} {}\n".format(attrs["kwname"], " ".join(attrs["args"])))
|
|
345
|
+
sys.stdout.flush()
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def patch_statusreporter():
|
|
349
|
+
"""Monkey patch robotframework to do postmortem debugging"""
|
|
350
|
+
from robot.running.statusreporter import StatusReporter
|
|
351
|
+
|
|
352
|
+
orig_exit = StatusReporter.__exit__
|
|
353
|
+
|
|
354
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
355
|
+
if exc_val and isinstance(exc_val, Exception):
|
|
356
|
+
set_pdb_trace(pm=True)
|
|
357
|
+
return orig_exit(self, exc_type, exc_val, exc_tb)
|
|
358
|
+
|
|
359
|
+
StatusReporter.__exit__ = __exit__
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def patch_executescript():
|
|
363
|
+
# convert executeScript calls into executeAsyncScript
|
|
364
|
+
# to work around an issue in chromedriver 77
|
|
365
|
+
# https://bugs.chromium.org/p/chromedriver/issues/detail?id=3103
|
|
366
|
+
from selenium.webdriver.remote.webdriver import WebDriver
|
|
367
|
+
|
|
368
|
+
def execute_script(self, script, *args):
|
|
369
|
+
# the last argument is the function called to say the async operation is done
|
|
370
|
+
script = (
|
|
371
|
+
"arguments[arguments.length - 1](function(){"
|
|
372
|
+
+ script
|
|
373
|
+
+ "}.apply(null, Array.prototype.slice.call(arguments, 0, -1)));"
|
|
374
|
+
)
|
|
375
|
+
return self.execute_async_script(script, *args)
|
|
376
|
+
|
|
377
|
+
WebDriver.execute_script = execute_script
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def add_path(path, end=False):
|
|
381
|
+
"""
|
|
382
|
+
Adds a source to PYTHONPATH. Robot recommended that we
|
|
383
|
+
use pythonpathsetter.add_path instead of directly setting
|
|
384
|
+
sys.path, but removed this function in v6.1.
|
|
385
|
+
"""
|
|
386
|
+
if not end:
|
|
387
|
+
sys.path.insert(0, path)
|
|
388
|
+
elif not any(fnmatch.fnmatch(p, path) for p in sys.path):
|
|
389
|
+
sys.path.append(path)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
patch_executescript()
|