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,76 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from cumulusci.core.versions import PackageType, PackageVersionNumber, VersionTypeEnum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestPackageVersionNumber:
|
|
7
|
+
def test_parse_format(self):
|
|
8
|
+
assert PackageVersionNumber.parse("1.2.3.4").format() == "1.2.3.4"
|
|
9
|
+
assert (
|
|
10
|
+
str(
|
|
11
|
+
PackageVersionNumber.parse(
|
|
12
|
+
"1.2.3.4", package_type=PackageType.FIRST_GEN
|
|
13
|
+
)
|
|
14
|
+
)
|
|
15
|
+
== "1.2.3 (Beta 4)"
|
|
16
|
+
)
|
|
17
|
+
assert PackageVersionNumber.parse("1.2.3 (Beta 4)").format() == "1.2.3 (Beta 4)"
|
|
18
|
+
assert PackageVersionNumber.parse("1.2.3 (beta 4)").format() == "1.2.3 (Beta 4)"
|
|
19
|
+
assert PackageVersionNumber.parse("1.2.3").format() == "1.2.3"
|
|
20
|
+
|
|
21
|
+
assert (
|
|
22
|
+
PackageVersionNumber.parse_tag(
|
|
23
|
+
"release/1.2.3", "release/", "beta/"
|
|
24
|
+
).format()
|
|
25
|
+
== "1.2.3"
|
|
26
|
+
)
|
|
27
|
+
assert (
|
|
28
|
+
PackageVersionNumber.parse_tag(
|
|
29
|
+
"beta/1.2.3-Beta_4", "release/", "beta/"
|
|
30
|
+
).format()
|
|
31
|
+
== "1.2.3 (Beta 4)"
|
|
32
|
+
)
|
|
33
|
+
assert (
|
|
34
|
+
PackageVersionNumber.parse_tag("beta/1.2.3.4", "release/", "beta/").format()
|
|
35
|
+
== "1.2.3.4"
|
|
36
|
+
)
|
|
37
|
+
assert (
|
|
38
|
+
PackageVersionNumber.parse_tag(
|
|
39
|
+
"beta/1.2.3.4", "release/", "beta/"
|
|
40
|
+
).format_tag("beta/")
|
|
41
|
+
== "beta/1.2.3.4"
|
|
42
|
+
)
|
|
43
|
+
assert (
|
|
44
|
+
PackageVersionNumber.parse_tag(
|
|
45
|
+
"beta/1.2.3-Beta_4", "release/", "beta/"
|
|
46
|
+
).format_tag("beta/")
|
|
47
|
+
== "beta/1.2.3-Beta_4"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def test_parse__invalid(self):
|
|
51
|
+
with pytest.raises(ValueError):
|
|
52
|
+
PackageVersionNumber.parse("asdf")
|
|
53
|
+
|
|
54
|
+
def test_increment(self):
|
|
55
|
+
assert (
|
|
56
|
+
PackageVersionNumber.parse("1.0.0.1")
|
|
57
|
+
.increment(VersionTypeEnum.major)
|
|
58
|
+
.format()
|
|
59
|
+
== "2.0.0.NEXT"
|
|
60
|
+
)
|
|
61
|
+
assert (
|
|
62
|
+
PackageVersionNumber.parse("1.0.0.1")
|
|
63
|
+
.increment(VersionTypeEnum.minor)
|
|
64
|
+
.format()
|
|
65
|
+
== "1.1.0.NEXT"
|
|
66
|
+
)
|
|
67
|
+
assert (
|
|
68
|
+
PackageVersionNumber.parse("1.0.0.1")
|
|
69
|
+
.increment(VersionTypeEnum.patch)
|
|
70
|
+
.format()
|
|
71
|
+
== "1.0.1.NEXT"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def test_increment__1gp(self):
|
|
75
|
+
with pytest.raises(ValueError):
|
|
76
|
+
PackageVersionNumber.parse("1.0 (Beta 4)").increment(VersionTypeEnum.major)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
project:
|
|
2
|
+
name: Untrusted-Repo-Parent
|
|
3
|
+
|
|
4
|
+
sources:
|
|
5
|
+
# trusted by the parent but not the root cumulusci
|
|
6
|
+
untrusted_child:
|
|
7
|
+
path: cumulusci/core/tests/untrusted_repo_child
|
|
8
|
+
allow_remote_code: True
|
|
9
|
+
|
|
10
|
+
tasks:
|
|
11
|
+
example_task:
|
|
12
|
+
description: An example project-level task that does nothing
|
|
13
|
+
class_path: tasks.untrusted_parent.ExampleTask
|
|
14
|
+
|
|
15
|
+
untrusted_child_task:
|
|
16
|
+
description: An example project-level task that does nothing
|
|
17
|
+
class_path: tasks.untrusted_child.ExampleTask
|
|
18
|
+
|
|
19
|
+
flows:
|
|
20
|
+
untrusted:
|
|
21
|
+
steps:
|
|
22
|
+
1:
|
|
23
|
+
task: example_task
|
|
24
|
+
|
|
25
|
+
2:
|
|
26
|
+
task: untrusted_child:example_task
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
""" Utilities for testing CumulusCI
|
|
2
|
+
|
|
3
|
+
MockLoggingHandler: a logging handler that we can assert"""
|
|
4
|
+
|
|
5
|
+
import collections
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import cumulusci
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MockLoggingHandler(logging.Handler):
|
|
13
|
+
"""Mock logging handler to check for expected logs.
|
|
14
|
+
|
|
15
|
+
Messages are available from an instance's ``messages`` dict, in order,
|
|
16
|
+
indexed by a lowercase log level string (e.g., 'debug', 'info', etc.).
|
|
17
|
+
|
|
18
|
+
TODO: Should be replaced by caplog at some point.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, *args, **kwargs):
|
|
22
|
+
self.messages = {
|
|
23
|
+
"debug": [],
|
|
24
|
+
"info": [],
|
|
25
|
+
"warning": [],
|
|
26
|
+
"error": [],
|
|
27
|
+
"critical": [],
|
|
28
|
+
}
|
|
29
|
+
super().__init__(*args, **kwargs)
|
|
30
|
+
|
|
31
|
+
def emit(self, record):
|
|
32
|
+
"Store a message from ``record`` in the instance's ``messages`` dict."
|
|
33
|
+
self.acquire()
|
|
34
|
+
try:
|
|
35
|
+
self.messages[record.levelname.lower()].append(record.getMessage())
|
|
36
|
+
finally:
|
|
37
|
+
self.release()
|
|
38
|
+
|
|
39
|
+
def reset(self):
|
|
40
|
+
"""Reset the handler in TestCase.setup_method() to clear the msg list"""
|
|
41
|
+
self.acquire()
|
|
42
|
+
try:
|
|
43
|
+
for message_list in list(self.messages.values()):
|
|
44
|
+
del message_list[:]
|
|
45
|
+
finally:
|
|
46
|
+
self.release()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class EnvironmentVarGuard(collections.abc.MutableMapping):
|
|
50
|
+
|
|
51
|
+
"""Class to help protect the environment variable properly. Can be used as
|
|
52
|
+
a context manager."""
|
|
53
|
+
|
|
54
|
+
def __init__(self):
|
|
55
|
+
self._environ = os.environ
|
|
56
|
+
self._changed = {}
|
|
57
|
+
|
|
58
|
+
def __getitem__(self, envvar):
|
|
59
|
+
return self._environ[envvar]
|
|
60
|
+
|
|
61
|
+
def __setitem__(self, envvar, value):
|
|
62
|
+
# Remember the initial value on the first access
|
|
63
|
+
if envvar not in self._changed:
|
|
64
|
+
self._changed[envvar] = self._environ.get(envvar)
|
|
65
|
+
self._environ[envvar] = value
|
|
66
|
+
|
|
67
|
+
def __delitem__(self, envvar):
|
|
68
|
+
# Remember the initial value on the first access
|
|
69
|
+
if envvar not in self._changed:
|
|
70
|
+
self._changed[envvar] = self._environ.get(envvar)
|
|
71
|
+
if envvar in self._environ:
|
|
72
|
+
del self._environ[envvar]
|
|
73
|
+
|
|
74
|
+
def keys(self):
|
|
75
|
+
return self._environ.keys()
|
|
76
|
+
|
|
77
|
+
def __iter__(self):
|
|
78
|
+
return iter(self._environ)
|
|
79
|
+
|
|
80
|
+
def __len__(self):
|
|
81
|
+
return len(self._environ)
|
|
82
|
+
|
|
83
|
+
def set(self, envvar, value):
|
|
84
|
+
self[envvar] = value
|
|
85
|
+
|
|
86
|
+
def unset(self, envvar):
|
|
87
|
+
del self[envvar]
|
|
88
|
+
|
|
89
|
+
def __enter__(self):
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def __exit__(self, *ignore_exc):
|
|
93
|
+
for (k, v) in self._changed.items():
|
|
94
|
+
if v is None:
|
|
95
|
+
if k in self._environ:
|
|
96
|
+
del self._environ[k]
|
|
97
|
+
else:
|
|
98
|
+
self._environ[k] = v
|
|
99
|
+
os.environ = self._environ
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MockLoggerMixin(object):
|
|
103
|
+
@classmethod
|
|
104
|
+
def setup_class(cls):
|
|
105
|
+
logger = logging.getLogger(cumulusci.core.tasks.__name__)
|
|
106
|
+
logger.setLevel(logging.DEBUG)
|
|
107
|
+
cls._task_log_handler = MockLoggingHandler(logging.DEBUG)
|
|
108
|
+
logger.addHandler(cls._task_log_handler)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class MockLookup:
|
|
112
|
+
def __init__(self, **kwargs):
|
|
113
|
+
self.dict = kwargs
|
|
114
|
+
|
|
115
|
+
def __call__(self, name, default=None):
|
|
116
|
+
return self.dict[name]
|
|
File without changes
|
cumulusci/core/utils.py
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
""" Utilities for CumulusCI Core"""
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
import glob
|
|
5
|
+
import json
|
|
6
|
+
import time
|
|
7
|
+
import typing as T
|
|
8
|
+
import warnings
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
from logging import getLogger
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import pytz
|
|
14
|
+
|
|
15
|
+
from cumulusci.core.debug import get_debug_mode
|
|
16
|
+
from cumulusci.core.exceptions import (
|
|
17
|
+
ConfigMergeError,
|
|
18
|
+
CumulusCIException,
|
|
19
|
+
TaskOptionsError,
|
|
20
|
+
)
|
|
21
|
+
from cumulusci.utils.options import parse_list_of_pairs_dict_arg
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def import_global(path: str):
|
|
25
|
+
"""Import a class from a string module class path"""
|
|
26
|
+
components = path.split(".")
|
|
27
|
+
module = components[:-1]
|
|
28
|
+
module = ".".join(module)
|
|
29
|
+
|
|
30
|
+
if get_debug_mode():
|
|
31
|
+
import sys
|
|
32
|
+
|
|
33
|
+
logger = getLogger(__file__)
|
|
34
|
+
logger.info(f"Importing {path}")
|
|
35
|
+
logger.info(f"Looking in sys.path {sys.path}")
|
|
36
|
+
if components[0] == "tasks":
|
|
37
|
+
logger.info(f"With tasks.__path__ {sys.modules['tasks'].__path__}")
|
|
38
|
+
|
|
39
|
+
mod = __import__(module, fromlist=[str(components[-1])])
|
|
40
|
+
return getattr(mod, str(components[-1]))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# For backwards-compatibility
|
|
44
|
+
import_class = import_global
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def parse_datetime(dt_str, format):
|
|
48
|
+
"""Create a timezone-aware datetime object from a datetime string."""
|
|
49
|
+
t = time.strptime(dt_str, format)
|
|
50
|
+
return datetime(t[0], t[1], t[2], t[3], t[4], t[5], t[6], pytz.UTC)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def process_bool_arg(arg: T.Union[int, str, None]):
|
|
54
|
+
"""Determine True/False from argument.
|
|
55
|
+
|
|
56
|
+
Similar to parts of the Salesforce API, there are a few true-ish and false-ish strings,
|
|
57
|
+
but "True" and "False" are the canonical ones.
|
|
58
|
+
|
|
59
|
+
None is accepted as "False" for backwards compatiblity reasons, but this usage is deprecated.
|
|
60
|
+
"""
|
|
61
|
+
if isinstance(arg, (int, bool)):
|
|
62
|
+
return bool(arg)
|
|
63
|
+
elif arg is None:
|
|
64
|
+
# backwards compatible behaviour that some tasks
|
|
65
|
+
# rely upon.
|
|
66
|
+
import traceback
|
|
67
|
+
|
|
68
|
+
warnings.warn("".join(traceback.format_stack(limit=4)), DeprecationWarning)
|
|
69
|
+
warnings.warn(
|
|
70
|
+
"Future versions of CCI will not accept 'None' as an argument to process_bool_arg",
|
|
71
|
+
DeprecationWarning,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return False
|
|
75
|
+
elif isinstance(arg, str):
|
|
76
|
+
# these are values that Salesforce's bulk loader accepts
|
|
77
|
+
# there doesn't seem to be any harm in acccepting the
|
|
78
|
+
# full list to be coordinated with a "Salesforce standard"
|
|
79
|
+
if arg.lower() in ["yes", "y", "true", "on", "1"]:
|
|
80
|
+
return True
|
|
81
|
+
elif arg.lower() in ["no", "n", "false", "off", "0"]:
|
|
82
|
+
return False
|
|
83
|
+
raise TypeError(f"Cannot interpret as boolean: `{arg}`")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def process_glob_list_arg(arg):
|
|
87
|
+
"""Convert a list of glob patterns or filenames into a list of files
|
|
88
|
+
The initial list can take the form of a comma-separated string or
|
|
89
|
+
a proper list. Order is preserved, but duplicates will be removed.
|
|
90
|
+
|
|
91
|
+
Note: this function processes glob patterns, but doesn't validate
|
|
92
|
+
that the files actually exist. For example, if the pattern is
|
|
93
|
+
'foo.bar' and there is no file named 'foo.bar', the literal string
|
|
94
|
+
'foo.bar' will be included in the returned files.
|
|
95
|
+
|
|
96
|
+
Similarly, if the pattern is '*.baz' and it doesn't match any files,
|
|
97
|
+
the literal string '*.baz' will be returned.
|
|
98
|
+
"""
|
|
99
|
+
initial_list = process_list_arg(arg)
|
|
100
|
+
|
|
101
|
+
if not arg:
|
|
102
|
+
return []
|
|
103
|
+
|
|
104
|
+
files = []
|
|
105
|
+
for path in initial_list:
|
|
106
|
+
more_files = glob.glob(path, recursive=True)
|
|
107
|
+
if len(more_files):
|
|
108
|
+
files += sorted(more_files)
|
|
109
|
+
else:
|
|
110
|
+
files.append(path)
|
|
111
|
+
# In python 3.6+ dict is ordered, so we'll use it to weed
|
|
112
|
+
# out duplicates. We can't use a set because sets aren't ordered.
|
|
113
|
+
return list(dict.fromkeys(files))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def process_list_arg(arg):
|
|
117
|
+
"""Parse a string into a list separated by commas with whitespace stripped"""
|
|
118
|
+
if isinstance(arg, Path):
|
|
119
|
+
arg = str(arg)
|
|
120
|
+
|
|
121
|
+
if isinstance(arg, list):
|
|
122
|
+
return arg
|
|
123
|
+
elif isinstance(arg, str):
|
|
124
|
+
args = []
|
|
125
|
+
for part in arg.split(","):
|
|
126
|
+
args.append(part.strip())
|
|
127
|
+
return args
|
|
128
|
+
elif arg is None:
|
|
129
|
+
# backwards compatible behaviour.
|
|
130
|
+
return None
|
|
131
|
+
else:
|
|
132
|
+
getLogger(__file__).warn(
|
|
133
|
+
f"Unknown option type `{type(arg)}` for value `{arg}`."
|
|
134
|
+
"This will be an error in a future version of CCI."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def process_list_of_pairs_dict_arg(arg):
|
|
139
|
+
"""Process an arg in the format "aa:bb,cc:dd" """
|
|
140
|
+
try:
|
|
141
|
+
return parse_list_of_pairs_dict_arg(arg)
|
|
142
|
+
except TypeError as e:
|
|
143
|
+
raise TaskOptionsError(e) from e
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def decode_to_unicode(content):
|
|
147
|
+
"""decode ISO-8859-1 to unicode, when using sf api"""
|
|
148
|
+
if content and not isinstance(content, str):
|
|
149
|
+
try:
|
|
150
|
+
# Try to decode ISO-8859-1 to unicode
|
|
151
|
+
return content.decode("ISO-8859-1")
|
|
152
|
+
except UnicodeEncodeError:
|
|
153
|
+
# Assume content is unicode already
|
|
154
|
+
return content
|
|
155
|
+
return content
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def merge_config(configs):
|
|
159
|
+
"""
|
|
160
|
+
First remove any flow steps that are being overridden so that there are no conflicts
|
|
161
|
+
or different step types after merging. Then recursively deep-merge the configs into
|
|
162
|
+
one another (highest priority comes first)
|
|
163
|
+
"""
|
|
164
|
+
config_copies = {name: copy.deepcopy(config) for name, config in configs.items()}
|
|
165
|
+
cleaned_configs = cleanup_flow_step_override_conflicts(config_copies)
|
|
166
|
+
|
|
167
|
+
new_config = {}
|
|
168
|
+
for name, config in cleaned_configs.items():
|
|
169
|
+
new_config = dictmerge(new_config, config, name)
|
|
170
|
+
|
|
171
|
+
return new_config
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def cleanup_flow_step_override_conflicts(configs: T.List[dict]) -> T.List[dict]:
|
|
175
|
+
"""
|
|
176
|
+
If a flow step is been overridden with a step of a different type (i.e. tas, flow),
|
|
177
|
+
then we need to set the step that is _lower_ in precedence order to an empty dict ({}).
|
|
178
|
+
If we don't, then we will end up with both "flow" and "task" listed in the step_config which
|
|
179
|
+
leads to an error when CumulusCI attempts to run that step in the flow.
|
|
180
|
+
|
|
181
|
+
We need to also account for scenarios where a single flow step
|
|
182
|
+
is being overriden more than once.
|
|
183
|
+
|
|
184
|
+
Example:
|
|
185
|
+
A flow step in the universal config is being overridden somewhere
|
|
186
|
+
in the project_config, which is being overridden by additional_yaml.
|
|
187
|
+
|
|
188
|
+
The while loop below is how we account for these scenarios.
|
|
189
|
+
"""
|
|
190
|
+
config_precedence_order = [
|
|
191
|
+
"additional_yaml",
|
|
192
|
+
"project_local_config",
|
|
193
|
+
"project_config",
|
|
194
|
+
"plugins_config",
|
|
195
|
+
"global_config",
|
|
196
|
+
"universal_config",
|
|
197
|
+
]
|
|
198
|
+
while len(config_precedence_order) > 1:
|
|
199
|
+
overriding_config = config_precedence_order[0]
|
|
200
|
+
config_precedence_order = config_precedence_order[1:]
|
|
201
|
+
for config_to_override in config_precedence_order:
|
|
202
|
+
if configs_present_and_not_empty(
|
|
203
|
+
[config_to_override, overriding_config], configs
|
|
204
|
+
):
|
|
205
|
+
remove_overridden_flow_steps_in_config(
|
|
206
|
+
configs[config_to_override], configs[overriding_config]
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return configs
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def configs_present_and_not_empty(
|
|
213
|
+
configs_to_check: T.List[dict], configs: dict
|
|
214
|
+
) -> bool:
|
|
215
|
+
return all(c in configs and c != {} for c in configs_to_check)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def remove_overridden_flow_steps_in_config(
|
|
219
|
+
config_to_override: dict, overriding_config: dict
|
|
220
|
+
):
|
|
221
|
+
"""If any steps of flows from the config_to_override are being overridden in overriding_config,
|
|
222
|
+
then we need to set those steps in the config_to_override to an empty dict so that we don't have
|
|
223
|
+
both a "task" and a "flow" listed in a flow step after merging the configs with `dictmerge()`.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
if "flows" not in config_to_override or "flows" not in overriding_config:
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
for flow, flow_config in overriding_config["flows"].items():
|
|
230
|
+
for (
|
|
231
|
+
step_num,
|
|
232
|
+
overriding_step_config,
|
|
233
|
+
) in flow_config.get("steps", {}).items():
|
|
234
|
+
cleanup_old_flow_step_replace_syntax(overriding_step_config)
|
|
235
|
+
both_configs_have_flow_and_step = config_has_flow_and_step_num(
|
|
236
|
+
config_to_override, flow, step_num
|
|
237
|
+
)
|
|
238
|
+
if both_configs_have_flow_and_step:
|
|
239
|
+
step_config_to_override = config_to_override["flows"][flow]["steps"][
|
|
240
|
+
step_num
|
|
241
|
+
]
|
|
242
|
+
steps_same_type = steps_are_same_type(
|
|
243
|
+
overriding_step_config, step_config_to_override
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
link_missing_task_or_flow(
|
|
247
|
+
step_config_to_override, overriding_step_config
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if not steps_same_type:
|
|
251
|
+
config_to_override["flows"][flow]["steps"][step_num] = {}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def link_missing_task_or_flow(
|
|
255
|
+
step_config_to_override: dict, overriding_step_config: dict
|
|
256
|
+
):
|
|
257
|
+
"""If the incoming override does not have task/flow defined then inherit from
|
|
258
|
+
the flow step that we're overridding."""
|
|
259
|
+
if "flow" not in overriding_step_config and "task" not in overriding_step_config:
|
|
260
|
+
if "task" in step_config_to_override:
|
|
261
|
+
overriding_step_config["task"] = step_config_to_override["task"]
|
|
262
|
+
elif "flow" in step_config_to_override:
|
|
263
|
+
overriding_step_config["flow"] = step_config_to_override["flow"]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def cleanup_old_flow_step_replace_syntax(step_config: dict):
|
|
267
|
+
"""When replacing flow steps with a step of a different type, the old syntax
|
|
268
|
+
had users declare the original step type as 'None' along with the new step type.
|
|
269
|
+
If both are present, we want to remove the one that has a value of 'None'."""
|
|
270
|
+
if all(s_type in step_config for s_type in ("task", "flow")):
|
|
271
|
+
if step_config["flow"] == "None" and step_config["task"] == "None":
|
|
272
|
+
raise CumulusCIException(
|
|
273
|
+
"Cannot have both step types declared with a value of 'None'."
|
|
274
|
+
"For information on replacing a flow step see: https://cumulusci.readthedocs.io/en/latest/config.html#replace-a-flow-step"
|
|
275
|
+
)
|
|
276
|
+
elif step_config["flow"] == "None":
|
|
277
|
+
del step_config["flow"]
|
|
278
|
+
else:
|
|
279
|
+
del step_config["task"]
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def config_has_flow_and_step_num(config: dict, flow_name: str, step_num: int) -> bool:
|
|
283
|
+
return (
|
|
284
|
+
flow_name in config["flows"] and step_num in config["flows"][flow_name]["steps"]
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def steps_are_same_type(step_one_config: dict, step_two_config: dict) -> bool:
|
|
289
|
+
"""If both steps are of the same type returns True, else False."""
|
|
290
|
+
config_one_type = "task" if "task" in step_one_config else "flow"
|
|
291
|
+
config_two_type = "task" if "task" in step_two_config else "flow"
|
|
292
|
+
|
|
293
|
+
return config_one_type == config_two_type
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def dictmerge(a, b, name=None):
|
|
297
|
+
"""Deeply merge two ``dict``s that consist of lists, dicts, and scalars.
|
|
298
|
+
This function (recursively) merges ``b`` INTO ``a``, does not copy any values, and returns ``a``.
|
|
299
|
+
|
|
300
|
+
based on https://stackoverflow.com/a/15836901/5042831
|
|
301
|
+
NOTE: tuples and arbitrary objects are NOT handled and will raise TypeError"""
|
|
302
|
+
|
|
303
|
+
key = None
|
|
304
|
+
|
|
305
|
+
if b is None:
|
|
306
|
+
return a
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
if a is None or isinstance(a, (bytes, int, str, float)):
|
|
310
|
+
# first run, or if ``a``` is a scalar
|
|
311
|
+
a = b
|
|
312
|
+
elif isinstance(a, list):
|
|
313
|
+
# lists can be only appended
|
|
314
|
+
if isinstance(b, list):
|
|
315
|
+
# merge lists
|
|
316
|
+
a.extend(b)
|
|
317
|
+
else:
|
|
318
|
+
# append to list
|
|
319
|
+
a.append(b)
|
|
320
|
+
elif isinstance(a, dict):
|
|
321
|
+
# dicts must be merged
|
|
322
|
+
if isinstance(b, dict):
|
|
323
|
+
for key in b:
|
|
324
|
+
if key in a:
|
|
325
|
+
a[key] = dictmerge(a[key], b[key], name)
|
|
326
|
+
else:
|
|
327
|
+
a[key] = copy.deepcopy(b[key])
|
|
328
|
+
else:
|
|
329
|
+
raise TypeError(
|
|
330
|
+
f'Cannot merge non-dict of type "{type(b)}" into dict "{a}"'
|
|
331
|
+
)
|
|
332
|
+
else:
|
|
333
|
+
raise TypeError(
|
|
334
|
+
f'dictmerge does not supporting merging "{type(b)}" into "{type(a)}"'
|
|
335
|
+
)
|
|
336
|
+
except TypeError as e:
|
|
337
|
+
raise ConfigMergeError(
|
|
338
|
+
f'TypeError "{e}" in key "{key}" when merging "{type(b)}" into "{type(a)}"',
|
|
339
|
+
config_name=name,
|
|
340
|
+
)
|
|
341
|
+
return a
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def format_duration(duration: timedelta):
|
|
345
|
+
hours, remainder = divmod(duration.total_seconds(), 3600)
|
|
346
|
+
minutes, seconds = divmod(remainder, 60)
|
|
347
|
+
hours = f"{int(hours)}h:" if hours > 0 else ""
|
|
348
|
+
minutes = f"{int(minutes)}m:" if (hours or minutes) else ""
|
|
349
|
+
seconds = f"{str(int(seconds))}s"
|
|
350
|
+
return hours + minutes + seconds
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def make_jsonable(x):
|
|
354
|
+
"""Attempts to json serialize an object.
|
|
355
|
+
If it is not serializable,
|
|
356
|
+
returns a list if it's a set
|
|
357
|
+
or a string representation for anything else.
|
|
358
|
+
"""
|
|
359
|
+
if isinstance(x, set):
|
|
360
|
+
return list(x)
|
|
361
|
+
try:
|
|
362
|
+
json.dumps(x)
|
|
363
|
+
return x
|
|
364
|
+
except (TypeError, OverflowError):
|
|
365
|
+
return str(x)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def determine_managed_mode(options, project_config, org_config):
|
|
369
|
+
"""Determine the managed mode based on options, project config, and org config.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
options: Dict of task options that may contain 'managed' or 'unmanaged' flags
|
|
373
|
+
project_config: Project configuration object with package info
|
|
374
|
+
org_config: Org configuration object with installed packages and namespace info
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
bool: True if in managed mode, False if in unmanaged mode
|
|
378
|
+
|
|
379
|
+
Note: The changes allows multiple package development under same namespace.
|
|
380
|
+
"""
|
|
381
|
+
if "managed" in options:
|
|
382
|
+
return process_bool_arg(options["managed"])
|
|
383
|
+
|
|
384
|
+
# Get package and namespace information
|
|
385
|
+
package_name = getattr(project_config, "project__package__name", None)
|
|
386
|
+
namespace = getattr(
|
|
387
|
+
project_config, "project__package__namespace", None
|
|
388
|
+
) or options.get("namespace", None)
|
|
389
|
+
installed_packages = getattr(org_config, "installed_packages", {})
|
|
390
|
+
|
|
391
|
+
if "unmanaged" in options:
|
|
392
|
+
# Explicit unmanaged flag always takes precedence
|
|
393
|
+
return not process_bool_arg(options.get("unmanaged", True))
|
|
394
|
+
elif package_name and any(package_name in key for key in installed_packages.keys()):
|
|
395
|
+
# If this specific package is installed (or there is any installed package with a Name that contains package_name), we're in managed context
|
|
396
|
+
return True
|
|
397
|
+
elif bool(namespace) and namespace == getattr(org_config, "namespace", None):
|
|
398
|
+
# We're in a namespaced org (packaging org) developing unmanaged code
|
|
399
|
+
return False
|
|
400
|
+
else:
|
|
401
|
+
# Fall back to checking namespace in installed packages
|
|
402
|
+
return bool(namespace) and namespace in installed_packages
|