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,436 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from abc import ABCMeta, abstractmethod
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from urllib.parse import quote, unquote
|
|
5
|
+
|
|
6
|
+
from cumulusci.core.config import TaskConfig
|
|
7
|
+
from cumulusci.core.enums import StrEnum
|
|
8
|
+
from cumulusci.core.exceptions import CumulusCIException, TaskOptionsError
|
|
9
|
+
from cumulusci.core.tasks import BaseSalesforceTask
|
|
10
|
+
from cumulusci.core.utils import process_bool_arg, process_list_arg, determine_managed_mode
|
|
11
|
+
from cumulusci.salesforce_api.metadata import ApiRetrieveUnpackaged
|
|
12
|
+
from cumulusci.tasks.metadata.package import PackageXmlGenerator
|
|
13
|
+
from cumulusci.utils import inject_namespace
|
|
14
|
+
from cumulusci.utils.xml import metadata_tree
|
|
15
|
+
from cumulusci.utils.xml.metadata_tree import MetadataElement
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MetadataOperation(StrEnum):
|
|
19
|
+
DEPLOY = "deploy"
|
|
20
|
+
RETRIEVE = "retrieve"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BaseMetadataETLTask(BaseSalesforceTask, metaclass=ABCMeta):
|
|
24
|
+
"""Abstract base class for all Metadata ETL tasks. Concrete tasks should
|
|
25
|
+
generally subclass BaseMetadataSynthesisTask, BaseMetadataTransformTask,
|
|
26
|
+
or MetadataSingleEntityTransformTask."""
|
|
27
|
+
|
|
28
|
+
deploy = False
|
|
29
|
+
retrieve = False
|
|
30
|
+
|
|
31
|
+
task_options = {
|
|
32
|
+
"managed": {
|
|
33
|
+
"description": "If False, changes namespace_inject to replace tokens with a blank string"
|
|
34
|
+
},
|
|
35
|
+
"namespace_inject": {
|
|
36
|
+
"description": "If set, the namespace tokens in files and filenames are replaced with the namespace's prefix"
|
|
37
|
+
},
|
|
38
|
+
"api_version": {
|
|
39
|
+
"description": "Metadata API version to use, if not project__package__api_version."
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def _init_options(self, kwargs):
|
|
44
|
+
super()._init_options(kwargs)
|
|
45
|
+
|
|
46
|
+
self.api_version = (
|
|
47
|
+
self.options.get("api_version")
|
|
48
|
+
or self.project_config.project__package__api_version
|
|
49
|
+
)
|
|
50
|
+
try:
|
|
51
|
+
float(self.api_version)
|
|
52
|
+
except ValueError:
|
|
53
|
+
raise TaskOptionsError(f"Invalid API version {self.api_version}")
|
|
54
|
+
|
|
55
|
+
self.options["namespace_inject"] = (
|
|
56
|
+
self.options.get("namespace_inject")
|
|
57
|
+
or self.project_config.project__package__namespace
|
|
58
|
+
)
|
|
59
|
+
# org_config might be None if we're freezing steps for metadeploy.
|
|
60
|
+
# We can only autodetect the context for namespace injection if we have the org.
|
|
61
|
+
if self.org_config:
|
|
62
|
+
self._init_namespace_injection()
|
|
63
|
+
|
|
64
|
+
def _init_namespace_injection(self):
|
|
65
|
+
namespace = (
|
|
66
|
+
self.options.get("namespace_inject")
|
|
67
|
+
or self.project_config.project__package__namespace
|
|
68
|
+
)
|
|
69
|
+
self.options["managed"] = determine_managed_mode(
|
|
70
|
+
self.options, self.project_config, self.org_config
|
|
71
|
+
)
|
|
72
|
+
if "namespaced_org" in self.options:
|
|
73
|
+
self.options["namespaced_org"] = process_bool_arg(
|
|
74
|
+
self.options["namespaced_org"] or False
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
self.options["namespaced_org"] = (
|
|
78
|
+
bool(namespace) and namespace == getattr(self.org_config, 'namespace', None)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def _inject_namespace(self, text):
|
|
82
|
+
"""Inject the namespace into the given text if running in managed mode."""
|
|
83
|
+
# We might not have an org yet if this is called from _init_options
|
|
84
|
+
# while freezing steps for metadeploy.
|
|
85
|
+
if self.org_config is None:
|
|
86
|
+
return text
|
|
87
|
+
return inject_namespace(
|
|
88
|
+
"",
|
|
89
|
+
text,
|
|
90
|
+
namespace=self.options["namespace_inject"],
|
|
91
|
+
managed=self.options.get("managed") or False,
|
|
92
|
+
namespaced_org=self.options.get("namespaced_org"),
|
|
93
|
+
)[1]
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def _get_package_xml_content(self, operation):
|
|
97
|
+
"""Return the textual content of a package.xml for the given operation."""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def _generate_package_xml(self, operation):
|
|
101
|
+
"""Call _get_package_xml_content() and perform namespace injection if needed"""
|
|
102
|
+
return self._inject_namespace(self._get_package_xml_content(operation))
|
|
103
|
+
|
|
104
|
+
def _create_directories(self, tempdir):
|
|
105
|
+
"""Create self.retrieve_dir and self.deploy_dir, if required"""
|
|
106
|
+
if self.retrieve:
|
|
107
|
+
self.retrieve_dir = Path(tempdir, "retrieve")
|
|
108
|
+
self.retrieve_dir.mkdir()
|
|
109
|
+
if self.deploy:
|
|
110
|
+
self.deploy_dir = Path(tempdir, "deploy")
|
|
111
|
+
self.deploy_dir.mkdir()
|
|
112
|
+
|
|
113
|
+
def _retrieve(self):
|
|
114
|
+
"""Retrieve metadata into self.retrieve_dir"""
|
|
115
|
+
self.logger.info("Extracting existing metadata...")
|
|
116
|
+
api_retrieve = ApiRetrieveUnpackaged(
|
|
117
|
+
self,
|
|
118
|
+
self._generate_package_xml(MetadataOperation.RETRIEVE),
|
|
119
|
+
self.api_version,
|
|
120
|
+
)
|
|
121
|
+
unpackaged = api_retrieve()
|
|
122
|
+
unpackaged.extractall(self.retrieve_dir)
|
|
123
|
+
|
|
124
|
+
@abstractmethod
|
|
125
|
+
def _transform(self):
|
|
126
|
+
"""Transform the metadata in self.retrieve_dir into self.deploy_dir."""
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
def _deploy(self):
|
|
130
|
+
"""Deploy metadata from self.deploy_dir"""
|
|
131
|
+
self.logger.info("Loading transformed metadata...")
|
|
132
|
+
target_profile_xml = Path(self.deploy_dir, "package.xml")
|
|
133
|
+
target_profile_xml.write_text(
|
|
134
|
+
self._generate_package_xml(MetadataOperation.DEPLOY), encoding="utf-8"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# import is here to avoid an import cycle
|
|
138
|
+
from cumulusci.tasks.salesforce import Deploy
|
|
139
|
+
|
|
140
|
+
api = Deploy(
|
|
141
|
+
self.project_config,
|
|
142
|
+
TaskConfig(
|
|
143
|
+
{
|
|
144
|
+
"options": {
|
|
145
|
+
"path": self.deploy_dir,
|
|
146
|
+
"namespace_inject": self.options.get("namespace_inject"),
|
|
147
|
+
"unmanaged": not self.options["managed"],
|
|
148
|
+
"namespaced_org": self.options["namespaced_org"],
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
self.org_config,
|
|
153
|
+
)
|
|
154
|
+
result = api()
|
|
155
|
+
|
|
156
|
+
return result
|
|
157
|
+
|
|
158
|
+
def _post_deploy(self, result):
|
|
159
|
+
"""Run any post-deploy logic required, such as waiting for asynchronous
|
|
160
|
+
operations to complete in the target org."""
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
def _run_task(self):
|
|
164
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
165
|
+
self._create_directories(tempdir)
|
|
166
|
+
if self.retrieve:
|
|
167
|
+
self._retrieve()
|
|
168
|
+
self._transform()
|
|
169
|
+
if self.deploy:
|
|
170
|
+
result = self._deploy()
|
|
171
|
+
self._post_deploy(result)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class BaseMetadataSynthesisTask(BaseMetadataETLTask, metaclass=ABCMeta):
|
|
175
|
+
"""Base class for Metadata ETL tasks that generate new metadata
|
|
176
|
+
and deploy it into the org, but do not retrieve."""
|
|
177
|
+
|
|
178
|
+
deploy = True
|
|
179
|
+
|
|
180
|
+
def _generate_package_xml(self, deploy):
|
|
181
|
+
"""Synthesize a package.xml for generated metadata."""
|
|
182
|
+
generator = PackageXmlGenerator(str(self.deploy_dir), self.api_version)
|
|
183
|
+
return generator()
|
|
184
|
+
|
|
185
|
+
def _get_package_xml_content(self, operation) -> str:
|
|
186
|
+
return ""
|
|
187
|
+
|
|
188
|
+
def _transform(self):
|
|
189
|
+
self._synthesize()
|
|
190
|
+
|
|
191
|
+
@abstractmethod
|
|
192
|
+
def _synthesize(self):
|
|
193
|
+
"""Create new metadata in self.deploy_dir."""
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class BaseMetadataTransformTask(BaseMetadataETLTask, metaclass=ABCMeta):
|
|
198
|
+
"""Base class for Metadata ETL tasks that extract metadata,
|
|
199
|
+
transform it, and deploy it back into the org."""
|
|
200
|
+
|
|
201
|
+
retrieve = True
|
|
202
|
+
deploy = True
|
|
203
|
+
|
|
204
|
+
@abstractmethod
|
|
205
|
+
def _get_entities(self):
|
|
206
|
+
"""Return a dict of Metadata API entities and API names to be transformed."""
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
def _get_types_package_xml(self):
|
|
210
|
+
"""Generate package.xml content based on the return value of _get_entities()."""
|
|
211
|
+
base = """ <types>
|
|
212
|
+
{members}
|
|
213
|
+
<name>{name}</name>
|
|
214
|
+
</types>
|
|
215
|
+
"""
|
|
216
|
+
types = ""
|
|
217
|
+
for entity, api_names in self._get_entities().items():
|
|
218
|
+
members = "\n".join(
|
|
219
|
+
f" <members>{api_name}</members>"
|
|
220
|
+
for api_name in sorted(api_names)
|
|
221
|
+
)
|
|
222
|
+
types += base.format(members=members, name=entity)
|
|
223
|
+
|
|
224
|
+
return types
|
|
225
|
+
|
|
226
|
+
def _get_package_xml_content(self, operation):
|
|
227
|
+
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
|
228
|
+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
229
|
+
{self._get_types_package_xml()}
|
|
230
|
+
<version>{self.api_version}</version>
|
|
231
|
+
</Package>
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
@abstractmethod
|
|
235
|
+
def _transform(self):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class MetadataSingleEntityTransformTask(BaseMetadataTransformTask, metaclass=ABCMeta):
|
|
240
|
+
"""Base class for a Metadata ETL task that affects one or more
|
|
241
|
+
instances of a specific metadata entity. Concrete subclasses must set
|
|
242
|
+
`entity` to the Metadata API entity transformed, and implement _transform_entity()."""
|
|
243
|
+
|
|
244
|
+
entity = None
|
|
245
|
+
|
|
246
|
+
task_options = {
|
|
247
|
+
"api_names": {"description": "List of API names of entities to affect"},
|
|
248
|
+
**BaseMetadataETLTask.task_options,
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
def _init_options(self, kwargs):
|
|
252
|
+
super()._init_options(kwargs)
|
|
253
|
+
|
|
254
|
+
self.api_names = {
|
|
255
|
+
self._inject_namespace(arg)
|
|
256
|
+
for arg in process_list_arg(self.options.get("api_names", ["*"]))
|
|
257
|
+
}
|
|
258
|
+
self.api_names = {
|
|
259
|
+
quote(arg, safe=" ") if arg != "*" else arg for arg in self.api_names
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
def _get_entities(self):
|
|
263
|
+
return {self.entity: self.api_names}
|
|
264
|
+
|
|
265
|
+
@abstractmethod
|
|
266
|
+
def _transform_entity(self, metadata, api_name):
|
|
267
|
+
"""Accept an XML element corresponding to the metadata entity with
|
|
268
|
+
the given api_name. Transform the XML and return the version which
|
|
269
|
+
should be deployed, or None to suppress deployment of this entity."""
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
def _transform(self):
|
|
273
|
+
# call _transform_entity once per retrieved entity
|
|
274
|
+
# if the entity is an XML file, provide a parsed version
|
|
275
|
+
# and write the returned metadata into the deploy directory
|
|
276
|
+
|
|
277
|
+
parser = PackageXmlGenerator(
|
|
278
|
+
None, self.api_version
|
|
279
|
+
) # We'll use it for its metadata_map
|
|
280
|
+
entity_configurations = [
|
|
281
|
+
entry
|
|
282
|
+
for entry in parser.metadata_map
|
|
283
|
+
if any(
|
|
284
|
+
[
|
|
285
|
+
subentry["type"] == self.entity
|
|
286
|
+
for subentry in parser.metadata_map[entry]
|
|
287
|
+
]
|
|
288
|
+
)
|
|
289
|
+
]
|
|
290
|
+
if not entity_configurations:
|
|
291
|
+
raise CumulusCIException(
|
|
292
|
+
f"Unable to locate configuration for entity {self.entity}"
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
configuration = parser.metadata_map[entity_configurations[0]][0]
|
|
296
|
+
if configuration["class"] not in [
|
|
297
|
+
"MetadataFilenameParser",
|
|
298
|
+
"CustomObjectParser",
|
|
299
|
+
]:
|
|
300
|
+
raise CumulusCIException(
|
|
301
|
+
f"MetadataSingleEntityTransformTask only supports manipulating complete, file-based XML entities (not {self.entity})"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
extension = configuration["extension"]
|
|
305
|
+
directory = entity_configurations[0]
|
|
306
|
+
source_metadata_dir = self.retrieve_dir / directory
|
|
307
|
+
|
|
308
|
+
if "*" in self.api_names:
|
|
309
|
+
# Walk the retrieved directory to get the actual suite
|
|
310
|
+
# of API names retrieved and rebuild our api_names list.
|
|
311
|
+
self.api_names.remove("*")
|
|
312
|
+
self.api_names = self.api_names.union(
|
|
313
|
+
metadata_file.stem
|
|
314
|
+
for metadata_file in source_metadata_dir.iterdir()
|
|
315
|
+
if metadata_file.suffix == f".{extension}"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
removed_api_names = set()
|
|
319
|
+
|
|
320
|
+
for api_name in self.api_names:
|
|
321
|
+
# Page Layout names can contain spaces, but parentheses and other
|
|
322
|
+
# characters like ' and < are quoted.
|
|
323
|
+
# We quote user-specified API names so we can locate the corresponding
|
|
324
|
+
# metadata files, but present them un-quoted in messages to the user.
|
|
325
|
+
unquoted_api_name = unquote(api_name)
|
|
326
|
+
|
|
327
|
+
path = source_metadata_dir / f"{api_name}.{extension}"
|
|
328
|
+
if not path.exists():
|
|
329
|
+
raise CumulusCIException(f"Cannot find metadata file {path}")
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
tree = metadata_tree.parse(str(path))
|
|
333
|
+
except SyntaxError as err:
|
|
334
|
+
err.filename = path
|
|
335
|
+
raise err
|
|
336
|
+
transformed_xml = self._transform_entity(tree, unquoted_api_name)
|
|
337
|
+
if transformed_xml:
|
|
338
|
+
parent_dir = self.deploy_dir / directory
|
|
339
|
+
if not parent_dir.exists():
|
|
340
|
+
parent_dir.mkdir()
|
|
341
|
+
destination_path = parent_dir / f"{api_name}.{extension}"
|
|
342
|
+
|
|
343
|
+
with destination_path.open(mode="w", encoding="utf-8") as f:
|
|
344
|
+
f.write(transformed_xml.tostring(xml_declaration=True))
|
|
345
|
+
else:
|
|
346
|
+
# Make sure to remove from our package.xml
|
|
347
|
+
removed_api_names.add(api_name)
|
|
348
|
+
|
|
349
|
+
self.api_names = self.api_names - removed_api_names
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class UpdateMetadataFirstChildTextTask(MetadataSingleEntityTransformTask):
|
|
353
|
+
task_docs = """
|
|
354
|
+
Metadata ETL task to update a single child element's text within metadata XML.
|
|
355
|
+
|
|
356
|
+
If the child doesn't exist, the child is created and appended to the Metadata. Furthermore, the ``value`` option is namespaced injected if the task is properly configured.
|
|
357
|
+
|
|
358
|
+
Example: Assign a Custom Object's Compact Layout
|
|
359
|
+
------------------------------------------------
|
|
360
|
+
|
|
361
|
+
Researching `CustomObject <https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/customobject.htm>`_ in the Metadata API documentation or even retrieving the CustomObject's Metadata for inspection, we see the ``compactLayoutAssignment`` Field. We want to assign a specific Compact Layout for our Custom Object, so we write the following CumulusCI task in our project's ``cumulusci.yml``.
|
|
362
|
+
|
|
363
|
+
.. code-block:: yaml
|
|
364
|
+
|
|
365
|
+
tasks:
|
|
366
|
+
assign_compact_layout:
|
|
367
|
+
class_path: cumulusci.tasks.metadata_etl.UpdateMetadataFirstChildTextTask
|
|
368
|
+
options:
|
|
369
|
+
managed: False
|
|
370
|
+
namespace_inject: $project_config.project__package__namespace
|
|
371
|
+
entity: CustomObject
|
|
372
|
+
api_names: OurCustomObject__c
|
|
373
|
+
tag: compactLayoutAssignment
|
|
374
|
+
value: "%%%NAMESPACE%%%DifferentCompactLayout"
|
|
375
|
+
# We include a namespace token so it's easy to use this task in a managed context.
|
|
376
|
+
|
|
377
|
+
Suppose the original CustomObject metadata XML looks like:
|
|
378
|
+
|
|
379
|
+
.. code-block:: xml
|
|
380
|
+
|
|
381
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
382
|
+
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
383
|
+
...
|
|
384
|
+
<label>Our Custom Object</label>
|
|
385
|
+
<compactLayoutAssignment>OriginalCompactLayout</compactLayoutAssignment>
|
|
386
|
+
...
|
|
387
|
+
</CustomObject>
|
|
388
|
+
|
|
389
|
+
After running ``cci task run assign_compact_layout``, the CustomObject metadata XML is deployed as:
|
|
390
|
+
|
|
391
|
+
.. code-block:: xml
|
|
392
|
+
|
|
393
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
394
|
+
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
395
|
+
...
|
|
396
|
+
<label>Our Custom Object</label>
|
|
397
|
+
<compactLayoutAssignment>DifferentCompactLayout</compactLayoutAssignment>
|
|
398
|
+
...
|
|
399
|
+
</CustomObject>
|
|
400
|
+
"""
|
|
401
|
+
|
|
402
|
+
task_options = {
|
|
403
|
+
"metadata_type": {"description": "Metadata Type", "required": True},
|
|
404
|
+
"tag": {
|
|
405
|
+
"description": "Targeted tag. The text of the first instance of this tag within the metadata entity will be updated.",
|
|
406
|
+
"required": True,
|
|
407
|
+
},
|
|
408
|
+
"value": {
|
|
409
|
+
"description": "Desired value to set for the targeted tag's text. This value is namespace-injected.",
|
|
410
|
+
"required": True,
|
|
411
|
+
},
|
|
412
|
+
**MetadataSingleEntityTransformTask.task_options,
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
def _init_options(self, kwargs):
|
|
416
|
+
super()._init_options(kwargs)
|
|
417
|
+
self.entity = self.options.get("metadata_type")
|
|
418
|
+
self.options["value"] = self._inject_namespace(self.options.get("value"))
|
|
419
|
+
|
|
420
|
+
def _transform_entity(
|
|
421
|
+
self, metadata: MetadataElement, api_name: str
|
|
422
|
+
) -> MetadataElement:
|
|
423
|
+
"""Finds metadata's first child with tag. If no child is found, appends
|
|
424
|
+
a new child with tag. Then updates child's text as the value option."""
|
|
425
|
+
tag = self.options["tag"]
|
|
426
|
+
|
|
427
|
+
child = metadata.find(tag)
|
|
428
|
+
if child is None:
|
|
429
|
+
child = metadata.append(tag)
|
|
430
|
+
|
|
431
|
+
child.text = self.options["value"]
|
|
432
|
+
|
|
433
|
+
self.logger.info(f'Updating {self.entity} "{api_name}":')
|
|
434
|
+
self.logger.info(f' {tag} as "{child.text}"')
|
|
435
|
+
|
|
436
|
+
return metadata
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from cumulusci.core.utils import process_bool_arg
|
|
4
|
+
from cumulusci.tasks.metadata_etl import MetadataSingleEntityTransformTask
|
|
5
|
+
from cumulusci.utils.xml.metadata_tree import MetadataElement
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SetDuplicateRuleStatus(MetadataSingleEntityTransformTask):
|
|
9
|
+
entity = "DuplicateRule"
|
|
10
|
+
task_options = {
|
|
11
|
+
"active": {
|
|
12
|
+
"description": "Boolean value, set the Duplicate Rule to either active or inactive",
|
|
13
|
+
"required": True,
|
|
14
|
+
},
|
|
15
|
+
**MetadataSingleEntityTransformTask.task_options,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def _transform_entity(
|
|
19
|
+
self, metadata: MetadataElement, api_name: str
|
|
20
|
+
) -> Optional[MetadataElement]:
|
|
21
|
+
status = "true" if process_bool_arg(self.options["active"]) else "false"
|
|
22
|
+
metadata.find("isActive").text = status
|
|
23
|
+
|
|
24
|
+
return metadata
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from cumulusci.core.exceptions import TaskOptionsError
|
|
2
|
+
from cumulusci.core.utils import process_list_arg
|
|
3
|
+
from cumulusci.tasks.metadata_etl import MetadataSingleEntityTransformTask
|
|
4
|
+
from cumulusci.utils.xml.metadata_tree import MetadataElement
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AddFieldsToFieldSet(MetadataSingleEntityTransformTask):
|
|
8
|
+
entity = "CustomObject"
|
|
9
|
+
task_options = {
|
|
10
|
+
"field_set": {
|
|
11
|
+
"description": "Name of field set to affect, in Object__c.FieldSetName form.",
|
|
12
|
+
"required": True,
|
|
13
|
+
},
|
|
14
|
+
"fields": {
|
|
15
|
+
"description": "Array of field API names to add to the field set. "
|
|
16
|
+
"Can include related fields using AccountId.Name or Lookup__r.CustomField__c style syntax.",
|
|
17
|
+
"required": True,
|
|
18
|
+
},
|
|
19
|
+
**MetadataSingleEntityTransformTask.task_options,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def _init_options(self, kwargs):
|
|
23
|
+
self.task_config.options["api_names"] = "dummy"
|
|
24
|
+
super()._init_options(kwargs)
|
|
25
|
+
self.api_names = set(
|
|
26
|
+
[self._inject_namespace(self.options["field_set"].split(".")[0])]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if not self.options.get("fields"):
|
|
30
|
+
raise TaskOptionsError("The 'fields' option is required.")
|
|
31
|
+
|
|
32
|
+
self.fields = []
|
|
33
|
+
for field in process_list_arg(self.options["fields"]):
|
|
34
|
+
self.fields.append(self._inject_namespace(field))
|
|
35
|
+
|
|
36
|
+
self.field_set_name = self._inject_namespace(
|
|
37
|
+
self.options["field_set"].split(".")[1]
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def _transform_entity(self, metadata: MetadataElement, api_name: str):
|
|
41
|
+
# Locate the <fieldSets> entry for this field_set.
|
|
42
|
+
field_set = metadata.find("fieldSets", fullName=self.field_set_name)
|
|
43
|
+
if not field_set:
|
|
44
|
+
raise TaskOptionsError(
|
|
45
|
+
f"The field set {self.field_set_name} was not found."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
for field_name in self.fields:
|
|
49
|
+
self._add_field(field_set, field_name)
|
|
50
|
+
|
|
51
|
+
return metadata
|
|
52
|
+
|
|
53
|
+
def _add_field(self, field_set: MetadataElement, field_name: str):
|
|
54
|
+
|
|
55
|
+
# remove it from available fields if it's there
|
|
56
|
+
available_field = field_set.find("availableFields", field=field_name)
|
|
57
|
+
if available_field:
|
|
58
|
+
field_set.remove(available_field)
|
|
59
|
+
|
|
60
|
+
# check if it's already in displayedFields
|
|
61
|
+
displayed_field = field_set.find("displayedFields", field=field_name)
|
|
62
|
+
if displayed_field:
|
|
63
|
+
self.logger.info(
|
|
64
|
+
f"The field {field_name} is already in field set {self.field_set_name}."
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
new_field = field_set.append("displayedFields")
|
|
68
|
+
new_field.append("field", text=field_name)
|
|
69
|
+
new_field.append("isFieldManaged", text="false")
|
|
70
|
+
new_field.append("isRequired", text="false")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
|
|
3
|
+
from cumulusci.core.exceptions import TaskOptionsError
|
|
4
|
+
from cumulusci.core.utils import process_bool_arg, process_list_arg
|
|
5
|
+
from cumulusci.tasks.metadata_etl import MetadataSingleEntityTransformTask
|
|
6
|
+
from cumulusci.utils.xml.metadata_tree import MetadataElement
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SetFieldHelpText(MetadataSingleEntityTransformTask):
|
|
10
|
+
entity = "CustomObject"
|
|
11
|
+
task_options = {
|
|
12
|
+
"fields": {
|
|
13
|
+
"description": "List of object fields to affect, in Object__c.Field__c form.",
|
|
14
|
+
"required": True,
|
|
15
|
+
},
|
|
16
|
+
"overwrite": {
|
|
17
|
+
"description": "If set to True, overwrite any differing Help Text found on the field. "
|
|
18
|
+
"By default, Help Text is set only if it is blank."
|
|
19
|
+
},
|
|
20
|
+
**MetadataSingleEntityTransformTask.task_options,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def _init_options(self, kwargs):
|
|
24
|
+
self.task_config.options["api_names"] = "dummy"
|
|
25
|
+
super()._init_options(kwargs)
|
|
26
|
+
|
|
27
|
+
self.options["overwrite"] = process_bool_arg(
|
|
28
|
+
self.options.get("overwrite", False)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
not isinstance(self.options.get("fields"), list)
|
|
33
|
+
or len(self.options["fields"]) == 0
|
|
34
|
+
):
|
|
35
|
+
raise TaskOptionsError(
|
|
36
|
+
"Please populate the fields field with a list of dictionaries containing at minimum one entry with an 'api_name' and 'help_text' keys"
|
|
37
|
+
)
|
|
38
|
+
if not all(["api_name" in entry for entry in self.options["fields"]]):
|
|
39
|
+
raise TaskOptionsError(
|
|
40
|
+
"The 'api_name' key is required on all entry values."
|
|
41
|
+
)
|
|
42
|
+
if not all(["help_text" in entry for entry in self.options["fields"]]):
|
|
43
|
+
raise TaskOptionsError(
|
|
44
|
+
"The 'help_text' key is required on all entry values to declare what help text value to insert."
|
|
45
|
+
)
|
|
46
|
+
self.api_name_list = defaultdict(list)
|
|
47
|
+
for entry in process_list_arg(self.options["fields"]):
|
|
48
|
+
try:
|
|
49
|
+
obj, field = entry["api_name"].split(".")
|
|
50
|
+
|
|
51
|
+
self.api_name_list[self._inject_namespace(obj)].append(
|
|
52
|
+
(self._inject_namespace(field), entry["help_text"])
|
|
53
|
+
)
|
|
54
|
+
except ValueError:
|
|
55
|
+
raise TaskOptionsError(
|
|
56
|
+
f"api_name {entry} is not a valid Object.Field reference"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
self.api_names = set(self.api_name_list.keys())
|
|
60
|
+
|
|
61
|
+
def _transform_entity(self, metadata: MetadataElement, api_name: str):
|
|
62
|
+
for field, help_text in self.api_name_list[api_name]:
|
|
63
|
+
self._modify_help_text(metadata, api_name, field, help_text)
|
|
64
|
+
return metadata
|
|
65
|
+
|
|
66
|
+
def _modify_help_text(
|
|
67
|
+
self,
|
|
68
|
+
metadata: MetadataElement,
|
|
69
|
+
api_name: str,
|
|
70
|
+
custom_field: str,
|
|
71
|
+
help_text: str,
|
|
72
|
+
):
|
|
73
|
+
# Locate the <fields> entry for this field entry.
|
|
74
|
+
field = metadata.find("fields", fullName=custom_field)
|
|
75
|
+
if not field:
|
|
76
|
+
raise TaskOptionsError(
|
|
77
|
+
f"The field {api_name}.{custom_field} was not found."
|
|
78
|
+
)
|
|
79
|
+
try:
|
|
80
|
+
if (
|
|
81
|
+
field.inlineHelpText.text == ""
|
|
82
|
+
or field.inlineHelpText.text == help_text
|
|
83
|
+
or self.options["overwrite"]
|
|
84
|
+
):
|
|
85
|
+
field.inlineHelpText.text = help_text
|
|
86
|
+
else:
|
|
87
|
+
self.logger.warning(
|
|
88
|
+
f"Help text for field {api_name} has a different value. "
|
|
89
|
+
"Set the overwrite option to True to overwrite this field help text."
|
|
90
|
+
)
|
|
91
|
+
except AttributeError:
|
|
92
|
+
field.append("inlineHelpText", text=help_text)
|