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,689 @@
|
|
|
1
|
+
import http.client
|
|
2
|
+
from datetime import UTC, datetime
|
|
3
|
+
from io import BytesIO, StringIO
|
|
4
|
+
from re import Pattern
|
|
5
|
+
from string import Template
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
|
|
8
|
+
from github3 import GitHub, GitHubError
|
|
9
|
+
from github3.exceptions import NotFoundError, UnprocessableEntity
|
|
10
|
+
from github3.git import Reference, Tag
|
|
11
|
+
from github3.issues.issue import ShortIssue
|
|
12
|
+
from github3.issues.label import ShortLabel
|
|
13
|
+
from github3.pulls import PullRequest, ShortPullRequest
|
|
14
|
+
from github3.repos.branch import Branch
|
|
15
|
+
from github3.repos.commit import RepoCommit
|
|
16
|
+
from github3.repos.release import Release
|
|
17
|
+
from github3.repos.repo import Repository
|
|
18
|
+
from github3.session import GitHubSession
|
|
19
|
+
from requests.models import Response
|
|
20
|
+
|
|
21
|
+
from cumulusci.core.config.project_config import BaseProjectConfig
|
|
22
|
+
from cumulusci.core.exceptions import GithubApiNotFoundError
|
|
23
|
+
from cumulusci.core.github import catch_common_github_auth_errors
|
|
24
|
+
from cumulusci.utils.git import parse_repo_url
|
|
25
|
+
from cumulusci.utils.http.requests_utils import safe_json_from_response
|
|
26
|
+
from cumulusci.vcs.models import (
|
|
27
|
+
AbstractBranch,
|
|
28
|
+
AbstractComparison,
|
|
29
|
+
AbstractGitTag,
|
|
30
|
+
AbstractPullRequest,
|
|
31
|
+
AbstractRef,
|
|
32
|
+
AbstractRelease,
|
|
33
|
+
AbstractRepo,
|
|
34
|
+
AbstractRepoCommit,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class GitHubRef(AbstractRef):
|
|
39
|
+
ref: Reference
|
|
40
|
+
sha: str
|
|
41
|
+
type: str
|
|
42
|
+
|
|
43
|
+
def __init__(self, ref: Reference, **kwargs) -> None:
|
|
44
|
+
super().__init__(ref, **kwargs)
|
|
45
|
+
self.sha = ref.object.sha
|
|
46
|
+
self.type = ref.object.type
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class GitHubTag(AbstractGitTag):
|
|
50
|
+
tag: Tag
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def message(self) -> str:
|
|
54
|
+
"""Gets the message of the tag."""
|
|
55
|
+
return self.tag.message if self.tag else ""
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def sha(self) -> str:
|
|
59
|
+
"""Gets the SHA of the tag."""
|
|
60
|
+
return self.tag.object.sha or self.tag.sha if self.tag else ""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class GitHubComparison(AbstractComparison):
|
|
64
|
+
@catch_common_github_auth_errors
|
|
65
|
+
def get_comparison(self) -> None:
|
|
66
|
+
"""Gets the comparison object for the current base and head."""
|
|
67
|
+
self.comparison = self.repo.repo.compare_commits(self.base, self.head)
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def files(self) -> list:
|
|
71
|
+
return (
|
|
72
|
+
self.comparison.files if self.comparison and self.comparison.files else []
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def behind_by(self) -> int:
|
|
77
|
+
"""Returns the number of commits the head is behind the base."""
|
|
78
|
+
return (
|
|
79
|
+
self.comparison.behind_by
|
|
80
|
+
if self.comparison and self.comparison.behind_by
|
|
81
|
+
else 0
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def compare(cls, repo: AbstractRepo, base: str, head: str) -> "GitHubComparison":
|
|
86
|
+
comparison = GitHubComparison(repo, base, head)
|
|
87
|
+
comparison.get_comparison()
|
|
88
|
+
return comparison
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class GitHubCommit(AbstractRepoCommit):
|
|
92
|
+
"""GitHub comparison object for comparing commits."""
|
|
93
|
+
|
|
94
|
+
commit: RepoCommit
|
|
95
|
+
_sha: str
|
|
96
|
+
|
|
97
|
+
def __init__(self, **kwargs) -> None:
|
|
98
|
+
super().__init__(**kwargs)
|
|
99
|
+
self._sha = self.commit.sha if self.commit else kwargs.get("sha", "")
|
|
100
|
+
|
|
101
|
+
def get_statuses(self, context: str, regex_match: Pattern[str]) -> Optional[str]:
|
|
102
|
+
for status in self.commit.status().statuses:
|
|
103
|
+
if status.state == "success" and status.context == context:
|
|
104
|
+
match = regex_match.search(status.description)
|
|
105
|
+
if match:
|
|
106
|
+
return match.group(1)
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def parents(self) -> list["GitHubCommit"]:
|
|
111
|
+
return [GitHubCommit(**c) for c in self.commit.parents]
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def sha(self) -> str:
|
|
115
|
+
"""Gets the SHA of the commit."""
|
|
116
|
+
return self._sha
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class GitHubBranch(AbstractBranch):
|
|
120
|
+
repo: "GitHubRepository"
|
|
121
|
+
branch: Optional[Branch]
|
|
122
|
+
|
|
123
|
+
def __init__(self, repo: "GitHubRepository", branch_name: str, **kwargs) -> None:
|
|
124
|
+
super().__init__(repo, branch_name, **kwargs)
|
|
125
|
+
|
|
126
|
+
def get_branch(self) -> None:
|
|
127
|
+
try:
|
|
128
|
+
self.branch = self.repo.repo.branch(self.name)
|
|
129
|
+
except NotFoundError:
|
|
130
|
+
message = f"Branch {self.name} not found"
|
|
131
|
+
raise GithubApiNotFoundError(message)
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
@catch_common_github_auth_errors
|
|
136
|
+
def branches(cls, git_repo: AbstractRepo) -> list["GitHubBranch"]:
|
|
137
|
+
"""Fetches all branches from the given repository"""
|
|
138
|
+
try:
|
|
139
|
+
branches = git_repo.repo.branches()
|
|
140
|
+
return [
|
|
141
|
+
GitHubBranch(git_repo, branch.name, branch=branch)
|
|
142
|
+
for branch in branches
|
|
143
|
+
]
|
|
144
|
+
except NotFoundError:
|
|
145
|
+
raise GithubApiNotFoundError("Could not find branches on GitHub")
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def commit(self) -> Optional[GitHubCommit]:
|
|
149
|
+
"""Gets the branch commit for the current branch."""
|
|
150
|
+
if self.branch is None:
|
|
151
|
+
self.get_branch()
|
|
152
|
+
|
|
153
|
+
return GitHubCommit(commit=self.branch.commit) if self.branch else None
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class GitHubRelease(AbstractRelease):
|
|
157
|
+
"""GitHub release object for creating and managing releases."""
|
|
158
|
+
|
|
159
|
+
release: Release
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def tag_name(self) -> str:
|
|
163
|
+
"""Gets the tag name of the release."""
|
|
164
|
+
return self.release.tag_name if self.release else ""
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def body(self) -> Union[str, None]:
|
|
168
|
+
"""Gets the body of the release."""
|
|
169
|
+
return self.release.body if self.release else None
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def prerelease(self) -> bool:
|
|
173
|
+
"""Checks if the release is a pre-release."""
|
|
174
|
+
return self.release.prerelease if self.release else False
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def name(self) -> str:
|
|
178
|
+
"""Gets the name of the release."""
|
|
179
|
+
return self.release.name if self.release else ""
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def html_url(self) -> str:
|
|
183
|
+
"""Gets the HTML URL of the release."""
|
|
184
|
+
return self.release.html_url if self.release else ""
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def created_at(self) -> datetime:
|
|
188
|
+
"""Gets the creation date of the release."""
|
|
189
|
+
return self.release.created_at if self.release else None
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def draft(self) -> bool:
|
|
193
|
+
"""Checks if the release is a draft."""
|
|
194
|
+
return self.release.draft if self.release else False
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def tag_ref_name(self) -> str:
|
|
198
|
+
"""Gets the tag reference name of the release."""
|
|
199
|
+
return "tags/" + self.tag_name
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class GitHubPullRequest(AbstractPullRequest):
|
|
203
|
+
"""GitHub pull request object for creating and managing pull requests."""
|
|
204
|
+
|
|
205
|
+
@classmethod
|
|
206
|
+
def pull_requests(
|
|
207
|
+
cls,
|
|
208
|
+
git_repo: AbstractRepo,
|
|
209
|
+
state=None,
|
|
210
|
+
head=None,
|
|
211
|
+
base=None,
|
|
212
|
+
sort="created",
|
|
213
|
+
direction="desc",
|
|
214
|
+
number=-1,
|
|
215
|
+
etag=None,
|
|
216
|
+
) -> list["GitHubPullRequest"]:
|
|
217
|
+
"""Fetches all pull requests from the repository."""
|
|
218
|
+
try:
|
|
219
|
+
pull_requests = git_repo.repo.pull_requests(
|
|
220
|
+
state=state,
|
|
221
|
+
head=head,
|
|
222
|
+
base=base,
|
|
223
|
+
sort=sort,
|
|
224
|
+
direction=direction,
|
|
225
|
+
number=number,
|
|
226
|
+
etag=etag,
|
|
227
|
+
)
|
|
228
|
+
return [
|
|
229
|
+
GitHubPullRequest(repo=git_repo, pull_request=pull_request)
|
|
230
|
+
for pull_request in pull_requests
|
|
231
|
+
]
|
|
232
|
+
except NotFoundError:
|
|
233
|
+
raise GithubApiNotFoundError("Could not find pull requests on GitHub")
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def create_pull(
|
|
237
|
+
cls,
|
|
238
|
+
git_repo: AbstractRepo,
|
|
239
|
+
title: str,
|
|
240
|
+
base: str,
|
|
241
|
+
head: str,
|
|
242
|
+
body: str = None,
|
|
243
|
+
maintainer_can_modify: bool = None,
|
|
244
|
+
) -> "GitHubPullRequest":
|
|
245
|
+
"""Creates a pull request on the given repository."""
|
|
246
|
+
try:
|
|
247
|
+
pull_request: PullRequest = git_repo.repo.create_pull(
|
|
248
|
+
title,
|
|
249
|
+
base,
|
|
250
|
+
head,
|
|
251
|
+
body=body,
|
|
252
|
+
maintainer_can_modify=maintainer_can_modify,
|
|
253
|
+
)
|
|
254
|
+
return GitHubPullRequest(repo=git_repo, pull_request=pull_request)
|
|
255
|
+
except NotFoundError:
|
|
256
|
+
raise GithubApiNotFoundError("Could not create pull request on GitHub")
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def number(self) -> int:
|
|
260
|
+
"""Gets the pull request number."""
|
|
261
|
+
return self.pull_request.number if self.pull_request else None
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def title(self) -> str:
|
|
265
|
+
"""Gets the pull request title."""
|
|
266
|
+
return self.pull_request.title if self.pull_request else ""
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def base_ref(self) -> str:
|
|
270
|
+
"""Gets the base reference of the pull request."""
|
|
271
|
+
return self.pull_request.base.ref if self.pull_request else ""
|
|
272
|
+
|
|
273
|
+
@property
|
|
274
|
+
def head_ref(self) -> str:
|
|
275
|
+
"""Gets the head reference of the pull request."""
|
|
276
|
+
return self.pull_request.head.ref if self.pull_request else ""
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def merged_at(self) -> datetime:
|
|
280
|
+
"""Gets the merged date of the short pull request."""
|
|
281
|
+
return self.pull_request.merged_at if self.pull_request else None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class GitHubRepository(AbstractRepo):
|
|
285
|
+
|
|
286
|
+
github: GitHub
|
|
287
|
+
project_config: BaseProjectConfig
|
|
288
|
+
repo: Repository
|
|
289
|
+
|
|
290
|
+
def __init__(
|
|
291
|
+
self, github: GitHub, project_config: BaseProjectConfig, **kwargs
|
|
292
|
+
) -> None:
|
|
293
|
+
super().__init__(**kwargs)
|
|
294
|
+
self.github: GitHub = github
|
|
295
|
+
self.project_config: BaseProjectConfig = project_config
|
|
296
|
+
self.service_type = kwargs.get("service_type") or "github"
|
|
297
|
+
self._service_config = kwargs.get("service_config")
|
|
298
|
+
|
|
299
|
+
self._init_repo()
|
|
300
|
+
|
|
301
|
+
def _init_repo(self) -> None:
|
|
302
|
+
"""Initializes the repository object."""
|
|
303
|
+
if self.repo_url is not None:
|
|
304
|
+
self.repo_owner, self.repo_name, host = parse_repo_url(self.repo_url)
|
|
305
|
+
|
|
306
|
+
self.repo_owner = (
|
|
307
|
+
self.repo_owner
|
|
308
|
+
or self.options.get("repo_owner")
|
|
309
|
+
or self.project_config.repo_owner
|
|
310
|
+
)
|
|
311
|
+
self.repo_name = (
|
|
312
|
+
self.repo_name
|
|
313
|
+
or self.options.get("repo_name")
|
|
314
|
+
or self.project_config.repo_name
|
|
315
|
+
)
|
|
316
|
+
self.repo: Repository = self.github.repository(self.repo_owner, self.repo_name)
|
|
317
|
+
self.repo_url = self.repo_url or self.repo.html_url
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def service_config(self):
|
|
321
|
+
if not self._service_config:
|
|
322
|
+
self._service_config = self.project_config.keychain.get_service(
|
|
323
|
+
self.service_type
|
|
324
|
+
)
|
|
325
|
+
return self._service_config
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def owner_login(self) -> str:
|
|
329
|
+
"""Returns the owner login of the repository."""
|
|
330
|
+
return self.repo.owner.login if self.repo else ""
|
|
331
|
+
|
|
332
|
+
def get_ref(self, ref_sha: str) -> GitHubRef:
|
|
333
|
+
"""Gets a Reference object for the tag with the given SHA"""
|
|
334
|
+
try:
|
|
335
|
+
ref = self.repo.ref(ref_sha)
|
|
336
|
+
return GitHubRef(ref=ref)
|
|
337
|
+
except NotFoundError:
|
|
338
|
+
raise GithubApiNotFoundError(
|
|
339
|
+
f"Could not find reference for '{ref_sha}' on GitHub"
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
def get_ref_for_tag(self, tag_name: str) -> GitHubRef:
|
|
343
|
+
"""Gets a Reference object for the tag with the given name"""
|
|
344
|
+
try:
|
|
345
|
+
ref = self.repo.ref(f"tags/{tag_name}")
|
|
346
|
+
return GitHubRef(ref=ref)
|
|
347
|
+
except NotFoundError:
|
|
348
|
+
raise GithubApiNotFoundError(
|
|
349
|
+
f"Could not find reference for 'tags/{tag_name}' on GitHub"
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
def get_tag_by_ref(self, ref: GitHubRef, tag_name: str = None) -> GitHubTag:
|
|
353
|
+
"""Fetches a tag by reference, name from the given repository"""
|
|
354
|
+
try:
|
|
355
|
+
tag = self.repo.tag(ref.sha)
|
|
356
|
+
return GitHubTag(tag=tag)
|
|
357
|
+
except NotFoundError:
|
|
358
|
+
msg = f"Could not find tag '{tag_name}' with SHA {ref.sha} on GitHub"
|
|
359
|
+
if ref.type != "tag":
|
|
360
|
+
msg += f"\n{tag_name} is not an annotated tag."
|
|
361
|
+
raise GithubApiNotFoundError(msg)
|
|
362
|
+
|
|
363
|
+
@catch_common_github_auth_errors
|
|
364
|
+
def create_tag(
|
|
365
|
+
self,
|
|
366
|
+
tag_name: str,
|
|
367
|
+
message: str,
|
|
368
|
+
sha: str,
|
|
369
|
+
obj_type: str,
|
|
370
|
+
tagger: dict = {},
|
|
371
|
+
lightweight: Optional[bool] = False,
|
|
372
|
+
) -> GitHubTag:
|
|
373
|
+
# Create a tag on the given repository
|
|
374
|
+
tagger["name"] = tagger.get("name", self.service_config.username)
|
|
375
|
+
tagger["email"] = tagger.get("email", self.service_config.email)
|
|
376
|
+
tagger["date"] = tagger.get(
|
|
377
|
+
"date", f"{datetime.now(UTC).replace(tzinfo=None).isoformat()}Z"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
tag = self.repo.create_tag(
|
|
381
|
+
tag=tag_name,
|
|
382
|
+
message=message,
|
|
383
|
+
sha=sha,
|
|
384
|
+
obj_type=obj_type,
|
|
385
|
+
tagger=tagger,
|
|
386
|
+
lightweight=lightweight,
|
|
387
|
+
)
|
|
388
|
+
return GitHubTag(tag=tag)
|
|
389
|
+
|
|
390
|
+
def branch(self, branch_name) -> GitHubBranch:
|
|
391
|
+
# Fetches a branch from the given repository
|
|
392
|
+
return GitHubBranch(self, branch_name)
|
|
393
|
+
|
|
394
|
+
def branches(self) -> list[GitHubBranch]:
|
|
395
|
+
# Fetches all branches from the given repository
|
|
396
|
+
return GitHubBranch.branches(self)
|
|
397
|
+
|
|
398
|
+
def compare_commits(
|
|
399
|
+
self, branch_name: str, commit: str, source: str
|
|
400
|
+
) -> GitHubComparison:
|
|
401
|
+
# Compares the given branch with the given commit
|
|
402
|
+
return GitHubComparison.compare(self, branch_name, commit)
|
|
403
|
+
|
|
404
|
+
def merge(
|
|
405
|
+
self, base: str, head: str, source: str, message: str = ""
|
|
406
|
+
) -> Union[GitHubCommit, None]:
|
|
407
|
+
# Merges the given base and head with the specified message
|
|
408
|
+
try:
|
|
409
|
+
commit = self.repo.merge(base, head, message)
|
|
410
|
+
git_commit = GitHubCommit(commit=commit)
|
|
411
|
+
return git_commit
|
|
412
|
+
except GitHubError as e:
|
|
413
|
+
if e.code != http.client.CONFLICT:
|
|
414
|
+
raise
|
|
415
|
+
except NotFoundError:
|
|
416
|
+
raise GithubApiNotFoundError(
|
|
417
|
+
f"Could not find base {base} or head {head} for merge on GitHub"
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
def pull_requests(
|
|
421
|
+
self,
|
|
422
|
+
state: str = None,
|
|
423
|
+
head: str = None,
|
|
424
|
+
base: str = None,
|
|
425
|
+
sort: str = "created",
|
|
426
|
+
direction: str = "desc",
|
|
427
|
+
number: int = -1,
|
|
428
|
+
etag: str = None,
|
|
429
|
+
) -> list[GitHubPullRequest]:
|
|
430
|
+
"""Fetches all pull requests from the given repository"""
|
|
431
|
+
return GitHubPullRequest.pull_requests(
|
|
432
|
+
self,
|
|
433
|
+
state=state,
|
|
434
|
+
head=head,
|
|
435
|
+
base=base,
|
|
436
|
+
sort=sort,
|
|
437
|
+
direction=direction,
|
|
438
|
+
number=number,
|
|
439
|
+
etag=etag,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
def create_pull(
|
|
443
|
+
self,
|
|
444
|
+
title: str,
|
|
445
|
+
base: str,
|
|
446
|
+
head: str,
|
|
447
|
+
body: str = None,
|
|
448
|
+
maintainer_can_modify: bool = None,
|
|
449
|
+
options: dict = {},
|
|
450
|
+
) -> Union[GitHubPullRequest, None]:
|
|
451
|
+
"""Creates a pull request on the given repository"""
|
|
452
|
+
try:
|
|
453
|
+
pull_request = GitHubPullRequest.create_pull(
|
|
454
|
+
self,
|
|
455
|
+
title,
|
|
456
|
+
base,
|
|
457
|
+
head,
|
|
458
|
+
body=body,
|
|
459
|
+
maintainer_can_modify=maintainer_can_modify,
|
|
460
|
+
)
|
|
461
|
+
return pull_request
|
|
462
|
+
except UnprocessableEntity as e:
|
|
463
|
+
error_msg = options.get(
|
|
464
|
+
"error_message",
|
|
465
|
+
f"Error creating pull request to merge {head} into {base}",
|
|
466
|
+
)
|
|
467
|
+
self.logger.error(f"{error_msg}:\n{e.response.text}")
|
|
468
|
+
except Exception as e:
|
|
469
|
+
self.logger.error(f"An unexpected error occurred: {str(e)}")
|
|
470
|
+
return None
|
|
471
|
+
|
|
472
|
+
def get_commit(self, commit_sha: str) -> GitHubCommit:
|
|
473
|
+
"""Given a SHA1 hash, retrieve a Commit object from the REST API."""
|
|
474
|
+
try:
|
|
475
|
+
commit = self.repo.commit(commit_sha)
|
|
476
|
+
return GitHubCommit(commit=commit)
|
|
477
|
+
except (NotFoundError, UnprocessableEntity):
|
|
478
|
+
# GitHub returns 422 for nonexistent commits in at least some circumstances.
|
|
479
|
+
raise GithubApiNotFoundError(
|
|
480
|
+
f"Could not find commit {commit_sha} on GitHub"
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
def release_from_tag(self, tag_name: str) -> GitHubRelease:
|
|
484
|
+
"""Fetches a release from the given tag name."""
|
|
485
|
+
try:
|
|
486
|
+
release: Release = self.repo.release_from_tag(tag_name)
|
|
487
|
+
except NotFoundError:
|
|
488
|
+
message = f"Release for {tag_name} not found"
|
|
489
|
+
raise GithubApiNotFoundError(message)
|
|
490
|
+
return GitHubRelease(release=release)
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def default_branch(self) -> str:
|
|
494
|
+
"""Returns the default branch of the repository."""
|
|
495
|
+
return self.repo.default_branch if self.repo else ""
|
|
496
|
+
|
|
497
|
+
def archive(
|
|
498
|
+
self, format: str, zip_content: Union[str, object], ref=None
|
|
499
|
+
) -> BytesIO:
|
|
500
|
+
"""Archives the repository content as a zip file."""
|
|
501
|
+
try:
|
|
502
|
+
self.repo.archive(format, zip_content, ref)
|
|
503
|
+
return zip_content
|
|
504
|
+
except NotFoundError:
|
|
505
|
+
raise GithubApiNotFoundError(
|
|
506
|
+
f"Could not find archive for {zip_content} for service {self.service_type}"
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
def full_name(self) -> str:
|
|
510
|
+
"""Returns the full name of the repository."""
|
|
511
|
+
return self.repo.full_name if self.repo else ""
|
|
512
|
+
|
|
513
|
+
def create_release(
|
|
514
|
+
self,
|
|
515
|
+
tag_name: str,
|
|
516
|
+
name: str = None,
|
|
517
|
+
body: str = None,
|
|
518
|
+
draft: bool = False,
|
|
519
|
+
prerelease: bool = False,
|
|
520
|
+
options: dict = {},
|
|
521
|
+
) -> GitHubRelease:
|
|
522
|
+
"""Creates a release on the given repository."""
|
|
523
|
+
try:
|
|
524
|
+
release = self.repo.create_release(
|
|
525
|
+
tag_name, name=name, body=body, draft=draft, prerelease=prerelease
|
|
526
|
+
)
|
|
527
|
+
return GitHubRelease(release=release)
|
|
528
|
+
except NotFoundError:
|
|
529
|
+
raise GithubApiNotFoundError(
|
|
530
|
+
f"Could not create release for {tag_name} on GitHub"
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
def releases(self) -> list[GitHubRelease]:
|
|
534
|
+
"""Fetches all releases from the given repository."""
|
|
535
|
+
try:
|
|
536
|
+
releases = self.repo.releases()
|
|
537
|
+
return [GitHubRelease(release=release) for release in releases]
|
|
538
|
+
except NotFoundError:
|
|
539
|
+
raise GithubApiNotFoundError("Could not find releases on GitHub")
|
|
540
|
+
except UnprocessableEntity:
|
|
541
|
+
raise GithubApiNotFoundError(
|
|
542
|
+
"Could not find releases on GitHub. Check if the repository is archived."
|
|
543
|
+
)
|
|
544
|
+
except GitHubError as e:
|
|
545
|
+
if e.code == http.client.UNAUTHORIZED:
|
|
546
|
+
raise GithubApiNotFoundError(
|
|
547
|
+
"Could not find releases on GitHub. Check your authentication."
|
|
548
|
+
)
|
|
549
|
+
else:
|
|
550
|
+
raise GithubApiNotFoundError(
|
|
551
|
+
f"Could not find releases on GitHub: {e.message}"
|
|
552
|
+
)
|
|
553
|
+
except Exception as e:
|
|
554
|
+
raise GithubApiNotFoundError(
|
|
555
|
+
f"An unexpected error occurred while fetching releases: {str(e)}"
|
|
556
|
+
)
|
|
557
|
+
return []
|
|
558
|
+
|
|
559
|
+
def latest_release(self) -> Optional[GitHubRelease]:
|
|
560
|
+
"""Fetches the latest release from the given repository."""
|
|
561
|
+
try:
|
|
562
|
+
release = self.repo.latest_release()
|
|
563
|
+
if release:
|
|
564
|
+
return GitHubRelease(release=release)
|
|
565
|
+
return None
|
|
566
|
+
except NotFoundError:
|
|
567
|
+
raise GithubApiNotFoundError("Could not find latest release on GitHub")
|
|
568
|
+
|
|
569
|
+
def has_issues(self) -> bool:
|
|
570
|
+
"""Checks if the repository has issues enabled."""
|
|
571
|
+
return self.repo.has_issues() if self.repo else False
|
|
572
|
+
|
|
573
|
+
def get_pull_requests_by_commit(self, commit_sha) -> list[GitHubPullRequest]:
|
|
574
|
+
"""Fetches all pull requests associated with the given commit SHA."""
|
|
575
|
+
endpoint = (
|
|
576
|
+
self.github.session.base_url
|
|
577
|
+
+ f"/repos/{self.repo.owner.login}/{self.repo.name}/commits/{commit_sha}/pulls"
|
|
578
|
+
)
|
|
579
|
+
response = self.github.session.get(
|
|
580
|
+
endpoint, headers={"Accept": "application/vnd.github.groot-preview+json"}
|
|
581
|
+
)
|
|
582
|
+
json_list = safe_json_from_response(response)
|
|
583
|
+
|
|
584
|
+
for json in json_list:
|
|
585
|
+
json["body_html"] = ""
|
|
586
|
+
json["body_text"] = ""
|
|
587
|
+
|
|
588
|
+
pull_requests = [
|
|
589
|
+
GitHubPullRequest(
|
|
590
|
+
repo=self.repo, pull_request=ShortPullRequest(json, self.github)
|
|
591
|
+
)
|
|
592
|
+
for json in json_list
|
|
593
|
+
]
|
|
594
|
+
return pull_requests
|
|
595
|
+
|
|
596
|
+
def get_pr_issue_labels(self, pull_request: GitHubPullRequest) -> list[str]:
|
|
597
|
+
"""Fetches all labels associated with the given pull request."""
|
|
598
|
+
issue: ShortIssue = self.repo.issue(pull_request.number)
|
|
599
|
+
labels: ShortLabel = issue.labels()
|
|
600
|
+
return [label.name for label in labels] if labels else []
|
|
601
|
+
|
|
602
|
+
def get_latest_prerelease(self) -> Optional[GitHubRelease]:
|
|
603
|
+
"""Fetches the latest pre-release from the given repository."""
|
|
604
|
+
try:
|
|
605
|
+
QUERY = Template(
|
|
606
|
+
"""
|
|
607
|
+
query {
|
|
608
|
+
repository(owner: "$owner", name: "$name") {
|
|
609
|
+
releases(last: 1, orderBy: {field: CREATED_AT, direction: ASC}) {
|
|
610
|
+
nodes {
|
|
611
|
+
tagName
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
"""
|
|
617
|
+
).substitute(dict(owner=self.repo.owner, name=self.repo.name))
|
|
618
|
+
|
|
619
|
+
session: GitHubSession = self.repo.session
|
|
620
|
+
# HACK: This is a kludgy workaround because GitHub Enterprise Server
|
|
621
|
+
# base_urls in github3.py end in `/api/v3`.
|
|
622
|
+
host = (
|
|
623
|
+
session.base_url[: -len("/v3")]
|
|
624
|
+
if session.base_url.endswith("/v3")
|
|
625
|
+
else session.base_url
|
|
626
|
+
)
|
|
627
|
+
url: str = f"{host}/graphql"
|
|
628
|
+
response: Response = session.request("POST", url, json={"query": QUERY})
|
|
629
|
+
response_dict: dict = response.json()
|
|
630
|
+
|
|
631
|
+
if release_tags := response_dict["data"]["repository"]["releases"]["nodes"]:
|
|
632
|
+
return self.release_from_tag(release_tags[0]["tagName"])
|
|
633
|
+
except NotFoundError:
|
|
634
|
+
raise GithubApiNotFoundError("Could not find latest prerelease on GitHub")
|
|
635
|
+
|
|
636
|
+
def directory_contents(self, subfolder: str, return_as, ref: str) -> dict:
|
|
637
|
+
try:
|
|
638
|
+
contents = self.repo.directory_contents(
|
|
639
|
+
subfolder, return_as=return_as, ref=ref
|
|
640
|
+
)
|
|
641
|
+
except NotFoundError:
|
|
642
|
+
contents = None
|
|
643
|
+
raise GithubApiNotFoundError(
|
|
644
|
+
f"Could not find directory {subfolder} on GitHub."
|
|
645
|
+
)
|
|
646
|
+
return contents
|
|
647
|
+
|
|
648
|
+
def file_contents(self, file_path: str, ref: str) -> StringIO:
|
|
649
|
+
contents = self.repo.file_contents(file_path, ref=ref)
|
|
650
|
+
contents_io = StringIO(contents.decoded.decode("utf-8") if contents else "")
|
|
651
|
+
contents_io.url = (
|
|
652
|
+
f"{file_path} from {self.repo.owner}/{self.repo.name}" # for logging
|
|
653
|
+
)
|
|
654
|
+
return contents_io
|
|
655
|
+
|
|
656
|
+
@property
|
|
657
|
+
def clone_url(self) -> str:
|
|
658
|
+
return self.repo.clone_url
|
|
659
|
+
|
|
660
|
+
def create_commit_status(
|
|
661
|
+
self,
|
|
662
|
+
commit_id: str,
|
|
663
|
+
context: str,
|
|
664
|
+
state: str,
|
|
665
|
+
description: str,
|
|
666
|
+
target_url: str,
|
|
667
|
+
) -> GitHubCommit:
|
|
668
|
+
"""Creates a commit status in the repository."""
|
|
669
|
+
try:
|
|
670
|
+
status = self.repo.create_status(
|
|
671
|
+
commit_id,
|
|
672
|
+
state,
|
|
673
|
+
target_url=target_url,
|
|
674
|
+
description=description,
|
|
675
|
+
context=context,
|
|
676
|
+
)
|
|
677
|
+
if not status:
|
|
678
|
+
raise GithubApiNotFoundError(
|
|
679
|
+
f"Could not create commit status for {commit_id} on GitHub"
|
|
680
|
+
)
|
|
681
|
+
return self.get_commit(commit_id)
|
|
682
|
+
except NotFoundError:
|
|
683
|
+
raise GithubApiNotFoundError(
|
|
684
|
+
f"Could not create commit status for {commit_id} on GitHub"
|
|
685
|
+
)
|
|
686
|
+
except UnprocessableEntity as e:
|
|
687
|
+
raise GithubApiNotFoundError(
|
|
688
|
+
f"Could not create commit status for {commit_id} on GitHub: {e.response.text}"
|
|
689
|
+
)
|