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,56 @@
|
|
|
1
|
+
from cumulusci.salesforce_api.metadata import ApiRetrievePackaged
|
|
2
|
+
from cumulusci.tasks.salesforce import UninstallLocal
|
|
3
|
+
from cumulusci.utils import temporary_dir, zip_subfolder
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UninstallPackaged(UninstallLocal):
|
|
7
|
+
|
|
8
|
+
task_options = {
|
|
9
|
+
"package": {
|
|
10
|
+
"description": "The package name to uninstall. All metadata from the package will be retrieved and a custom destructiveChanges.xml package will be constructed and deployed to delete all deleteable metadata from the package. Defaults to project__package__name",
|
|
11
|
+
"required": True,
|
|
12
|
+
},
|
|
13
|
+
"purge_on_delete": {
|
|
14
|
+
"description": "Sets the purgeOnDelete option for the deployment. Defaults to True",
|
|
15
|
+
"required": True,
|
|
16
|
+
},
|
|
17
|
+
"dry_run": {
|
|
18
|
+
"description": "Perform a dry run of the operation without actually deleting any components, and display the components that would be deleted."
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def _init_options(self, kwargs):
|
|
23
|
+
super(UninstallPackaged, self)._init_options(kwargs)
|
|
24
|
+
if "package" not in self.options:
|
|
25
|
+
self.options["package"] = self.project_config.project__package__name
|
|
26
|
+
|
|
27
|
+
def _retrieve_packaged(self):
|
|
28
|
+
retrieve_api = ApiRetrievePackaged(
|
|
29
|
+
self,
|
|
30
|
+
self.options["package"],
|
|
31
|
+
self.project_config.project__package__api_version,
|
|
32
|
+
)
|
|
33
|
+
packaged = retrieve_api()
|
|
34
|
+
packaged = zip_subfolder(packaged, self.options["package"])
|
|
35
|
+
return packaged
|
|
36
|
+
|
|
37
|
+
def _get_destructive_changes(self, path=None):
|
|
38
|
+
self.logger.info(
|
|
39
|
+
"Retrieving metadata in package {} from target org".format(
|
|
40
|
+
self.options["package"]
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
packaged = self._retrieve_packaged()
|
|
44
|
+
|
|
45
|
+
with temporary_dir() as tempdir:
|
|
46
|
+
packaged.extractall(tempdir)
|
|
47
|
+
destructive_changes = super(
|
|
48
|
+
UninstallPackaged, self
|
|
49
|
+
)._get_destructive_changes(tempdir)
|
|
50
|
+
|
|
51
|
+
self.logger.info(
|
|
52
|
+
"Deleting metadata in package {} from target org".format(
|
|
53
|
+
self.options["package"]
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
return destructive_changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Salesforce tasks
|
|
2
|
+
|
|
3
|
+
This package uses a lazy import system inspired by werkzeug
|
|
4
|
+
(for startup speed and to avoid problems with import cycles).
|
|
5
|
+
We should be able to replace LazyModule with a module-level __getattr__
|
|
6
|
+
one we drop support for Python 3.6.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
ORIGINS = {
|
|
13
|
+
"BaseRetrieveMetadata": "cumulusci.tasks.salesforce.BaseRetrieveMetadata",
|
|
14
|
+
"BaseSalesforceTask": "cumulusci.tasks.salesforce.BaseSalesforceTask",
|
|
15
|
+
"BaseSalesforceApiTask": "cumulusci.tasks.salesforce.BaseSalesforceApiTask",
|
|
16
|
+
"BaseSalesforceMetadataApiTask": "cumulusci.tasks.salesforce.BaseSalesforceMetadataApiTask",
|
|
17
|
+
"BaseUninstallMetadata": "cumulusci.tasks.salesforce.BaseUninstallMetadata",
|
|
18
|
+
"CreateCommunity": "cumulusci.tasks.salesforce.CreateCommunity",
|
|
19
|
+
"CreatePackage": "cumulusci.tasks.salesforce.CreatePackage",
|
|
20
|
+
"Deploy": "cumulusci.tasks.salesforce.Deploy",
|
|
21
|
+
"DeployBundles": "cumulusci.tasks.salesforce.DeployBundles",
|
|
22
|
+
"EnsureRecordTypes": "cumulusci.tasks.salesforce.EnsureRecordTypes",
|
|
23
|
+
"GetInstalledPackages": "cumulusci.tasks.preflight.packages",
|
|
24
|
+
"InstallPackageVersion": "cumulusci.tasks.salesforce.install_package_version",
|
|
25
|
+
"ListCommunities": "cumulusci.tasks.salesforce.ListCommunities",
|
|
26
|
+
"ListCommunityTemplates": "cumulusci.tasks.salesforce.ListCommunityTemplates",
|
|
27
|
+
"LoadCustomSettings": "cumulusci.tasks.salesforce.custom_settings",
|
|
28
|
+
"PackageUpload": "cumulusci.tasks.salesforce.package_upload",
|
|
29
|
+
"ProfileGrantAllAccess": "cumulusci.tasks.salesforce.update_profile",
|
|
30
|
+
"PublishCommunity": "cumulusci.tasks.salesforce.PublishCommunity",
|
|
31
|
+
"RetrievePackaged": "cumulusci.tasks.salesforce.RetrievePackaged",
|
|
32
|
+
"RetrieveReportsAndDashboards": "cumulusci.tasks.salesforce.RetrieveReportsAndDashboards",
|
|
33
|
+
"DescribeMetadataTypes": "cumulusci.tasks.salesforce.DescribeMetadataTypes",
|
|
34
|
+
"RetrieveUnpackaged": "cumulusci.tasks.salesforce.RetrieveUnpackaged",
|
|
35
|
+
"SOQLQuery": "cumulusci.tasks.salesforce.SOQLQuery",
|
|
36
|
+
"SetTDTMHandlerStatus": "cumulusci.tasks.salesforce.trigger_handlers",
|
|
37
|
+
"UninstallLocal": "cumulusci.tasks.salesforce.UninstallLocal",
|
|
38
|
+
"UninstallLocalBundles": "cumulusci.tasks.salesforce.UninstallLocalBundles",
|
|
39
|
+
"UninstallLocalNamespacedBundles": "cumulusci.tasks.salesforce.UninstallLocalNamespacedBundles",
|
|
40
|
+
"UninstallPackage": "cumulusci.tasks.salesforce.UninstallPackage",
|
|
41
|
+
"UninstallPackaged": "cumulusci.tasks.salesforce.UninstallPackaged",
|
|
42
|
+
"UninstallPackagedIncremental": "cumulusci.tasks.salesforce.uninstall_packaged_incremental",
|
|
43
|
+
"UpdateDependencies": "cumulusci.tasks.salesforce.update_dependencies",
|
|
44
|
+
"UpdateProfile": "cumulusci.tasks.salesforce.update_profile",
|
|
45
|
+
"UpdateAdminProfile": "cumulusci.tasks.salesforce.update_profile",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LazyModule(ModuleType):
|
|
50
|
+
def __getattr__(self, name):
|
|
51
|
+
# Import and set attribute on demand
|
|
52
|
+
# (__getattr__ is only called if it hasn't been set already)
|
|
53
|
+
if name in ORIGINS:
|
|
54
|
+
origin = ORIGINS[name]
|
|
55
|
+
module = __import__(origin, None, None, [name])
|
|
56
|
+
setattr(self, name, getattr(module, name))
|
|
57
|
+
return ModuleType.__getattribute__(self, name)
|
|
58
|
+
|
|
59
|
+
def __setattr__(self, name, value):
|
|
60
|
+
# Avoid shadowing our intended classes with submodules of the same name
|
|
61
|
+
# when they are imported.
|
|
62
|
+
if name in ORIGINS and isinstance(value, ModuleType):
|
|
63
|
+
return
|
|
64
|
+
ModuleType.__setattr__(self, name, value)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# create LazyModule and replace the reference to ourself in sys.modules
|
|
68
|
+
new_module = sys.modules[__name__] = LazyModule(__name__)
|
|
69
|
+
|
|
70
|
+
# copy over some special attributes
|
|
71
|
+
new_module.__dict__.update(
|
|
72
|
+
{
|
|
73
|
+
"__doc__": __doc__,
|
|
74
|
+
"__file__": __file__,
|
|
75
|
+
"__path__": __path__,
|
|
76
|
+
"__spec__": __spec__,
|
|
77
|
+
"__all__": tuple(ORIGINS),
|
|
78
|
+
}
|
|
79
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from cumulusci.core.exceptions import TaskOptionsError
|
|
2
|
+
from cumulusci.core.utils import process_list_arg
|
|
3
|
+
from cumulusci.tasks.salesforce import BaseSalesforceApiTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ActivateFlow(BaseSalesforceApiTask):
|
|
7
|
+
"""
|
|
8
|
+
Activate the Flows with the supplied Developer Names
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
task_options = {
|
|
12
|
+
"developer_names": {
|
|
13
|
+
"description": "List of DeveloperNames to query in SOQL",
|
|
14
|
+
"required": True,
|
|
15
|
+
},
|
|
16
|
+
"status": {
|
|
17
|
+
"description": "Flag to check whether to activate or deactivate the flow",
|
|
18
|
+
"required": False,
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def _init_options(self, kwargs):
|
|
23
|
+
super(ActivateFlow, self)._init_options(kwargs)
|
|
24
|
+
self.options["developer_names"] = process_list_arg(
|
|
25
|
+
self.options.get("developer_names")
|
|
26
|
+
)
|
|
27
|
+
self.api_version = self.project_config.project__api_version
|
|
28
|
+
if not self.options["developer_names"]:
|
|
29
|
+
raise TaskOptionsError(
|
|
30
|
+
"Error you are missing developer_names definition in your task cumulusci.yml file. Please pass in developer_names for your task configuration or use -o to developer_names as a commandline argument"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def _run_task(self):
|
|
34
|
+
if self.options["status"]:
|
|
35
|
+
self.logger.info(
|
|
36
|
+
f"Activating the following Flows: {self.options['developer_names']}"
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
self.logger.info(
|
|
40
|
+
f"Deactivating the following Flows: {self.options['developer_names']}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
self.logger.info("Querying flow definitions...")
|
|
44
|
+
result = self.tooling.query(
|
|
45
|
+
"SELECT Id, ActiveVersion.VersionNumber, LatestVersion.VersionNumber, DeveloperName FROM FlowDefinition WHERE DeveloperName IN ({0})".format(
|
|
46
|
+
",".join([f"'{n}'" for n in self.options["developer_names"]])
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
results = []
|
|
51
|
+
for listed_flow in result["records"]:
|
|
52
|
+
results.append(listed_flow["DeveloperName"])
|
|
53
|
+
self.logger.info(f'Processing: {listed_flow["DeveloperName"]}')
|
|
54
|
+
path = f"tooling/sobjects/FlowDefinition/{listed_flow['Id']}"
|
|
55
|
+
|
|
56
|
+
urlpath = self.sf.base_url + path
|
|
57
|
+
|
|
58
|
+
if self.options["status"]:
|
|
59
|
+
updated_version_number = listed_flow["LatestVersion"]["VersionNumber"]
|
|
60
|
+
else:
|
|
61
|
+
updated_version_number = 0
|
|
62
|
+
data = {"Metadata": {"activeVersionNumber": updated_version_number}}
|
|
63
|
+
self.logger.info(urlpath)
|
|
64
|
+
response = self.tooling._call_salesforce("PATCH", urlpath, json=data)
|
|
65
|
+
self.logger.info(response)
|
|
66
|
+
|
|
67
|
+
excluded = []
|
|
68
|
+
for i in self.options["developer_names"]:
|
|
69
|
+
if i not in results:
|
|
70
|
+
excluded.append(i)
|
|
71
|
+
if len(excluded) > 0:
|
|
72
|
+
self.logger.warning(
|
|
73
|
+
f"The following developer names were not found: {excluded}"
|
|
74
|
+
)
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from itertools import chain
|
|
7
|
+
from xml.etree.ElementTree import ParseError
|
|
8
|
+
|
|
9
|
+
from defusedxml.minidom import parseString
|
|
10
|
+
|
|
11
|
+
from cumulusci.core.config import FlowConfig, TaskConfig
|
|
12
|
+
from cumulusci.core.exceptions import TaskOptionsError
|
|
13
|
+
from cumulusci.core.flowrunner import FlowCoordinator
|
|
14
|
+
from cumulusci.core.sfdx import convert_sfdx_source
|
|
15
|
+
from cumulusci.core.utils import process_list_arg
|
|
16
|
+
from cumulusci.salesforce_api.metadata import ApiRetrieveUnpackaged
|
|
17
|
+
from cumulusci.tasks.metadata.package import process_common_components
|
|
18
|
+
from cumulusci.tasks.salesforce import BaseSalesforceTask
|
|
19
|
+
from cumulusci.utils import cd
|
|
20
|
+
from cumulusci.utils.xml import metadata_tree
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CheckComponents(BaseSalesforceTask):
|
|
24
|
+
api_retrieve_unpackaged = ApiRetrieveUnpackaged
|
|
25
|
+
task_options = {
|
|
26
|
+
"paths": {
|
|
27
|
+
"description": "List of deploy paths to check",
|
|
28
|
+
"required": False,
|
|
29
|
+
},
|
|
30
|
+
"name": {
|
|
31
|
+
"description": "The name of the current plan or flow to detect deploy paths",
|
|
32
|
+
"required": False,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
deploy_paths = []
|
|
36
|
+
|
|
37
|
+
def _init_options(self, kwargs):
|
|
38
|
+
super(CheckComponents, self)._init_options(kwargs)
|
|
39
|
+
if "paths" in self.options and "name" in self.options:
|
|
40
|
+
raise TaskOptionsError("Please provide either --paths or --name")
|
|
41
|
+
if "paths" not in self.options and "name" not in self.options:
|
|
42
|
+
raise TaskOptionsError(
|
|
43
|
+
"This task requires a plan/flow name or paths options. Pass --paths or --name options"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def _run_task(self):
|
|
47
|
+
# Check if paths are provided in options. Assuming to only check for those paths
|
|
48
|
+
paths = self.options.get("paths")
|
|
49
|
+
plan_or_flow_name = self.options.get("name")
|
|
50
|
+
|
|
51
|
+
(
|
|
52
|
+
components,
|
|
53
|
+
api_retrieve_unpackaged_response,
|
|
54
|
+
) = self.get_repo_existing_components(plan_or_flow_name, paths)
|
|
55
|
+
|
|
56
|
+
if not components:
|
|
57
|
+
self.logger.info("No components found in deploy path")
|
|
58
|
+
raise TaskOptionsError("No plan or paths options provided")
|
|
59
|
+
|
|
60
|
+
self.logger.debug("Components detected at source")
|
|
61
|
+
for component_type, component_names in components.items():
|
|
62
|
+
self.logger.debug(f"{component_type}: {', '.join(component_names)}")
|
|
63
|
+
# check common components
|
|
64
|
+
components.pop("Settings", None)
|
|
65
|
+
existing_components = process_common_components(
|
|
66
|
+
api_retrieve_unpackaged_response, components
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if existing_components:
|
|
70
|
+
self.logger.info("Components exists in the target org:")
|
|
71
|
+
for component_type, component_names in existing_components.items():
|
|
72
|
+
self.logger.info(f"{component_type}: {', '.join(component_names)}")
|
|
73
|
+
self.return_values["existing_components"] = existing_components
|
|
74
|
+
else:
|
|
75
|
+
self.logger.info(
|
|
76
|
+
"No components from the deploy paths exist in the target org."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def get_repo_existing_components(self, plan_or_flow_name, paths=""):
|
|
80
|
+
if paths:
|
|
81
|
+
paths = process_list_arg(paths)
|
|
82
|
+
self.logger.info(f"Using provided paths: {paths}")
|
|
83
|
+
self.deploy_paths = paths
|
|
84
|
+
elif plan_or_flow_name:
|
|
85
|
+
# if path is not provided
|
|
86
|
+
is_plan = self._is_plan(plan_or_flow_name)
|
|
87
|
+
if is_plan is None:
|
|
88
|
+
raise TaskOptionsError(
|
|
89
|
+
f"Plan or flow name '{plan_or_flow_name}' not found"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self.logger.info(
|
|
93
|
+
f"Analyzing project {'plan' if is_plan else 'flow'}: {plan_or_flow_name}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# load deploy paths from all the steps in plan or flow
|
|
97
|
+
self._load_deploy_paths(plan_or_flow_name, is_plan)
|
|
98
|
+
if not self.deploy_paths:
|
|
99
|
+
self.logger.warning("No deploy paths found in the plan or flow.")
|
|
100
|
+
return
|
|
101
|
+
self.logger.debug(
|
|
102
|
+
f"deploy paths found in the plan or flow.{self.deploy_paths}"
|
|
103
|
+
)
|
|
104
|
+
# Temp dir to copy all deploy paths from task options
|
|
105
|
+
temp_dir = tempfile.mkdtemp()
|
|
106
|
+
self.logger.info(f"Temporary deploy directory created: {temp_dir}")
|
|
107
|
+
mdapi_components = {}
|
|
108
|
+
mdapi_response_messages = []
|
|
109
|
+
for path in self.deploy_paths:
|
|
110
|
+
full_path = os.path.join(self.project_config.repo_root, path)
|
|
111
|
+
if not os.path.exists(full_path):
|
|
112
|
+
self.logger.info(f"Skipping path: '{path}' - path doesn't exist")
|
|
113
|
+
continue
|
|
114
|
+
elif "package.xml" in os.listdir(full_path):
|
|
115
|
+
package_xml_path = os.path.join(full_path, "package.xml")
|
|
116
|
+
source_xml_tree = metadata_tree.parse(package_xml_path)
|
|
117
|
+
components = metadata_tree.parse_package_xml_types(
|
|
118
|
+
"name", source_xml_tree
|
|
119
|
+
)
|
|
120
|
+
response_messages = self._get_api_object_responce(
|
|
121
|
+
package_xml_path, source_xml_tree.version.text
|
|
122
|
+
)
|
|
123
|
+
merged = {}
|
|
124
|
+
for key in set(components).union(mdapi_components):
|
|
125
|
+
merged[key] = list(
|
|
126
|
+
set(
|
|
127
|
+
chain(
|
|
128
|
+
components.get(key, []), mdapi_components.get(key, [])
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
mdapi_components = merged
|
|
133
|
+
mdapi_response_messages.extend(response_messages)
|
|
134
|
+
continue
|
|
135
|
+
self._copy_to_tempdir(path, temp_dir)
|
|
136
|
+
|
|
137
|
+
(
|
|
138
|
+
components,
|
|
139
|
+
api_retrieve_unpackaged_response,
|
|
140
|
+
) = self._collect_components_from_paths(temp_dir)
|
|
141
|
+
|
|
142
|
+
# remove temp dir
|
|
143
|
+
shutil.rmtree(temp_dir)
|
|
144
|
+
merged = {}
|
|
145
|
+
if components:
|
|
146
|
+
for key in set(components).union(mdapi_components):
|
|
147
|
+
merged[key] = list(
|
|
148
|
+
set(chain(components.get(key, []), mdapi_components.get(key, [])))
|
|
149
|
+
)
|
|
150
|
+
components = merged
|
|
151
|
+
else:
|
|
152
|
+
components = mdapi_components
|
|
153
|
+
|
|
154
|
+
if api_retrieve_unpackaged_response:
|
|
155
|
+
api_retrieve_unpackaged_response.extend(mdapi_response_messages)
|
|
156
|
+
else:
|
|
157
|
+
api_retrieve_unpackaged_response = mdapi_response_messages
|
|
158
|
+
|
|
159
|
+
return [components, api_retrieve_unpackaged_response]
|
|
160
|
+
|
|
161
|
+
def _copy_to_tempdir(self, src_dir, temp_dir):
|
|
162
|
+
for item in os.listdir(src_dir):
|
|
163
|
+
src_item = os.path.join(src_dir, item)
|
|
164
|
+
dst_item = os.path.join(temp_dir, item)
|
|
165
|
+
|
|
166
|
+
if os.path.isdir(src_item):
|
|
167
|
+
if not os.path.exists(dst_item):
|
|
168
|
+
shutil.copytree(src_item, dst_item)
|
|
169
|
+
else:
|
|
170
|
+
self._merge_directories(src_item, dst_item)
|
|
171
|
+
else:
|
|
172
|
+
if not os.path.exists(dst_item):
|
|
173
|
+
shutil.copy2(src_item, dst_item)
|
|
174
|
+
else:
|
|
175
|
+
self.logger.debug(f"File {dst_item} already exists, skipping...")
|
|
176
|
+
|
|
177
|
+
def _merge_directories(self, src_dir, dst_dir):
|
|
178
|
+
for item in os.listdir(src_dir):
|
|
179
|
+
src_item = os.path.join(src_dir, item)
|
|
180
|
+
dst_item = os.path.join(dst_dir, item)
|
|
181
|
+
|
|
182
|
+
if os.path.isdir(src_item):
|
|
183
|
+
if not os.path.exists(dst_item):
|
|
184
|
+
shutil.copytree(src_item, dst_item)
|
|
185
|
+
self._merge_directories(src_item, dst_item)
|
|
186
|
+
else:
|
|
187
|
+
if not os.path.exists(dst_item):
|
|
188
|
+
shutil.copy2(src_item, dst_item) # Copy file if it doesn't exist
|
|
189
|
+
else:
|
|
190
|
+
self.logger.debug(f"File {dst_item} already exists, skipping...")
|
|
191
|
+
|
|
192
|
+
def _is_plan(self, name):
|
|
193
|
+
|
|
194
|
+
if self.project_config.lookup(f"plans__{name}") is not None:
|
|
195
|
+
return True
|
|
196
|
+
elif self.project_config.lookup(f"flows__{name}") is not None:
|
|
197
|
+
return False
|
|
198
|
+
else:
|
|
199
|
+
raise TaskOptionsError(
|
|
200
|
+
"No paths provided and unable to determine the current plan or flow name."
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def _get_plan_tasks(self, name, is_plan=False):
|
|
204
|
+
|
|
205
|
+
tasks = []
|
|
206
|
+
if is_plan:
|
|
207
|
+
step_config = self.project_config.lookup(f"plans__{name}")
|
|
208
|
+
else:
|
|
209
|
+
step_config = self.project_config.lookup(f"flows__{name}")
|
|
210
|
+
|
|
211
|
+
tasks = self._freeze_steps(self.project_config, step_config)
|
|
212
|
+
|
|
213
|
+
return tasks
|
|
214
|
+
|
|
215
|
+
def _freeze_steps(self, project_config, plan_config) -> list:
|
|
216
|
+
steps = plan_config["steps"]
|
|
217
|
+
flow_config = FlowConfig(plan_config)
|
|
218
|
+
flow_config.project_config = project_config
|
|
219
|
+
flow = FlowCoordinator(project_config, flow_config)
|
|
220
|
+
steps = []
|
|
221
|
+
for step in flow.steps:
|
|
222
|
+
if step.skip:
|
|
223
|
+
continue
|
|
224
|
+
with cd(step.project_config.repo_root):
|
|
225
|
+
task = step.task_class(
|
|
226
|
+
step.project_config,
|
|
227
|
+
TaskConfig(step.task_config),
|
|
228
|
+
name=step.task_name,
|
|
229
|
+
)
|
|
230
|
+
steps.extend(task.freeze(step))
|
|
231
|
+
self.logger.debug("Prepared steps:\n" + json.dumps(steps, indent=4))
|
|
232
|
+
return steps
|
|
233
|
+
|
|
234
|
+
def _load_deploy_paths(self, name, is_plan=False):
|
|
235
|
+
tasks = self._get_plan_tasks(name, is_plan)
|
|
236
|
+
if tasks:
|
|
237
|
+
self.deploy_paths = self._get_deployable_paths(tasks)
|
|
238
|
+
|
|
239
|
+
def _get_deployable_paths(self, tasks):
|
|
240
|
+
found_paths = []
|
|
241
|
+
paths_to_search = ["path", "subfolder"]
|
|
242
|
+
for task in tasks:
|
|
243
|
+
if "task_config" in task and "options" in task["task_config"]:
|
|
244
|
+
options = task["task_config"]["options"]
|
|
245
|
+
found_paths.extend(self._search_for_paths(options, paths_to_search))
|
|
246
|
+
return found_paths
|
|
247
|
+
|
|
248
|
+
def _search_for_paths(self, options, keys_to_search):
|
|
249
|
+
found_values = []
|
|
250
|
+
|
|
251
|
+
if not keys_to_search:
|
|
252
|
+
return found_values
|
|
253
|
+
|
|
254
|
+
def recursive_search(obj):
|
|
255
|
+
if isinstance(obj, dict):
|
|
256
|
+
for key, value in obj.items():
|
|
257
|
+
if key in keys_to_search and isinstance(value, str):
|
|
258
|
+
found_values.append(value)
|
|
259
|
+
elif isinstance(value, (dict, list)):
|
|
260
|
+
recursive_search(value)
|
|
261
|
+
|
|
262
|
+
elif isinstance(obj, list):
|
|
263
|
+
for item in obj:
|
|
264
|
+
recursive_search(item)
|
|
265
|
+
|
|
266
|
+
recursive_search(options)
|
|
267
|
+
|
|
268
|
+
return found_values
|
|
269
|
+
|
|
270
|
+
def _collect_components_from_paths(self, full_path):
|
|
271
|
+
|
|
272
|
+
if not os.path.exists(full_path):
|
|
273
|
+
return None, None
|
|
274
|
+
|
|
275
|
+
components = defaultdict(set)
|
|
276
|
+
self.logger.info(f"Collecting components from path: {full_path}")
|
|
277
|
+
# remove if any exiting package.xml files coppied from deploy_pre/post paths
|
|
278
|
+
|
|
279
|
+
if os.path.exists(os.path.join(full_path, "package.xml")):
|
|
280
|
+
os.remove(os.path.join(full_path, "package.xml"))
|
|
281
|
+
|
|
282
|
+
with convert_sfdx_source(full_path, None, self.logger) as src_path:
|
|
283
|
+
package_xml_path = os.path.join(src_path, "package.xml")
|
|
284
|
+
if os.path.exists(package_xml_path):
|
|
285
|
+
try:
|
|
286
|
+
source_xml_tree = metadata_tree.parse(package_xml_path)
|
|
287
|
+
self.logger.info("parsing package.xml")
|
|
288
|
+
|
|
289
|
+
components = metadata_tree.parse_package_xml_types(
|
|
290
|
+
"name", source_xml_tree
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
response_messages = self._get_api_object_responce(
|
|
294
|
+
package_xml_path, source_xml_tree.version.text
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
return [components, response_messages]
|
|
298
|
+
|
|
299
|
+
except ParseError as e:
|
|
300
|
+
self.logger.error(f"Error parsing package.xml: {e}")
|
|
301
|
+
return None, None
|
|
302
|
+
else:
|
|
303
|
+
self.logger.warning(
|
|
304
|
+
f"No package.xml found in {full_path}, scanning directories"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
return None, None
|
|
308
|
+
|
|
309
|
+
def _get_api_object_responce(self, pakcage_xml_path, version):
|
|
310
|
+
|
|
311
|
+
if not os.path.exists(pakcage_xml_path):
|
|
312
|
+
return None
|
|
313
|
+
|
|
314
|
+
package_xml = open(pakcage_xml_path, "r")
|
|
315
|
+
|
|
316
|
+
api_retrieve_unpackaged_object = self.api_retrieve_unpackaged(
|
|
317
|
+
self, package_xml.read(), version
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
response_messages = parseString(
|
|
321
|
+
api_retrieve_unpackaged_object._get_response().content
|
|
322
|
+
).getElementsByTagName("messages")
|
|
323
|
+
|
|
324
|
+
return response_messages
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import random
|
|
3
|
+
import re
|
|
4
|
+
import string
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from cumulusci.cli.ui import CliTable
|
|
8
|
+
from cumulusci.core.exceptions import SalesforceException
|
|
9
|
+
from cumulusci.core.utils import process_bool_arg, process_list_arg, determine_managed_mode
|
|
10
|
+
from cumulusci.tasks.salesforce import BaseSalesforceApiTask
|
|
11
|
+
from cumulusci.utils import inject_namespace
|
|
12
|
+
|
|
13
|
+
API_ROLLBACK_MESSAGE = "The transaction was rolled back since another operation in the same transaction failed."
|
|
14
|
+
API_INVALID_REF_MESSAGE = "Invalid reference specified."
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CompositeApi(BaseSalesforceApiTask):
|
|
18
|
+
task_docs = """
|
|
19
|
+
This task is a wrapper for Composite REST API calls. Given a list of JSON files
|
|
20
|
+
(one request body per file), POST each and process the returned composite
|
|
21
|
+
result. Files are processed in the order given by the ``data_files`` option.
|
|
22
|
+
|
|
23
|
+
In addition, this task will process the request body and replace namespace
|
|
24
|
+
(``%%%NAMESPACE%%%``) and user ID (``%%%USERID%%%``) tokens. To avoid username
|
|
25
|
+
collisions, use the ``randomize_username`` option to replace the top-level
|
|
26
|
+
domains in any ``Username`` field with a random string.
|
|
27
|
+
|
|
28
|
+
When the top-level ``allOrNone`` property for the request is set to true a
|
|
29
|
+
SalesforceException is raised if an error is returned for any subrequest,
|
|
30
|
+
otherwise partial successes will not raise an exception.
|
|
31
|
+
|
|
32
|
+
Example Task Definition
|
|
33
|
+
-----------------------
|
|
34
|
+
|
|
35
|
+
.. code-block:: yaml
|
|
36
|
+
|
|
37
|
+
tasks:
|
|
38
|
+
example_composite_request:
|
|
39
|
+
class_path: cumulusci.tasks.salesforce.composite.CompositeApi
|
|
40
|
+
options:
|
|
41
|
+
data_files:
|
|
42
|
+
- "datasets/composite/users.json"
|
|
43
|
+
- "datasets/composite/setup_objects.json"
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
task_options = {
|
|
47
|
+
"data_files": {
|
|
48
|
+
"description": "A list of paths, where each path is a JSON file containing a composite request body.",
|
|
49
|
+
"required": True,
|
|
50
|
+
},
|
|
51
|
+
"managed": {
|
|
52
|
+
"description": "If True, replaces namespace tokens with the namespace prefix.",
|
|
53
|
+
"default": False,
|
|
54
|
+
},
|
|
55
|
+
"namespaced": {
|
|
56
|
+
"description": "If True, replaces namespace tokens with the namespace prefix.",
|
|
57
|
+
"default": False,
|
|
58
|
+
},
|
|
59
|
+
"randomize_username": {
|
|
60
|
+
"description": "If True, randomize the TLD for any 'Username' fields.",
|
|
61
|
+
"default": False,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def _init_options(self, kwargs):
|
|
66
|
+
super()._init_options(kwargs)
|
|
67
|
+
self.data_files = process_list_arg(self.options.get("data_files") or [])
|
|
68
|
+
|
|
69
|
+
def _run_task(self):
|
|
70
|
+
for data_file_path in self.data_files:
|
|
71
|
+
self.logger.info(f"Processing {data_file_path}")
|
|
72
|
+
self._composite_request(data_file_path)
|
|
73
|
+
|
|
74
|
+
def _composite_request(self, data_file_path):
|
|
75
|
+
request_body = self._process_json(Path(data_file_path).read_text())
|
|
76
|
+
self.is_all_or_none = json.loads(request_body).get("allOrNone", False)
|
|
77
|
+
result = self.sf.restful("composite", method="POST", data=request_body)
|
|
78
|
+
self._process_response(result)
|
|
79
|
+
|
|
80
|
+
def _process_json(self, body):
|
|
81
|
+
"""Replace namespace tokens and randomize username domains."""
|
|
82
|
+
user_id = self.org_config.user_id
|
|
83
|
+
body = body.replace("%%%USERID%%%", user_id)
|
|
84
|
+
|
|
85
|
+
namespace = self.project_config.project__package__namespace
|
|
86
|
+
managed = determine_managed_mode(
|
|
87
|
+
self.options, self.project_config, self.org_config
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
_, body = inject_namespace(
|
|
91
|
+
"composite",
|
|
92
|
+
body,
|
|
93
|
+
namespace=namespace,
|
|
94
|
+
managed=managed,
|
|
95
|
+
namespaced_org=self.options.get("namespaced", self.org_config.namespaced),
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if self.options.get("randomize_username", False):
|
|
99
|
+
random_tld = "".join(random.choices(string.ascii_lowercase, k=4))
|
|
100
|
+
body = re.sub(
|
|
101
|
+
r'("Username": .[\w-]+@[\w-]+\.)+[\w-]+', rf"\1{random_tld}", body
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return body
|
|
105
|
+
|
|
106
|
+
def _process_response(self, result):
|
|
107
|
+
"""Handle the compositeResponse and raise an exception if failed."""
|
|
108
|
+
subrequests = result["compositeResponse"]
|
|
109
|
+
status_codes = {subrequest["httpStatusCode"] for subrequest in subrequests}
|
|
110
|
+
|
|
111
|
+
all_success = all([self._http_ok(code) for code in status_codes])
|
|
112
|
+
if self.is_all_or_none and not all_success:
|
|
113
|
+
self._log_exception_message(subrequests)
|
|
114
|
+
raise SalesforceException(json.dumps(subrequests, indent=2))
|
|
115
|
+
else:
|
|
116
|
+
self._log_success_message(subrequests)
|
|
117
|
+
|
|
118
|
+
def _http_ok(self, status_code):
|
|
119
|
+
return status_code >= 200 and status_code < 300
|
|
120
|
+
|
|
121
|
+
def _log_exception_message(self, subrequests):
|
|
122
|
+
table_data = [["ReferenceId", "Message"]]
|
|
123
|
+
table_data.extend(
|
|
124
|
+
[sub["referenceId"], body["message"]]
|
|
125
|
+
for sub in subrequests
|
|
126
|
+
for body in sub["body"]
|
|
127
|
+
if body.get("message") != API_ROLLBACK_MESSAGE
|
|
128
|
+
)
|
|
129
|
+
table = CliTable(
|
|
130
|
+
table_data,
|
|
131
|
+
)
|
|
132
|
+
self.logger.error("The request failed with the following message(s):\n\n")
|
|
133
|
+
table.echo()
|
|
134
|
+
|
|
135
|
+
def _log_success_message(self, subrequests):
|
|
136
|
+
table_data = [["ReferenceId", "Success"]]
|
|
137
|
+
table_data.extend(
|
|
138
|
+
[sub["referenceId"], self._http_ok(sub["httpStatusCode"])]
|
|
139
|
+
for sub in subrequests
|
|
140
|
+
)
|
|
141
|
+
table = CliTable(table_data, title="Subrequest Results")
|
|
142
|
+
table.echo()
|