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,121 @@
|
|
|
1
|
+
import typing as T
|
|
2
|
+
from itertools import chain
|
|
3
|
+
|
|
4
|
+
from snowfakery.cci_mapping_files.declaration_parser import SObjectRuleDeclaration
|
|
5
|
+
|
|
6
|
+
from cumulusci.salesforce_api.org_schema import Schema
|
|
7
|
+
from cumulusci.tasks.bulkdata.mapping_parser import MappingStep
|
|
8
|
+
from cumulusci.utils.collections import OrderedSet
|
|
9
|
+
from cumulusci.utils.iterators import partition
|
|
10
|
+
|
|
11
|
+
from ..extract_dataset_utils.calculate_dependencies import SObjDependency
|
|
12
|
+
from ..extract_dataset_utils.synthesize_extract_declarations import (
|
|
13
|
+
ExtractDeclaration,
|
|
14
|
+
SimplifiedExtractDeclaration,
|
|
15
|
+
flatten_declarations,
|
|
16
|
+
)
|
|
17
|
+
from .load_mapping_file_generator import generate_load_mapping_file
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SimplifiedExtractDeclarationWithLookups(SimplifiedExtractDeclaration):
|
|
21
|
+
lookups: T.Dict[str, T.Union[str, T.Tuple[str, ...]]]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_load_mapping_file_from_extract_declarations(
|
|
25
|
+
decls: T.Sequence[ExtractDeclaration],
|
|
26
|
+
schema: Schema,
|
|
27
|
+
opt_in_only: T.Sequence[str] = (),
|
|
28
|
+
loading_rules: T.Sequence[SObjectRuleDeclaration] = (),
|
|
29
|
+
) -> T.Dict[str, dict]:
|
|
30
|
+
"""Create a mapping file from Extract declarations"""
|
|
31
|
+
simplified_decls = flatten_declarations(decls, schema, opt_in_only) # FIXME
|
|
32
|
+
simplified_decls_w_lookups = classify_and_filter_lookups(simplified_decls, schema)
|
|
33
|
+
intertable_dependencies = _discover_dependendencies(simplified_decls_w_lookups)
|
|
34
|
+
|
|
35
|
+
def _mapping_step(decl):
|
|
36
|
+
fields = tuple(chain(decl.fields, decl.lookups.keys()))
|
|
37
|
+
return MappingStep(
|
|
38
|
+
sf_object=decl.sf_object,
|
|
39
|
+
fields=dict(zip(fields, fields)),
|
|
40
|
+
# lookups=lookups, # lookups can be re-created later, for simplicity
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
mapping_steps = [_mapping_step(decl) for decl in simplified_decls_w_lookups]
|
|
44
|
+
|
|
45
|
+
mappings = generate_load_mapping_file(
|
|
46
|
+
mapping_steps, intertable_dependencies, loading_rules
|
|
47
|
+
)
|
|
48
|
+
return mappings
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _discover_dependendencies(simplified_decls: T.Sequence):
|
|
52
|
+
"""Look at all of the lookups in a set of declarations to determine
|
|
53
|
+
what depends on what"""
|
|
54
|
+
intertable_dependencies = OrderedSet()
|
|
55
|
+
|
|
56
|
+
for decl in simplified_decls:
|
|
57
|
+
for fieldname, tablenames in decl.lookups.items():
|
|
58
|
+
intertable_dependencies.add(
|
|
59
|
+
SObjDependency(decl.sf_object, tablenames, fieldname)
|
|
60
|
+
)
|
|
61
|
+
return intertable_dependencies
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def classify_and_filter_lookups(
|
|
65
|
+
decls: T.Sequence[SimplifiedExtractDeclaration], schema: Schema
|
|
66
|
+
) -> T.Sequence[SimplifiedExtractDeclarationWithLookups]:
|
|
67
|
+
"""Move lookups into their own field, if they reference a table we're including"""
|
|
68
|
+
referenceable_tables = [decl.sf_object for decl in decls if decl.sf_object]
|
|
69
|
+
# the if statement above is just to shut up the type checker
|
|
70
|
+
return [_add_lookups_to_decl(decl, schema, referenceable_tables) for decl in decls]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _add_lookups_to_decl(
|
|
74
|
+
decl: SimplifiedExtractDeclaration,
|
|
75
|
+
schema: Schema,
|
|
76
|
+
referenceable_tables: T.Sequence[str],
|
|
77
|
+
) -> SimplifiedExtractDeclarationWithLookups:
|
|
78
|
+
"""Look at every declaration and check whether any of the fields it refers to
|
|
79
|
+
are actually lookups. If so, synthesize the lookups declarations."""
|
|
80
|
+
sobject_schema_info = schema[decl.sf_object]
|
|
81
|
+
fields, lookups_and_targets = _fields_and_lookups_for_decl(
|
|
82
|
+
decl, sobject_schema_info, referenceable_tables
|
|
83
|
+
)
|
|
84
|
+
new_decl_data = {
|
|
85
|
+
**dict(decl),
|
|
86
|
+
"fields": list(fields),
|
|
87
|
+
"lookups": dict(lookups_and_targets),
|
|
88
|
+
}
|
|
89
|
+
del new_decl_data["fields_"]
|
|
90
|
+
new_decl = SimplifiedExtractDeclarationWithLookups(**new_decl_data)
|
|
91
|
+
return new_decl
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _fields_and_lookups_for_decl(decl, sobject_schema_info, referenceable_tables):
|
|
95
|
+
"""Split fields versus lookups for a declaration"""
|
|
96
|
+
|
|
97
|
+
def is_lookup(field_name):
|
|
98
|
+
# Record types are not treated as lookup.
|
|
99
|
+
if field_name == "RecordTypeId":
|
|
100
|
+
return False
|
|
101
|
+
schema_info_for_field = sobject_schema_info.fields[field_name]
|
|
102
|
+
target = schema_info_for_field.referenceTo
|
|
103
|
+
return target
|
|
104
|
+
|
|
105
|
+
simple_fields, lookups = partition(is_lookup, decl.fields)
|
|
106
|
+
|
|
107
|
+
def target_table(field_info):
|
|
108
|
+
target = field_info.referenceTo
|
|
109
|
+
return target
|
|
110
|
+
|
|
111
|
+
lookups = list(lookups)
|
|
112
|
+
|
|
113
|
+
lookups_and_targets = (
|
|
114
|
+
(lookup, target_table(sobject_schema_info.fields[lookup])) for lookup in lookups
|
|
115
|
+
)
|
|
116
|
+
lookups_and_targets = (
|
|
117
|
+
(lookup, [table for table in tables if table in referenceable_tables])
|
|
118
|
+
for lookup, tables in lookups_and_targets
|
|
119
|
+
if any(table in referenceable_tables for table in tables)
|
|
120
|
+
)
|
|
121
|
+
return simple_fields, lookups_and_targets
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import typing as T
|
|
2
|
+
|
|
3
|
+
from snowfakery.cci_mapping_files.declaration_parser import SObjectRuleDeclaration
|
|
4
|
+
|
|
5
|
+
from cumulusci.tasks.bulkdata.extract_dataset_utils.calculate_dependencies import (
|
|
6
|
+
SObjDependency,
|
|
7
|
+
)
|
|
8
|
+
from cumulusci.tasks.bulkdata.generate_mapping_utils.dependency_map import DependencyMap
|
|
9
|
+
from cumulusci.tasks.bulkdata.generate_mapping_utils.mapping_transforms import (
|
|
10
|
+
merge_matching_steps,
|
|
11
|
+
recategorize_lookups,
|
|
12
|
+
rename_record_type_fields,
|
|
13
|
+
sort_steps,
|
|
14
|
+
)
|
|
15
|
+
from cumulusci.tasks.bulkdata.mapping_parser import MappingStep
|
|
16
|
+
from cumulusci.utils.collections import OrderedSet, OrderedSetType
|
|
17
|
+
|
|
18
|
+
# from ..extract_dataset_utils.extract_yml import ExtractDeclaration
|
|
19
|
+
from .mapping_generator_post_processes import add_after_statements
|
|
20
|
+
|
|
21
|
+
# Note that the code in this file is also used by Snowfakery, so
|
|
22
|
+
# changes need to be coordinated.
|
|
23
|
+
#
|
|
24
|
+
# It is also intended to someday be used by CCI to generate
|
|
25
|
+
# Load Mapping Files from Load Declarations.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Code adapted from Snowfakery
|
|
29
|
+
def generate_load_mapping_file(
|
|
30
|
+
mapping_steps: T.Sequence[MappingStep],
|
|
31
|
+
intertable_dependencies: OrderedSetType[SObjDependency],
|
|
32
|
+
load_declarations: T.Sequence[SObjectRuleDeclaration] = (),
|
|
33
|
+
) -> T.Dict[str, dict]:
|
|
34
|
+
"""Generate a mapping file in optimal order with forward references etc.
|
|
35
|
+
|
|
36
|
+
Input is a set of a tables, dependencies between them and load declarations"""
|
|
37
|
+
|
|
38
|
+
load_declarations = list(load_declarations) or []
|
|
39
|
+
declared_dependencies = collect_user_specified_dependencies(load_declarations)
|
|
40
|
+
table_names = OrderedSet(mapping.sf_object for mapping in mapping_steps)
|
|
41
|
+
depmap = DependencyMap(
|
|
42
|
+
table_names, intertable_dependencies.union(declared_dependencies)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Merge similar steps (output step count will be equal or less)
|
|
46
|
+
mapping_steps = merge_matching_steps(mapping_steps, depmap)
|
|
47
|
+
|
|
48
|
+
# Sort steps according to dependencies
|
|
49
|
+
mapping_steps = sort_steps(mapping_steps, depmap)
|
|
50
|
+
|
|
51
|
+
# Normalize various forms of record type fields
|
|
52
|
+
mapping_steps = rename_record_type_fields(mapping_steps, depmap)
|
|
53
|
+
|
|
54
|
+
# Detect which fields are lookups and properly set them up
|
|
55
|
+
mapping_steps = recategorize_lookups(mapping_steps, depmap)
|
|
56
|
+
|
|
57
|
+
# Apply user-specified declarations
|
|
58
|
+
mapping_steps = apply_declarations(mapping_steps, load_declarations)
|
|
59
|
+
|
|
60
|
+
mappings_dict = mappings_as_dicts(mapping_steps, depmap)
|
|
61
|
+
add_after_statements(mappings_dict)
|
|
62
|
+
return mappings_dict
|
|
63
|
+
|
|
64
|
+
# note that it is entirely possible for e.g.
|
|
65
|
+
# M=10 input mapping steps to relate to N=3 tables which generate P=7 load steps.
|
|
66
|
+
#
|
|
67
|
+
# This invariiant will always hold
|
|
68
|
+
#
|
|
69
|
+
# N <= P <= M
|
|
70
|
+
#
|
|
71
|
+
# e.g. 10 Snowfakery Templates generating Accounts, Contacts, Opportunities
|
|
72
|
+
# But Accounts have 5 different update keys and the other two have none.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def collect_user_specified_dependencies(
|
|
76
|
+
declarations: T.Iterable[SObjectRuleDeclaration],
|
|
77
|
+
) -> OrderedSetType[SObjDependency]:
|
|
78
|
+
"""The user can specify load order dependencies."""
|
|
79
|
+
declared_dependencies = [decl for decl in declarations if decl.load_after]
|
|
80
|
+
return OrderedSet(
|
|
81
|
+
[
|
|
82
|
+
SObjDependency(decl.sf_object, decl.load_after, "DECLARED", True)
|
|
83
|
+
for decl in declared_dependencies
|
|
84
|
+
]
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def mappings_as_dicts(
|
|
89
|
+
load_steps: T.List[MappingStep],
|
|
90
|
+
depmap: DependencyMap,
|
|
91
|
+
) -> T.Mapping[str, T.Dict]:
|
|
92
|
+
"""Generate mapping.yml data structures."""
|
|
93
|
+
mappings = {}
|
|
94
|
+
for mapping_step in load_steps:
|
|
95
|
+
step_name = f"{mapping_step.action.value.title()} {mapping_step.sf_object}"
|
|
96
|
+
# Will be used by Snowfakery to generate Upsert mapping files
|
|
97
|
+
if mapping_step.update_key:
|
|
98
|
+
step_name += f" {'_'.join(mapping_step.update_key)}"
|
|
99
|
+
|
|
100
|
+
assert step_name not in mappings
|
|
101
|
+
|
|
102
|
+
mappings[step_name] = mapping_step.dict(
|
|
103
|
+
by_alias=True,
|
|
104
|
+
exclude_defaults=True,
|
|
105
|
+
)
|
|
106
|
+
return mappings
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def apply_declarations(
|
|
110
|
+
mapping_steps: T.List[MappingStep],
|
|
111
|
+
load_declarations: T.List[SObjectRuleDeclaration] = None,
|
|
112
|
+
) -> T.List[MappingStep]:
|
|
113
|
+
"""Apply user-specified declarations.
|
|
114
|
+
Will be used when this code is used to generate load mappings
|
|
115
|
+
from schemas and SQL instead of from ExtractDeclarations."""
|
|
116
|
+
|
|
117
|
+
load_declarations = {decl.sf_object: decl for decl in load_declarations}
|
|
118
|
+
|
|
119
|
+
def doit(mapping_step: MappingStep) -> MappingStep:
|
|
120
|
+
if sobject_declarations := load_declarations.get(mapping_step.sf_object):
|
|
121
|
+
return MappingStep(
|
|
122
|
+
**{**mapping_step.dict(), **sobject_declarations.as_mapping()}
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
return mapping_step
|
|
126
|
+
|
|
127
|
+
return [doit(step) for step in mapping_steps]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import NamedTuple
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def add_after_statements(mappings: dict):
|
|
5
|
+
"""Automatically add CCI after: statements to the lookups
|
|
6
|
+
in a mapping file"""
|
|
7
|
+
indexed_by_sobject = _index_by_sobject(mappings)
|
|
8
|
+
|
|
9
|
+
for idx, (_, mapping) in enumerate(mappings.items()):
|
|
10
|
+
for lookup in mapping.get("lookups", {}).values():
|
|
11
|
+
target_table = lookup["table"]
|
|
12
|
+
# SnowfakeryPersonAccounts: Add this back in when Snowfakery is integrated with this code.
|
|
13
|
+
# PersonContacts are not real, so skip them
|
|
14
|
+
if target_table == "PersonContact": # pragma: no cover
|
|
15
|
+
raise NotImplementedError(
|
|
16
|
+
"This code is not yet tested for use with Snowfakery and Person Accounts"
|
|
17
|
+
)
|
|
18
|
+
# continue
|
|
19
|
+
if isinstance(target_table, list):
|
|
20
|
+
target_mapping_index = max(
|
|
21
|
+
[indexed_by_sobject[table] for table in target_table],
|
|
22
|
+
key=lambda index: index.first_instance,
|
|
23
|
+
)
|
|
24
|
+
else:
|
|
25
|
+
target_mapping_index = indexed_by_sobject[target_table]
|
|
26
|
+
|
|
27
|
+
if target_mapping_index.first_instance >= idx:
|
|
28
|
+
if not lookup.get("after"):
|
|
29
|
+
lookup["after"] = target_mapping_index.last_step_name
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MappingIndex(NamedTuple): # info needed by the algorithm above
|
|
33
|
+
first_instance: int # where was the first time this sobj was referenced?
|
|
34
|
+
last_step_name: str # where was the last (so far)?
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _index_by_sobject(mappings):
|
|
38
|
+
"""Figure out the order in which sobjects are loaded and assign an index to each sobject
|
|
39
|
+
|
|
40
|
+
We can use this to detect sobjects out-of-order which require 'after' declarations."""
|
|
41
|
+
indexed_by_sobject = {}
|
|
42
|
+
for idx, (mapping_name, mapping) in enumerate(mappings.items()):
|
|
43
|
+
# make an index of the order of objects
|
|
44
|
+
sobject = mapping["sf_object"]
|
|
45
|
+
existing_index = indexed_by_sobject.get(sobject)
|
|
46
|
+
|
|
47
|
+
if existing_index:
|
|
48
|
+
new_mi = MappingIndex(existing_index.first_instance, mapping_name)
|
|
49
|
+
else:
|
|
50
|
+
new_mi = MappingIndex(idx, mapping_name)
|
|
51
|
+
indexed_by_sobject[sobject] = new_mi
|
|
52
|
+
|
|
53
|
+
return indexed_by_sobject
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import typing as T
|
|
3
|
+
|
|
4
|
+
from snowfakery.salesforce import find_record_type_column
|
|
5
|
+
|
|
6
|
+
from cumulusci.tasks.bulkdata.mapping_parser import MappingStep
|
|
7
|
+
from cumulusci.tasks.bulkdata.step import DataOperationType
|
|
8
|
+
from cumulusci.utils.yaml.model_parser import CCIModel
|
|
9
|
+
|
|
10
|
+
"""A mapping transform is a function with the signature:
|
|
11
|
+
|
|
12
|
+
def func(mapping_steps: T.List[MappingStep], depmap: "DependencyMap") -> T.List[MappingStep]:
|
|
13
|
+
|
|
14
|
+
It should be idempotent and a pure function (don't mutate arguments).
|
|
15
|
+
|
|
16
|
+
Ideally the output should be as similar to the input as possible (i.e.
|
|
17
|
+
change what you need to change and leave the rest as it was). In particular,
|
|
18
|
+
the order of the input steps should be preserved unless reordering them
|
|
19
|
+
is the specific task of the transform.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from cumulusci.tasks.bulkdata.generate_mapping_utils.dependency_map import DependencyMap
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def sort_steps(
|
|
26
|
+
mapping_steps: T.List[MappingStep], depmap: DependencyMap
|
|
27
|
+
) -> T.List[MappingStep]:
|
|
28
|
+
"""Sort mapping declaration steps in dependency order"""
|
|
29
|
+
table_order = depmap.get_dependency_order()
|
|
30
|
+
|
|
31
|
+
return sorted(mapping_steps, key=lambda step: table_order.index(step.sf_object))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _MappingStepSignature(CCIModel):
|
|
35
|
+
index: int
|
|
36
|
+
sf_object: T.Optional[str]
|
|
37
|
+
filters: T.Optional[T.Tuple[str]] = ()
|
|
38
|
+
soql_filter: T.Optional[str] = None # soql_filter property
|
|
39
|
+
action: DataOperationType
|
|
40
|
+
update_key: T.Union[str, T.Tuple[str, ...]] = () # only for upserts
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def merge_matching_steps(
|
|
44
|
+
steps: T.Iterable[MappingStep], depmap: DependencyMap
|
|
45
|
+
) -> T.List[MappingStep]:
|
|
46
|
+
"""Merge mapping declaration steps with similar properties"""
|
|
47
|
+
table_order = {obj.sf_object: idx for idx, obj in enumerate(steps)}
|
|
48
|
+
grouped_steps = itertools.groupby(
|
|
49
|
+
steps,
|
|
50
|
+
lambda step: _MappingStepSignature(
|
|
51
|
+
index=table_order[step.sf_object],
|
|
52
|
+
sf_object=step.sf_object,
|
|
53
|
+
filters=tuple(step.filters) or None,
|
|
54
|
+
soql_filter=step.soql_filter,
|
|
55
|
+
action=step.action,
|
|
56
|
+
update_key=step.update_key,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
new_steps = [_merge_steps(steps) for _group, steps in grouped_steps]
|
|
61
|
+
return new_steps
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _merge_steps(steps: T.Iterable[MappingStep]) -> MappingStep:
|
|
65
|
+
"""Merge a groupp of matching steps together"""
|
|
66
|
+
steps = tuple(steps)
|
|
67
|
+
new_props = steps[0].dict()
|
|
68
|
+
new_props["fields"] = {}
|
|
69
|
+
new_props["lookups"] = {}
|
|
70
|
+
for step in steps:
|
|
71
|
+
new_props["fields"].update(step.fields)
|
|
72
|
+
new_props["lookups"].update(step.lookups)
|
|
73
|
+
return MappingStep(**new_props)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def rename_record_type_fields(
|
|
77
|
+
mapping_steps: T.List[MappingStep], depmap: DependencyMap
|
|
78
|
+
) -> T.List[MappingStep]:
|
|
79
|
+
"""Rename fields like recordtype, recordtypeid, recordtype_id to RecordTypeId"""
|
|
80
|
+
|
|
81
|
+
def doit(mapping_step: MappingStep):
|
|
82
|
+
table_name = mapping_step.sf_object
|
|
83
|
+
record_type_col = find_record_type_column(table_name, mapping_step.fields)
|
|
84
|
+
if record_type_col:
|
|
85
|
+
fields = mapping_step.fields.copy()
|
|
86
|
+
fields["RecordTypeId"] = fields.pop(record_type_col)
|
|
87
|
+
return MappingStep(**{**mapping_step.dict(), "fields": fields})
|
|
88
|
+
else:
|
|
89
|
+
return mapping_step
|
|
90
|
+
|
|
91
|
+
return list(map(doit, mapping_steps))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def recategorize_lookups(
|
|
95
|
+
mapping_steps: T.List[MappingStep], depmap: DependencyMap
|
|
96
|
+
) -> T.List[MappingStep]:
|
|
97
|
+
"""Categorize fields which are actually lookups
|
|
98
|
+
|
|
99
|
+
Put them in mapping_step.lookup and remove them from mapping_step.fields"""
|
|
100
|
+
|
|
101
|
+
def doit(mapping_step: MappingStep):
|
|
102
|
+
table_name = mapping_step.sf_object
|
|
103
|
+
lookups = mapping_step.lookups.copy() or {}
|
|
104
|
+
lookups.update(
|
|
105
|
+
{
|
|
106
|
+
fieldname: {
|
|
107
|
+
"table": depmap.target_table_for(table_name, fieldname),
|
|
108
|
+
"key_field": fieldname,
|
|
109
|
+
}
|
|
110
|
+
for fieldname in mapping_step.fields
|
|
111
|
+
if depmap.target_table_for(table_name, fieldname)
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if lookups:
|
|
116
|
+
fields = [
|
|
117
|
+
field for field in mapping_step.fields if field not in lookups.keys()
|
|
118
|
+
]
|
|
119
|
+
return MappingStep(
|
|
120
|
+
**{**mapping_step.dict(), "lookups": lookups, "fields": fields}
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
return mapping_step
|
|
124
|
+
|
|
125
|
+
return list(map(doit, mapping_steps))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# SnowfakeryPersonAccounts: This will be turned on when Snowfakery is
|
|
129
|
+
# integrated with this code.
|
|
130
|
+
#
|
|
131
|
+
# def change_person_contact_sf_object(
|
|
132
|
+
# mapping_steps: T.List[MappingStep], depmap: DependencyMap
|
|
133
|
+
# ) -> T.List[MappingStep]:
|
|
134
|
+
# def doit(mapping_step: MappingStep):
|
|
135
|
+
|
|
136
|
+
# if mapping_step.table_name == "PersonContact":
|
|
137
|
+
# mapping_step.sf_object = "Contact"
|
|
138
|
+
|
|
139
|
+
# return list(map(doit, mapping_steps))
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from cumulusci.tasks.bulkdata.extract_dataset_utils.extract_yml import (
|
|
2
|
+
ExtractDeclaration,
|
|
3
|
+
)
|
|
4
|
+
from cumulusci.tasks.bulkdata.extract_dataset_utils.tests.test_synthesize_extract_declarations import (
|
|
5
|
+
_fake_get_org_schema,
|
|
6
|
+
describe_for,
|
|
7
|
+
)
|
|
8
|
+
from cumulusci.tasks.bulkdata.generate_mapping_utils.extract_mapping_file_generator import (
|
|
9
|
+
create_extract_mapping_file_from_declarations,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestGenerateLoadMappingFromDeclarations:
|
|
14
|
+
def test_simple_generate_mapping_from_declarations(self, org_config):
|
|
15
|
+
declarations = [
|
|
16
|
+
ExtractDeclaration(sf_object="Account", fields=["Name", "Description"])
|
|
17
|
+
]
|
|
18
|
+
object_counts = {"Account": 10, "Contact": 0, "Case": 5}
|
|
19
|
+
obj_describes = (
|
|
20
|
+
describe_for("Account"),
|
|
21
|
+
describe_for("Contact"),
|
|
22
|
+
describe_for("Case"),
|
|
23
|
+
)
|
|
24
|
+
with _fake_get_org_schema(
|
|
25
|
+
org_config,
|
|
26
|
+
obj_describes,
|
|
27
|
+
object_counts,
|
|
28
|
+
filters=[],
|
|
29
|
+
include_counts=True,
|
|
30
|
+
) as schema:
|
|
31
|
+
mf = create_extract_mapping_file_from_declarations(declarations, schema, ())
|
|
32
|
+
assert mf == {
|
|
33
|
+
"Extract Account": {
|
|
34
|
+
"api": "smart",
|
|
35
|
+
"sf_object": "Account",
|
|
36
|
+
"fields": ["Name", "Description"],
|
|
37
|
+
"soql_filter": "Name != 'Sample Account for " "Entitlements'",
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def test_generate_mapping_from_declarations__lookups(self, org_config):
|
|
42
|
+
declarations = [
|
|
43
|
+
ExtractDeclaration(sf_object="Account", fields=["Name", "Description"]),
|
|
44
|
+
ExtractDeclaration(sf_object="Contact", fields=["LastName", "AccountId"]),
|
|
45
|
+
]
|
|
46
|
+
object_counts = {"Account": 10, "Contact": 5, "Case": 5}
|
|
47
|
+
obj_describes = (
|
|
48
|
+
describe_for("Account"),
|
|
49
|
+
describe_for("Contact"),
|
|
50
|
+
describe_for("Case"),
|
|
51
|
+
)
|
|
52
|
+
with _fake_get_org_schema(
|
|
53
|
+
org_config,
|
|
54
|
+
obj_describes,
|
|
55
|
+
object_counts,
|
|
56
|
+
filters=[],
|
|
57
|
+
include_counts=True,
|
|
58
|
+
) as schema:
|
|
59
|
+
mf = create_extract_mapping_file_from_declarations(declarations, schema, ())
|
|
60
|
+
print(mf)
|
|
61
|
+
assert mf == {
|
|
62
|
+
"Extract Account": {
|
|
63
|
+
"api": "smart",
|
|
64
|
+
"sf_object": "Account",
|
|
65
|
+
"soql_filter": "Name != 'Sample Account for Entitlements'",
|
|
66
|
+
"fields": ["Name", "Description"],
|
|
67
|
+
},
|
|
68
|
+
"Extract Contact": {
|
|
69
|
+
"api": "smart",
|
|
70
|
+
"sf_object": "Contact",
|
|
71
|
+
"fields": ["LastName"],
|
|
72
|
+
"lookups": {"AccountId": {"table": ("Account",)}},
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
def test_generate_mapping_from_declarations__polymorphic_lookups(self, org_config):
|
|
77
|
+
"""Generate correct mapping file for sobjects with polymorphic lookup fields"""
|
|
78
|
+
declarations = [
|
|
79
|
+
ExtractDeclaration(sf_object="Account", fields=["Name", "Description"]),
|
|
80
|
+
ExtractDeclaration(sf_object="Contact", fields=["LastName", "AccountId"]),
|
|
81
|
+
ExtractDeclaration(sf_object="Event", fields=["Subject", "WhoId"]),
|
|
82
|
+
ExtractDeclaration(sf_object="Lead", fields=["LastName", "Company"]),
|
|
83
|
+
]
|
|
84
|
+
object_counts = {"Account": 10, "Contact": 5, "Case": 5, "Event": 1, "Lead": 2}
|
|
85
|
+
obj_describes = (
|
|
86
|
+
describe_for("Account"),
|
|
87
|
+
describe_for("Contact"),
|
|
88
|
+
describe_for("Case"),
|
|
89
|
+
describe_for("Lead"),
|
|
90
|
+
describe_for("Event"),
|
|
91
|
+
)
|
|
92
|
+
with _fake_get_org_schema(
|
|
93
|
+
org_config,
|
|
94
|
+
obj_describes,
|
|
95
|
+
object_counts,
|
|
96
|
+
filters=[],
|
|
97
|
+
include_counts=True,
|
|
98
|
+
) as schema:
|
|
99
|
+
mf = create_extract_mapping_file_from_declarations(declarations, schema, ())
|
|
100
|
+
print(mf)
|
|
101
|
+
assert mf == {
|
|
102
|
+
"Extract Account": {
|
|
103
|
+
"api": "smart",
|
|
104
|
+
"sf_object": "Account",
|
|
105
|
+
"soql_filter": "Name != 'Sample Account for Entitlements'",
|
|
106
|
+
"fields": ["Name", "Description"],
|
|
107
|
+
},
|
|
108
|
+
"Extract Contact": {
|
|
109
|
+
"api": "smart",
|
|
110
|
+
"sf_object": "Contact",
|
|
111
|
+
"fields": ["LastName"],
|
|
112
|
+
"lookups": {"AccountId": {"table": ("Account",)}},
|
|
113
|
+
},
|
|
114
|
+
"Extract Lead": {
|
|
115
|
+
"api": "smart",
|
|
116
|
+
"sf_object": "Lead",
|
|
117
|
+
"fields": ["LastName", "Company"],
|
|
118
|
+
},
|
|
119
|
+
"Extract Event": {
|
|
120
|
+
"api": "smart",
|
|
121
|
+
"sf_object": "Event",
|
|
122
|
+
"fields": ["Subject"],
|
|
123
|
+
"lookups": {
|
|
124
|
+
"WhoId": {
|
|
125
|
+
"table": (
|
|
126
|
+
"Contact",
|
|
127
|
+
"Lead",
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# TODO: Figure out where clauses
|