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.

Files changed (744) hide show
  1. cumulusci/__about__.py +1 -0
  2. cumulusci/__init__.py +22 -0
  3. cumulusci/__main__.py +3 -0
  4. cumulusci/cli/__init__.py +0 -0
  5. cumulusci/cli/cci.py +244 -0
  6. cumulusci/cli/error.py +125 -0
  7. cumulusci/cli/flow.py +185 -0
  8. cumulusci/cli/logger.py +72 -0
  9. cumulusci/cli/org.py +692 -0
  10. cumulusci/cli/plan.py +181 -0
  11. cumulusci/cli/project.py +391 -0
  12. cumulusci/cli/robot.py +116 -0
  13. cumulusci/cli/runtime.py +190 -0
  14. cumulusci/cli/service.py +521 -0
  15. cumulusci/cli/task.py +295 -0
  16. cumulusci/cli/tests/__init__.py +0 -0
  17. cumulusci/cli/tests/test_cci.py +545 -0
  18. cumulusci/cli/tests/test_error.py +170 -0
  19. cumulusci/cli/tests/test_flow.py +276 -0
  20. cumulusci/cli/tests/test_logger.py +25 -0
  21. cumulusci/cli/tests/test_org.py +1438 -0
  22. cumulusci/cli/tests/test_plan.py +245 -0
  23. cumulusci/cli/tests/test_project.py +235 -0
  24. cumulusci/cli/tests/test_robot.py +177 -0
  25. cumulusci/cli/tests/test_runtime.py +197 -0
  26. cumulusci/cli/tests/test_service.py +853 -0
  27. cumulusci/cli/tests/test_task.py +266 -0
  28. cumulusci/cli/tests/test_ui.py +310 -0
  29. cumulusci/cli/tests/test_utils.py +122 -0
  30. cumulusci/cli/tests/utils.py +52 -0
  31. cumulusci/cli/ui.py +234 -0
  32. cumulusci/cli/utils.py +150 -0
  33. cumulusci/conftest.py +181 -0
  34. cumulusci/core/__init__.py +0 -0
  35. cumulusci/core/config/BaseConfig.py +5 -0
  36. cumulusci/core/config/BaseTaskFlowConfig.py +5 -0
  37. cumulusci/core/config/OrgConfig.py +5 -0
  38. cumulusci/core/config/ScratchOrgConfig.py +5 -0
  39. cumulusci/core/config/__init__.py +125 -0
  40. cumulusci/core/config/base_config.py +111 -0
  41. cumulusci/core/config/base_task_flow_config.py +82 -0
  42. cumulusci/core/config/marketing_cloud_service_config.py +83 -0
  43. cumulusci/core/config/oauth2_service_config.py +17 -0
  44. cumulusci/core/config/org_config.py +604 -0
  45. cumulusci/core/config/project_config.py +782 -0
  46. cumulusci/core/config/scratch_org_config.py +251 -0
  47. cumulusci/core/config/sfdx_org_config.py +220 -0
  48. cumulusci/core/config/tests/_test_config_backwards_compatibility.py +33 -0
  49. cumulusci/core/config/tests/test_config.py +1895 -0
  50. cumulusci/core/config/tests/test_config_expensive.py +839 -0
  51. cumulusci/core/config/tests/test_config_util.py +91 -0
  52. cumulusci/core/config/universal_config.py +88 -0
  53. cumulusci/core/config/util.py +18 -0
  54. cumulusci/core/datasets.py +303 -0
  55. cumulusci/core/debug.py +33 -0
  56. cumulusci/core/dependencies/__init__.py +55 -0
  57. cumulusci/core/dependencies/base.py +561 -0
  58. cumulusci/core/dependencies/dependencies.py +273 -0
  59. cumulusci/core/dependencies/github.py +177 -0
  60. cumulusci/core/dependencies/github_resolvers.py +244 -0
  61. cumulusci/core/dependencies/resolvers.py +580 -0
  62. cumulusci/core/dependencies/tests/__init__.py +0 -0
  63. cumulusci/core/dependencies/tests/conftest.py +385 -0
  64. cumulusci/core/dependencies/tests/test_dependencies.py +950 -0
  65. cumulusci/core/dependencies/tests/test_github.py +83 -0
  66. cumulusci/core/dependencies/tests/test_resolvers.py +1027 -0
  67. cumulusci/core/dependencies/utils.py +13 -0
  68. cumulusci/core/enums.py +11 -0
  69. cumulusci/core/exceptions.py +311 -0
  70. cumulusci/core/flowrunner.py +888 -0
  71. cumulusci/core/github.py +665 -0
  72. cumulusci/core/keychain/__init__.py +24 -0
  73. cumulusci/core/keychain/base_project_keychain.py +441 -0
  74. cumulusci/core/keychain/encrypted_file_project_keychain.py +945 -0
  75. cumulusci/core/keychain/environment_project_keychain.py +7 -0
  76. cumulusci/core/keychain/serialization.py +152 -0
  77. cumulusci/core/keychain/subprocess_keychain.py +24 -0
  78. cumulusci/core/keychain/tests/conftest.py +50 -0
  79. cumulusci/core/keychain/tests/test_base_project_keychain.py +299 -0
  80. cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py +1228 -0
  81. cumulusci/core/metadeploy/__init__.py +0 -0
  82. cumulusci/core/metadeploy/api.py +88 -0
  83. cumulusci/core/metadeploy/plans.py +25 -0
  84. cumulusci/core/metadeploy/tests/test_api.py +276 -0
  85. cumulusci/core/runtime.py +115 -0
  86. cumulusci/core/sfdx.py +162 -0
  87. cumulusci/core/source/__init__.py +16 -0
  88. cumulusci/core/source/github.py +50 -0
  89. cumulusci/core/source/local_folder.py +35 -0
  90. cumulusci/core/source_transforms/__init__.py +0 -0
  91. cumulusci/core/source_transforms/tests/test_transforms.py +1091 -0
  92. cumulusci/core/source_transforms/transforms.py +532 -0
  93. cumulusci/core/tasks.py +404 -0
  94. cumulusci/core/template_utils.py +59 -0
  95. cumulusci/core/tests/__init__.py +0 -0
  96. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_e2e.yaml +215 -0
  97. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_extract_standard_objects.yaml +199 -0
  98. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_read_explicit_extract_declaration.yaml +3 -0
  99. cumulusci/core/tests/fake_remote_repo/cumulusci.yml +32 -0
  100. cumulusci/core/tests/fake_remote_repo/tasks/directory/example_2.py +6 -0
  101. cumulusci/core/tests/fake_remote_repo/tasks/example.py +43 -0
  102. cumulusci/core/tests/fake_remote_repo_2/cumulusci.yml +11 -0
  103. cumulusci/core/tests/fake_remote_repo_2/tasks/example_3.py +6 -0
  104. cumulusci/core/tests/test_datasets_e2e.py +386 -0
  105. cumulusci/core/tests/test_exceptions.py +11 -0
  106. cumulusci/core/tests/test_flowrunner.py +836 -0
  107. cumulusci/core/tests/test_github.py +942 -0
  108. cumulusci/core/tests/test_sfdx.py +138 -0
  109. cumulusci/core/tests/test_source.py +678 -0
  110. cumulusci/core/tests/test_tasks.py +262 -0
  111. cumulusci/core/tests/test_utils.py +141 -0
  112. cumulusci/core/tests/test_utils_merge_config.py +276 -0
  113. cumulusci/core/tests/test_versions.py +76 -0
  114. cumulusci/core/tests/untrusted_repo_child/cumulusci.yml +7 -0
  115. cumulusci/core/tests/untrusted_repo_child/tasks/untrusted_child.py +6 -0
  116. cumulusci/core/tests/untrusted_repo_parent/cumulusci.yml +26 -0
  117. cumulusci/core/tests/untrusted_repo_parent/tasks/untrusted_parent.py +6 -0
  118. cumulusci/core/tests/utils.py +116 -0
  119. cumulusci/core/tests/yaml/global.yaml +0 -0
  120. cumulusci/core/utils.py +402 -0
  121. cumulusci/core/versions.py +149 -0
  122. cumulusci/cumulusci.yml +1621 -0
  123. cumulusci/files/admin_profile.xml +20 -0
  124. cumulusci/files/delete_excludes.txt +424 -0
  125. cumulusci/files/templates/project/README.md +12 -0
  126. cumulusci/files/templates/project/cumulusci.yml +63 -0
  127. cumulusci/files/templates/project/dot-gitignore +60 -0
  128. cumulusci/files/templates/project/mapping.yml +45 -0
  129. cumulusci/files/templates/project/scratch_def.json +25 -0
  130. cumulusci/oauth/__init__.py +0 -0
  131. cumulusci/oauth/client.py +400 -0
  132. cumulusci/oauth/exceptions.py +9 -0
  133. cumulusci/oauth/salesforce.py +95 -0
  134. cumulusci/oauth/tests/__init__.py +0 -0
  135. cumulusci/oauth/tests/cassettes/test_get_device_code.yaml +22 -0
  136. cumulusci/oauth/tests/cassettes/test_get_device_oauth_token.yaml +74 -0
  137. cumulusci/oauth/tests/test_client.py +308 -0
  138. cumulusci/oauth/tests/test_salesforce.py +46 -0
  139. cumulusci/plugins/__init__.py +3 -0
  140. cumulusci/plugins/plugin_base.py +93 -0
  141. cumulusci/plugins/plugin_loader.py +59 -0
  142. cumulusci/robotframework/CumulusCI.py +340 -0
  143. cumulusci/robotframework/CumulusCI.robot +7 -0
  144. cumulusci/robotframework/Performance.py +165 -0
  145. cumulusci/robotframework/Salesforce.py +936 -0
  146. cumulusci/robotframework/Salesforce.robot +192 -0
  147. cumulusci/robotframework/SalesforceAPI.py +416 -0
  148. cumulusci/robotframework/SalesforcePlaywright.py +220 -0
  149. cumulusci/robotframework/SalesforcePlaywright.robot +40 -0
  150. cumulusci/robotframework/__init__.py +2 -0
  151. cumulusci/robotframework/base_library.py +39 -0
  152. cumulusci/robotframework/faker_mixin.py +89 -0
  153. cumulusci/robotframework/form_handlers.py +222 -0
  154. cumulusci/robotframework/javascript/cci_init.js +34 -0
  155. cumulusci/robotframework/javascript/cumulusci.js +4 -0
  156. cumulusci/robotframework/locator_manager.py +197 -0
  157. cumulusci/robotframework/locators_56.py +88 -0
  158. cumulusci/robotframework/locators_57.py +5 -0
  159. cumulusci/robotframework/pageobjects/BasePageObjects.py +433 -0
  160. cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +246 -0
  161. cumulusci/robotframework/pageobjects/PageObjectLibrary.py +45 -0
  162. cumulusci/robotframework/pageobjects/PageObjects.py +351 -0
  163. cumulusci/robotframework/pageobjects/__init__.py +12 -0
  164. cumulusci/robotframework/pageobjects/baseobjects.py +120 -0
  165. cumulusci/robotframework/perftests/short/collection_perf.robot +105 -0
  166. cumulusci/robotframework/tests/CustomObjectTestPage.py +10 -0
  167. cumulusci/robotframework/tests/FooTestPage.py +8 -0
  168. cumulusci/robotframework/tests/cumulusci/base.robot +40 -0
  169. cumulusci/robotframework/tests/cumulusci/bulkdata.robot +38 -0
  170. cumulusci/robotframework/tests/cumulusci/communities.robot +57 -0
  171. cumulusci/robotframework/tests/cumulusci/datagen.robot +84 -0
  172. cumulusci/robotframework/tests/salesforce/TestLibraryA.py +24 -0
  173. cumulusci/robotframework/tests/salesforce/TestLibraryB.py +20 -0
  174. cumulusci/robotframework/tests/salesforce/TestListener.py +93 -0
  175. cumulusci/robotframework/tests/salesforce/api.robot +178 -0
  176. cumulusci/robotframework/tests/salesforce/browsers.robot +143 -0
  177. cumulusci/robotframework/tests/salesforce/classic.robot +51 -0
  178. cumulusci/robotframework/tests/salesforce/create_contact.robot +59 -0
  179. cumulusci/robotframework/tests/salesforce/faker.robot +68 -0
  180. cumulusci/robotframework/tests/salesforce/forms.robot +172 -0
  181. cumulusci/robotframework/tests/salesforce/label_locator.robot +244 -0
  182. cumulusci/robotframework/tests/salesforce/labels.html +33 -0
  183. cumulusci/robotframework/tests/salesforce/locators.robot +149 -0
  184. cumulusci/robotframework/tests/salesforce/pageobjects/base_pageobjects.robot +100 -0
  185. cumulusci/robotframework/tests/salesforce/pageobjects/example_page_object.py +25 -0
  186. cumulusci/robotframework/tests/salesforce/pageobjects/listing_page.robot +115 -0
  187. cumulusci/robotframework/tests/salesforce/pageobjects/objectmanager.robot +74 -0
  188. cumulusci/robotframework/tests/salesforce/pageobjects/pageobjects.robot +171 -0
  189. cumulusci/robotframework/tests/salesforce/performance.robot +109 -0
  190. cumulusci/robotframework/tests/salesforce/playwright/javascript_keywords.robot +33 -0
  191. cumulusci/robotframework/tests/salesforce/playwright/open_test_browser.robot +48 -0
  192. cumulusci/robotframework/tests/salesforce/playwright/playwright.robot +24 -0
  193. cumulusci/robotframework/tests/salesforce/playwright/ui.robot +32 -0
  194. cumulusci/robotframework/tests/salesforce/populate.robot +89 -0
  195. cumulusci/robotframework/tests/salesforce/test_testlistener.py +37 -0
  196. cumulusci/robotframework/tests/salesforce/ui.robot +361 -0
  197. cumulusci/robotframework/tests/test_cumulusci_library.py +304 -0
  198. cumulusci/robotframework/tests/test_locator_manager.py +158 -0
  199. cumulusci/robotframework/tests/test_pageobjects.py +291 -0
  200. cumulusci/robotframework/tests/test_performance.py +38 -0
  201. cumulusci/robotframework/tests/test_salesforce.py +79 -0
  202. cumulusci/robotframework/tests/test_salesforce_locators.py +73 -0
  203. cumulusci/robotframework/tests/test_template_util.py +53 -0
  204. cumulusci/robotframework/tests/test_utils.py +106 -0
  205. cumulusci/robotframework/utils.py +283 -0
  206. cumulusci/salesforce_api/__init__.py +0 -0
  207. cumulusci/salesforce_api/exceptions.py +23 -0
  208. cumulusci/salesforce_api/filterable_objects.py +96 -0
  209. cumulusci/salesforce_api/mc_soap_envelopes.py +89 -0
  210. cumulusci/salesforce_api/metadata.py +721 -0
  211. cumulusci/salesforce_api/org_schema.py +571 -0
  212. cumulusci/salesforce_api/org_schema_models.py +226 -0
  213. cumulusci/salesforce_api/package_install.py +265 -0
  214. cumulusci/salesforce_api/package_zip.py +301 -0
  215. cumulusci/salesforce_api/rest_deploy.py +148 -0
  216. cumulusci/salesforce_api/retrieve_profile_api.py +301 -0
  217. cumulusci/salesforce_api/soap_envelopes.py +177 -0
  218. cumulusci/salesforce_api/tests/__init__.py +0 -0
  219. cumulusci/salesforce_api/tests/metadata_test_strings.py +24 -0
  220. cumulusci/salesforce_api/tests/test_metadata.py +1015 -0
  221. cumulusci/salesforce_api/tests/test_package_install.py +219 -0
  222. cumulusci/salesforce_api/tests/test_package_zip.py +380 -0
  223. cumulusci/salesforce_api/tests/test_rest_deploy.py +264 -0
  224. cumulusci/salesforce_api/tests/test_retrieve_profile_api.py +337 -0
  225. cumulusci/salesforce_api/tests/test_utils.py +124 -0
  226. cumulusci/salesforce_api/utils.py +51 -0
  227. cumulusci/schema/cumulusci.jsonschema.json +782 -0
  228. cumulusci/tasks/__init__.py +0 -0
  229. cumulusci/tasks/apex/__init__.py +0 -0
  230. cumulusci/tasks/apex/anon.py +157 -0
  231. cumulusci/tasks/apex/batch.py +180 -0
  232. cumulusci/tasks/apex/testrunner.py +835 -0
  233. cumulusci/tasks/apex/tests/cassettes/ManualEditTestApexIntegrationTests.test_run_tests__integration_test.yaml +703 -0
  234. cumulusci/tasks/apex/tests/test_apex_tasks.py +1558 -0
  235. cumulusci/tasks/base_source_control_task.py +17 -0
  236. cumulusci/tasks/bulkdata/__init__.py +15 -0
  237. cumulusci/tasks/bulkdata/base_generate_data_task.py +96 -0
  238. cumulusci/tasks/bulkdata/dates.py +97 -0
  239. cumulusci/tasks/bulkdata/delete.py +156 -0
  240. cumulusci/tasks/bulkdata/extract.py +441 -0
  241. cumulusci/tasks/bulkdata/extract_dataset_utils/calculate_dependencies.py +117 -0
  242. cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +123 -0
  243. cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py +49 -0
  244. cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +283 -0
  245. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +142 -0
  246. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_synthesize_extract_declarations.py +575 -0
  247. cumulusci/tasks/bulkdata/factory_utils.py +134 -0
  248. cumulusci/tasks/bulkdata/generate.py +4 -0
  249. cumulusci/tasks/bulkdata/generate_and_load_data.py +232 -0
  250. cumulusci/tasks/bulkdata/generate_and_load_data_from_yaml.py +19 -0
  251. cumulusci/tasks/bulkdata/generate_from_yaml.py +183 -0
  252. cumulusci/tasks/bulkdata/generate_mapping.py +434 -0
  253. cumulusci/tasks/bulkdata/generate_mapping_utils/dependency_map.py +169 -0
  254. cumulusci/tasks/bulkdata/generate_mapping_utils/extract_mapping_file_generator.py +45 -0
  255. cumulusci/tasks/bulkdata/generate_mapping_utils/generate_mapping_from_declarations.py +121 -0
  256. cumulusci/tasks/bulkdata/generate_mapping_utils/load_mapping_file_generator.py +127 -0
  257. cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_generator_post_processes.py +53 -0
  258. cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_transforms.py +139 -0
  259. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_extract_mapping_from_declarations.py +135 -0
  260. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_load_mapping_from_declarations.py +330 -0
  261. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_generator_post_processes.py +60 -0
  262. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_transforms.py +188 -0
  263. cumulusci/tasks/bulkdata/load.py +1196 -0
  264. cumulusci/tasks/bulkdata/mapping_parser.py +811 -0
  265. cumulusci/tasks/bulkdata/query_transformers.py +264 -0
  266. cumulusci/tasks/bulkdata/select_utils.py +792 -0
  267. cumulusci/tasks/bulkdata/snowfakery.py +753 -0
  268. cumulusci/tasks/bulkdata/snowfakery_utils/queue_manager.py +478 -0
  269. cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_run_until.py +141 -0
  270. cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_working_directory.py +53 -0
  271. cumulusci/tasks/bulkdata/snowfakery_utils/subtask_configurator.py +64 -0
  272. cumulusci/tasks/bulkdata/step.py +1242 -0
  273. cumulusci/tasks/bulkdata/tests/__init__.py +0 -0
  274. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_random_strategy.yaml +147 -0
  275. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_annoy_strategy.yaml +123 -0
  276. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy.yaml +313 -0
  277. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy_bulk.yaml +550 -0
  278. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_strategy.yaml +175 -0
  279. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_standard_strategy.yaml +147 -0
  280. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__multiple_needed.yaml +69 -0
  281. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__none_needed.yaml +22 -0
  282. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__one_needed.yaml +24 -0
  283. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_snowfakery_query_salesforce.yaml +25 -0
  284. cumulusci/tasks/bulkdata/tests/cassettes/TestUpdatesIntegrationTests.test_updates_task.yaml +80 -0
  285. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_simple_upsert__rest.yaml +270 -0
  286. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert__rest.yaml +267 -0
  287. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field__rest.yaml +369 -0
  288. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field_rest__duplicate_error.yaml +204 -0
  289. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_fields__bulk.yaml +675 -0
  290. cumulusci/tasks/bulkdata/tests/dummy_data_factory.py +36 -0
  291. cumulusci/tasks/bulkdata/tests/integration_test_utils.py +49 -0
  292. cumulusci/tasks/bulkdata/tests/mapping-oid.yml +87 -0
  293. cumulusci/tasks/bulkdata/tests/mapping_after.yml +38 -0
  294. cumulusci/tasks/bulkdata/tests/mapping_poly.yml +34 -0
  295. cumulusci/tasks/bulkdata/tests/mapping_poly_incomplete.yml +20 -0
  296. cumulusci/tasks/bulkdata/tests/mapping_poly_wrong.yml +21 -0
  297. cumulusci/tasks/bulkdata/tests/mapping_select.yml +20 -0
  298. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_strategy.yml +20 -0
  299. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_number.yml +21 -0
  300. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_strategy.yml +21 -0
  301. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__non_float.yml +21 -0
  302. cumulusci/tasks/bulkdata/tests/mapping_select_missing_priority_fields.yml +22 -0
  303. cumulusci/tasks/bulkdata/tests/mapping_select_no_priority_fields.yml +18 -0
  304. cumulusci/tasks/bulkdata/tests/mapping_simple.yml +27 -0
  305. cumulusci/tasks/bulkdata/tests/mapping_v1.yml +28 -0
  306. cumulusci/tasks/bulkdata/tests/mapping_v2.yml +21 -0
  307. cumulusci/tasks/bulkdata/tests/mapping_v3.yml +32 -0
  308. cumulusci/tasks/bulkdata/tests/mapping_vanilla_sf.yml +69 -0
  309. cumulusci/tasks/bulkdata/tests/mock_data_factory_without_mapping.py +12 -0
  310. cumulusci/tasks/bulkdata/tests/person_accounts.yml +23 -0
  311. cumulusci/tasks/bulkdata/tests/person_accounts_minimal.yml +15 -0
  312. cumulusci/tasks/bulkdata/tests/recordtypes.yml +8 -0
  313. cumulusci/tasks/bulkdata/tests/recordtypes_2.yml +6 -0
  314. cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml +8 -0
  315. cumulusci/tasks/bulkdata/tests/snowfakery/child/child2.yml +3 -0
  316. cumulusci/tasks/bulkdata/tests/snowfakery/child.yml +4 -0
  317. cumulusci/tasks/bulkdata/tests/snowfakery/gen_npsp_standard_objects.recipe.yml +89 -0
  318. cumulusci/tasks/bulkdata/tests/snowfakery/include_parent.yml +3 -0
  319. cumulusci/tasks/bulkdata/tests/snowfakery/npsp_standard_objects_macros.yml +34 -0
  320. cumulusci/tasks/bulkdata/tests/snowfakery/options.recipe.yml +6 -0
  321. cumulusci/tasks/bulkdata/tests/snowfakery/query_snowfakery.recipe.yml +16 -0
  322. cumulusci/tasks/bulkdata/tests/snowfakery/sf_standard_object_macros.yml +83 -0
  323. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.load.yml +2 -0
  324. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.recipe.yml +13 -0
  325. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_2.load.yml +5 -0
  326. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.load.yml +13 -0
  327. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.recipe.yml +12 -0
  328. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels_2.load.yml +13 -0
  329. cumulusci/tasks/bulkdata/tests/snowfakery/unique_values.recipe.yml +4 -0
  330. cumulusci/tasks/bulkdata/tests/snowfakery/upsert.recipe.yml +23 -0
  331. cumulusci/tasks/bulkdata/tests/snowfakery/upsert_2.recipe.yml +29 -0
  332. cumulusci/tasks/bulkdata/tests/snowfakery/upsert_before.yml +10 -0
  333. cumulusci/tasks/bulkdata/tests/test_base_generate_data_tasks.py +61 -0
  334. cumulusci/tasks/bulkdata/tests/test_dates.py +99 -0
  335. cumulusci/tasks/bulkdata/tests/test_delete.py +404 -0
  336. cumulusci/tasks/bulkdata/tests/test_extract.py +1311 -0
  337. cumulusci/tasks/bulkdata/tests/test_factory_utils.py +55 -0
  338. cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +252 -0
  339. cumulusci/tasks/bulkdata/tests/test_generate_from_snowfakery_task.py +343 -0
  340. cumulusci/tasks/bulkdata/tests/test_generatemapping.py +1039 -0
  341. cumulusci/tasks/bulkdata/tests/test_load.py +3175 -0
  342. cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +1658 -0
  343. cumulusci/tasks/bulkdata/tests/test_query_db__joins_self_lookups.yml +12 -0
  344. cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups.yml +26 -0
  345. cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups_select.yml +48 -0
  346. cumulusci/tasks/bulkdata/tests/test_select.py +171 -0
  347. cumulusci/tasks/bulkdata/tests/test_select_utils.py +1057 -0
  348. cumulusci/tasks/bulkdata/tests/test_snowfakery.py +1153 -0
  349. cumulusci/tasks/bulkdata/tests/test_step.py +3957 -0
  350. cumulusci/tasks/bulkdata/tests/test_updates.py +513 -0
  351. cumulusci/tasks/bulkdata/tests/test_upsert.py +1015 -0
  352. cumulusci/tasks/bulkdata/tests/test_utils.py +158 -0
  353. cumulusci/tasks/bulkdata/tests/testdata.db +0 -0
  354. cumulusci/tasks/bulkdata/tests/update_describe.py +50 -0
  355. cumulusci/tasks/bulkdata/tests/update_person_accounts.yml +23 -0
  356. cumulusci/tasks/bulkdata/tests/utils.py +114 -0
  357. cumulusci/tasks/bulkdata/update_data.py +260 -0
  358. cumulusci/tasks/bulkdata/upsert_utils.py +130 -0
  359. cumulusci/tasks/bulkdata/utils.py +249 -0
  360. cumulusci/tasks/command.py +178 -0
  361. cumulusci/tasks/connectedapp.py +186 -0
  362. cumulusci/tasks/create_package_version.py +778 -0
  363. cumulusci/tasks/datadictionary.py +745 -0
  364. cumulusci/tasks/dx_convert_from.py +26 -0
  365. cumulusci/tasks/github/__init__.py +17 -0
  366. cumulusci/tasks/github/base.py +16 -0
  367. cumulusci/tasks/github/commit_status.py +13 -0
  368. cumulusci/tasks/github/merge.py +11 -0
  369. cumulusci/tasks/github/publish.py +11 -0
  370. cumulusci/tasks/github/pull_request.py +11 -0
  371. cumulusci/tasks/github/release.py +11 -0
  372. cumulusci/tasks/github/release_report.py +11 -0
  373. cumulusci/tasks/github/tag.py +11 -0
  374. cumulusci/tasks/github/tests/__init__.py +0 -0
  375. cumulusci/tasks/github/tests/test_util.py +202 -0
  376. cumulusci/tasks/github/tests/test_vcs_migration.py +44 -0
  377. cumulusci/tasks/github/tests/util_github_api.py +666 -0
  378. cumulusci/tasks/github/util.py +252 -0
  379. cumulusci/tasks/marketing_cloud/__init__.py +0 -0
  380. cumulusci/tasks/marketing_cloud/api.py +188 -0
  381. cumulusci/tasks/marketing_cloud/base.py +38 -0
  382. cumulusci/tasks/marketing_cloud/deploy.py +345 -0
  383. cumulusci/tasks/marketing_cloud/get_user_info.py +40 -0
  384. cumulusci/tasks/marketing_cloud/mc_constants.py +1 -0
  385. cumulusci/tasks/marketing_cloud/tests/__init__.py +0 -0
  386. cumulusci/tasks/marketing_cloud/tests/conftest.py +46 -0
  387. cumulusci/tasks/marketing_cloud/tests/expected-payload.json +110 -0
  388. cumulusci/tasks/marketing_cloud/tests/test_api.py +97 -0
  389. cumulusci/tasks/marketing_cloud/tests/test_api_soap_envelopes.py +145 -0
  390. cumulusci/tasks/marketing_cloud/tests/test_base.py +14 -0
  391. cumulusci/tasks/marketing_cloud/tests/test_deploy.py +400 -0
  392. cumulusci/tasks/marketing_cloud/tests/test_get_user_info.py +141 -0
  393. cumulusci/tasks/marketing_cloud/tests/validation-response.json +39 -0
  394. cumulusci/tasks/metadata/__init__.py +0 -0
  395. cumulusci/tasks/metadata/ee_src.py +94 -0
  396. cumulusci/tasks/metadata/managed_src.py +100 -0
  397. cumulusci/tasks/metadata/metadata_map.yml +868 -0
  398. cumulusci/tasks/metadata/modify.py +99 -0
  399. cumulusci/tasks/metadata/package.py +684 -0
  400. cumulusci/tasks/metadata/tests/__init__.py +0 -0
  401. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/.hidden/.keep +0 -0
  402. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/destructiveChanges.xml +9 -0
  403. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package.xml +9 -0
  404. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package_install_uninstall.xml +11 -0
  405. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/reports/namespace__TestFolder/TestReport.report +3 -0
  406. cumulusci/tasks/metadata/tests/sample_package.xml +9 -0
  407. cumulusci/tasks/metadata/tests/test_ee_src.py +112 -0
  408. cumulusci/tasks/metadata/tests/test_managed_src.py +111 -0
  409. cumulusci/tasks/metadata/tests/test_modify.py +123 -0
  410. cumulusci/tasks/metadata/tests/test_package.py +476 -0
  411. cumulusci/tasks/metadata_etl/__init__.py +29 -0
  412. cumulusci/tasks/metadata_etl/base.py +436 -0
  413. cumulusci/tasks/metadata_etl/duplicate_rules.py +24 -0
  414. cumulusci/tasks/metadata_etl/field_sets.py +70 -0
  415. cumulusci/tasks/metadata_etl/help_text.py +92 -0
  416. cumulusci/tasks/metadata_etl/layouts.py +550 -0
  417. cumulusci/tasks/metadata_etl/objects.py +68 -0
  418. cumulusci/tasks/metadata_etl/permissions.py +167 -0
  419. cumulusci/tasks/metadata_etl/picklists.py +221 -0
  420. cumulusci/tasks/metadata_etl/remote_site_settings.py +99 -0
  421. cumulusci/tasks/metadata_etl/sharing.py +138 -0
  422. cumulusci/tasks/metadata_etl/tests/test_base.py +512 -0
  423. cumulusci/tasks/metadata_etl/tests/test_duplicate_rules.py +22 -0
  424. cumulusci/tasks/metadata_etl/tests/test_field_sets.py +156 -0
  425. cumulusci/tasks/metadata_etl/tests/test_help_text.py +387 -0
  426. cumulusci/tasks/metadata_etl/tests/test_ip_ranges.py +85 -0
  427. cumulusci/tasks/metadata_etl/tests/test_layouts.py +858 -0
  428. cumulusci/tasks/metadata_etl/tests/test_objects.py +236 -0
  429. cumulusci/tasks/metadata_etl/tests/test_permissions.py +223 -0
  430. cumulusci/tasks/metadata_etl/tests/test_picklists.py +547 -0
  431. cumulusci/tasks/metadata_etl/tests/test_remote_site_settings.py +46 -0
  432. cumulusci/tasks/metadata_etl/tests/test_sharing.py +333 -0
  433. cumulusci/tasks/metadata_etl/tests/test_value_sets.py +298 -0
  434. cumulusci/tasks/metadata_etl/value_sets.py +106 -0
  435. cumulusci/tasks/metadeploy.py +393 -0
  436. cumulusci/tasks/metaxml.py +88 -0
  437. cumulusci/tasks/preflight/__init__.py +0 -0
  438. cumulusci/tasks/preflight/dataset_load.py +49 -0
  439. cumulusci/tasks/preflight/licenses.py +86 -0
  440. cumulusci/tasks/preflight/packages.py +14 -0
  441. cumulusci/tasks/preflight/permsets.py +23 -0
  442. cumulusci/tasks/preflight/recordtypes.py +16 -0
  443. cumulusci/tasks/preflight/retrieve_tasks.py +30 -0
  444. cumulusci/tasks/preflight/settings.py +77 -0
  445. cumulusci/tasks/preflight/sobjects.py +202 -0
  446. cumulusci/tasks/preflight/tests/test_dataset_load.py +85 -0
  447. cumulusci/tasks/preflight/tests/test_licenses.py +174 -0
  448. cumulusci/tasks/preflight/tests/test_packages.py +14 -0
  449. cumulusci/tasks/preflight/tests/test_permset_preflights.py +51 -0
  450. cumulusci/tasks/preflight/tests/test_recordtypes.py +30 -0
  451. cumulusci/tasks/preflight/tests/test_retrieve_tasks.py +62 -0
  452. cumulusci/tasks/preflight/tests/test_settings.py +130 -0
  453. cumulusci/tasks/preflight/tests/test_sobjects.py +231 -0
  454. cumulusci/tasks/push/README.md +59 -0
  455. cumulusci/tasks/push/__init__.py +0 -0
  456. cumulusci/tasks/push/push_api.py +659 -0
  457. cumulusci/tasks/push/pushfails.py +136 -0
  458. cumulusci/tasks/push/tasks.py +476 -0
  459. cumulusci/tasks/push/tests/conftest.py +263 -0
  460. cumulusci/tasks/push/tests/test_push_api.py +951 -0
  461. cumulusci/tasks/push/tests/test_push_tasks.py +659 -0
  462. cumulusci/tasks/release_notes/README.md +63 -0
  463. cumulusci/tasks/release_notes/__init__.py +0 -0
  464. cumulusci/tasks/release_notes/exceptions.py +5 -0
  465. cumulusci/tasks/release_notes/generator.py +137 -0
  466. cumulusci/tasks/release_notes/parser.py +232 -0
  467. cumulusci/tasks/release_notes/provider.py +44 -0
  468. cumulusci/tasks/release_notes/task.py +300 -0
  469. cumulusci/tasks/release_notes/tests/__init__.py +0 -0
  470. cumulusci/tasks/release_notes/tests/change_notes/full/example1.md +17 -0
  471. cumulusci/tasks/release_notes/tests/change_notes/multi/1.txt +1 -0
  472. cumulusci/tasks/release_notes/tests/change_notes/multi/2.txt +1 -0
  473. cumulusci/tasks/release_notes/tests/change_notes/multi/3.txt +1 -0
  474. cumulusci/tasks/release_notes/tests/change_notes/single/1.txt +1 -0
  475. cumulusci/tasks/release_notes/tests/test_generator.py +582 -0
  476. cumulusci/tasks/release_notes/tests/test_parser.py +867 -0
  477. cumulusci/tasks/release_notes/tests/test_provider.py +512 -0
  478. cumulusci/tasks/release_notes/tests/test_task.py +461 -0
  479. cumulusci/tasks/release_notes/tests/utils.py +153 -0
  480. cumulusci/tasks/robotframework/__init__.py +3 -0
  481. cumulusci/tasks/robotframework/debugger/DebugListener.py +100 -0
  482. cumulusci/tasks/robotframework/debugger/__init__.py +10 -0
  483. cumulusci/tasks/robotframework/debugger/model.py +87 -0
  484. cumulusci/tasks/robotframework/debugger/ui.py +259 -0
  485. cumulusci/tasks/robotframework/libdoc.py +269 -0
  486. cumulusci/tasks/robotframework/robotframework.py +392 -0
  487. cumulusci/tasks/robotframework/stylesheet.css +130 -0
  488. cumulusci/tasks/robotframework/template.html +109 -0
  489. cumulusci/tasks/robotframework/tests/TestLibrary.py +18 -0
  490. cumulusci/tasks/robotframework/tests/TestPageObjects.py +31 -0
  491. cumulusci/tasks/robotframework/tests/TestResource.robot +8 -0
  492. cumulusci/tasks/robotframework/tests/failing_tests.robot +16 -0
  493. cumulusci/tasks/robotframework/tests/performance.robot +23 -0
  494. cumulusci/tasks/robotframework/tests/test_browser_proxies.py +137 -0
  495. cumulusci/tasks/robotframework/tests/test_debugger.py +360 -0
  496. cumulusci/tasks/robotframework/tests/test_robot_parallel.py +141 -0
  497. cumulusci/tasks/robotframework/tests/test_robotframework.py +860 -0
  498. cumulusci/tasks/salesforce/BaseRetrieveMetadata.py +58 -0
  499. cumulusci/tasks/salesforce/BaseSalesforceApiTask.py +45 -0
  500. cumulusci/tasks/salesforce/BaseSalesforceMetadataApiTask.py +18 -0
  501. cumulusci/tasks/salesforce/BaseSalesforceTask.py +4 -0
  502. cumulusci/tasks/salesforce/BaseUninstallMetadata.py +41 -0
  503. cumulusci/tasks/salesforce/CreateCommunity.py +124 -0
  504. cumulusci/tasks/salesforce/CreatePackage.py +29 -0
  505. cumulusci/tasks/salesforce/Deploy.py +240 -0
  506. cumulusci/tasks/salesforce/DeployBundles.py +88 -0
  507. cumulusci/tasks/salesforce/DescribeMetadataTypes.py +26 -0
  508. cumulusci/tasks/salesforce/EnsureRecordTypes.py +202 -0
  509. cumulusci/tasks/salesforce/GetInstalledPackages.py +8 -0
  510. cumulusci/tasks/salesforce/ListCommunities.py +40 -0
  511. cumulusci/tasks/salesforce/ListCommunityTemplates.py +19 -0
  512. cumulusci/tasks/salesforce/PublishCommunity.py +62 -0
  513. cumulusci/tasks/salesforce/RetrievePackaged.py +41 -0
  514. cumulusci/tasks/salesforce/RetrieveReportsAndDashboards.py +82 -0
  515. cumulusci/tasks/salesforce/RetrieveUnpackaged.py +36 -0
  516. cumulusci/tasks/salesforce/SOQLQuery.py +39 -0
  517. cumulusci/tasks/salesforce/UninstallLocal.py +15 -0
  518. cumulusci/tasks/salesforce/UninstallLocalBundles.py +28 -0
  519. cumulusci/tasks/salesforce/UninstallLocalNamespacedBundles.py +58 -0
  520. cumulusci/tasks/salesforce/UninstallPackage.py +32 -0
  521. cumulusci/tasks/salesforce/UninstallPackaged.py +56 -0
  522. cumulusci/tasks/salesforce/UpdateAdminProfile.py +8 -0
  523. cumulusci/tasks/salesforce/__init__.py +79 -0
  524. cumulusci/tasks/salesforce/activate_flow.py +74 -0
  525. cumulusci/tasks/salesforce/check_components.py +324 -0
  526. cumulusci/tasks/salesforce/composite.py +142 -0
  527. cumulusci/tasks/salesforce/create_permission_sets.py +35 -0
  528. cumulusci/tasks/salesforce/custom_settings.py +134 -0
  529. cumulusci/tasks/salesforce/custom_settings_wait.py +132 -0
  530. cumulusci/tasks/salesforce/enable_prediction.py +107 -0
  531. cumulusci/tasks/salesforce/insert_record.py +40 -0
  532. cumulusci/tasks/salesforce/install_package_version.py +242 -0
  533. cumulusci/tasks/salesforce/license_preflights.py +8 -0
  534. cumulusci/tasks/salesforce/network_member_group.py +178 -0
  535. cumulusci/tasks/salesforce/nonsourcetracking.py +228 -0
  536. cumulusci/tasks/salesforce/org_settings.py +193 -0
  537. cumulusci/tasks/salesforce/package_upload.py +328 -0
  538. cumulusci/tasks/salesforce/profiles.py +74 -0
  539. cumulusci/tasks/salesforce/promote_package_version.py +376 -0
  540. cumulusci/tasks/salesforce/retrieve_profile.py +195 -0
  541. cumulusci/tasks/salesforce/salesforce_files.py +244 -0
  542. cumulusci/tasks/salesforce/sourcetracking.py +507 -0
  543. cumulusci/tasks/salesforce/tests/__init__.py +3 -0
  544. cumulusci/tasks/salesforce/tests/test_CreateCommunity.py +278 -0
  545. cumulusci/tasks/salesforce/tests/test_CreatePackage.py +22 -0
  546. cumulusci/tasks/salesforce/tests/test_Deploy.py +470 -0
  547. cumulusci/tasks/salesforce/tests/test_DeployBundles.py +76 -0
  548. cumulusci/tasks/salesforce/tests/test_EnsureRecordTypes.py +345 -0
  549. cumulusci/tasks/salesforce/tests/test_ListCommunities.py +84 -0
  550. cumulusci/tasks/salesforce/tests/test_ListCommunityTemplates.py +49 -0
  551. cumulusci/tasks/salesforce/tests/test_PackageUpload.py +547 -0
  552. cumulusci/tasks/salesforce/tests/test_ProfileGrantAllAccess.py +699 -0
  553. cumulusci/tasks/salesforce/tests/test_PublishCommunity.py +181 -0
  554. cumulusci/tasks/salesforce/tests/test_RetrievePackaged.py +24 -0
  555. cumulusci/tasks/salesforce/tests/test_RetrieveReportsAndDashboards.py +56 -0
  556. cumulusci/tasks/salesforce/tests/test_RetrieveUnpackaged.py +21 -0
  557. cumulusci/tasks/salesforce/tests/test_SOQLQuery.py +30 -0
  558. cumulusci/tasks/salesforce/tests/test_UninstallLocal.py +15 -0
  559. cumulusci/tasks/salesforce/tests/test_UninstallLocalBundles.py +19 -0
  560. cumulusci/tasks/salesforce/tests/test_UninstallLocalNamespacedBundles.py +22 -0
  561. cumulusci/tasks/salesforce/tests/test_UninstallPackage.py +19 -0
  562. cumulusci/tasks/salesforce/tests/test_UninstallPackaged.py +66 -0
  563. cumulusci/tasks/salesforce/tests/test_UninstallPackagedIncremental.py +127 -0
  564. cumulusci/tasks/salesforce/tests/test_activate_flow.py +132 -0
  565. cumulusci/tasks/salesforce/tests/test_base_tasks.py +110 -0
  566. cumulusci/tasks/salesforce/tests/test_check_components.py +445 -0
  567. cumulusci/tasks/salesforce/tests/test_composite.py +250 -0
  568. cumulusci/tasks/salesforce/tests/test_create_permission_sets.py +41 -0
  569. cumulusci/tasks/salesforce/tests/test_custom_settings.py +227 -0
  570. cumulusci/tasks/salesforce/tests/test_custom_settings_wait.py +174 -0
  571. cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py +18 -0
  572. cumulusci/tasks/salesforce/tests/test_enable_prediction.py +240 -0
  573. cumulusci/tasks/salesforce/tests/test_insert_record.py +110 -0
  574. cumulusci/tasks/salesforce/tests/test_install_package_version.py +464 -0
  575. cumulusci/tasks/salesforce/tests/test_network_member_group.py +444 -0
  576. cumulusci/tasks/salesforce/tests/test_nonsourcetracking.py +235 -0
  577. cumulusci/tasks/salesforce/tests/test_org_settings.py +407 -0
  578. cumulusci/tasks/salesforce/tests/test_profiles.py +202 -0
  579. cumulusci/tasks/salesforce/tests/test_retrieve_profile.py +287 -0
  580. cumulusci/tasks/salesforce/tests/test_salesforce_files.py +228 -0
  581. cumulusci/tasks/salesforce/tests/test_sourcetracking.py +350 -0
  582. cumulusci/tasks/salesforce/tests/test_trigger_handlers.py +300 -0
  583. cumulusci/tasks/salesforce/tests/test_update_dependencies.py +509 -0
  584. cumulusci/tasks/salesforce/tests/util.py +79 -0
  585. cumulusci/tasks/salesforce/trigger_handlers.py +119 -0
  586. cumulusci/tasks/salesforce/uninstall_packaged_incremental.py +136 -0
  587. cumulusci/tasks/salesforce/update_dependencies.py +290 -0
  588. cumulusci/tasks/salesforce/update_profile.py +339 -0
  589. cumulusci/tasks/salesforce/users/permsets.py +227 -0
  590. cumulusci/tasks/salesforce/users/photos.py +162 -0
  591. cumulusci/tasks/salesforce/users/tests/photo.mock.txt +1 -0
  592. cumulusci/tasks/salesforce/users/tests/test_permsets.py +950 -0
  593. cumulusci/tasks/salesforce/users/tests/test_photos.py +373 -0
  594. cumulusci/tasks/sample_data/capture_sample_data.py +77 -0
  595. cumulusci/tasks/sample_data/load_sample_data.py +85 -0
  596. cumulusci/tasks/sample_data/test_capture_sample_data.py +117 -0
  597. cumulusci/tasks/sample_data/test_load_sample_data.py +121 -0
  598. cumulusci/tasks/sfdx.py +83 -0
  599. cumulusci/tasks/tests/__init__.py +1 -0
  600. cumulusci/tasks/tests/conftest.py +30 -0
  601. cumulusci/tasks/tests/test_command.py +129 -0
  602. cumulusci/tasks/tests/test_connectedapp.py +236 -0
  603. cumulusci/tasks/tests/test_create_package_version.py +847 -0
  604. cumulusci/tasks/tests/test_datadictionary.py +1575 -0
  605. cumulusci/tasks/tests/test_dx_convert_from.py +60 -0
  606. cumulusci/tasks/tests/test_metadeploy.py +624 -0
  607. cumulusci/tasks/tests/test_metaxml.py +99 -0
  608. cumulusci/tasks/tests/test_promote_package_version.py +488 -0
  609. cumulusci/tasks/tests/test_pushfails.py +96 -0
  610. cumulusci/tasks/tests/test_salesforce.py +72 -0
  611. cumulusci/tasks/tests/test_sfdx.py +105 -0
  612. cumulusci/tasks/tests/test_util.py +207 -0
  613. cumulusci/tasks/util.py +261 -0
  614. cumulusci/tasks/vcs/__init__.py +19 -0
  615. cumulusci/tasks/vcs/commit_status.py +58 -0
  616. cumulusci/tasks/vcs/create_commit_status.py +37 -0
  617. cumulusci/tasks/vcs/download_extract.py +199 -0
  618. cumulusci/tasks/vcs/merge.py +298 -0
  619. cumulusci/tasks/vcs/publish.py +207 -0
  620. cumulusci/tasks/vcs/pull_request.py +9 -0
  621. cumulusci/tasks/vcs/release.py +134 -0
  622. cumulusci/tasks/vcs/release_report.py +105 -0
  623. cumulusci/tasks/vcs/tag.py +31 -0
  624. cumulusci/tasks/vcs/tests/github/test_commit_status.py +196 -0
  625. cumulusci/tasks/vcs/tests/github/test_download_extract.py +896 -0
  626. cumulusci/tasks/vcs/tests/github/test_merge.py +1118 -0
  627. cumulusci/tasks/vcs/tests/github/test_publish.py +823 -0
  628. cumulusci/tasks/vcs/tests/github/test_pull_request.py +29 -0
  629. cumulusci/tasks/vcs/tests/github/test_release.py +390 -0
  630. cumulusci/tasks/vcs/tests/github/test_release_report.py +109 -0
  631. cumulusci/tasks/vcs/tests/github/test_tag.py +90 -0
  632. cumulusci/tasks/vlocity/exceptions.py +2 -0
  633. cumulusci/tasks/vlocity/tests/test_vlocity.py +283 -0
  634. cumulusci/tasks/vlocity/vlocity.py +342 -0
  635. cumulusci/tests/__init__.py +1 -0
  636. cumulusci/tests/cassettes/GET_sobjects_Account_PersonAccount_describe.yaml +18 -0
  637. cumulusci/tests/cassettes/TestIntegrationInfrastructure.test_integration_tests.yaml +19 -0
  638. cumulusci/tests/pytest_plugins/pytest_sf_orgconnect.py +307 -0
  639. cumulusci/tests/pytest_plugins/pytest_sf_vcr.py +275 -0
  640. cumulusci/tests/pytest_plugins/pytest_sf_vcr_serializer.py +160 -0
  641. cumulusci/tests/pytest_plugins/pytest_typeguard.py +5 -0
  642. cumulusci/tests/pytest_plugins/test_vcr_string_compressor.py +49 -0
  643. cumulusci/tests/pytest_plugins/vcr_string_compressor.py +97 -0
  644. cumulusci/tests/shared_cassettes/GET_sobjects_Account_describe.yaml +18 -0
  645. cumulusci/tests/shared_cassettes/GET_sobjects_Case_describe.yaml +18 -0
  646. cumulusci/tests/shared_cassettes/GET_sobjects_Contact_describe.yaml +4838 -0
  647. cumulusci/tests/shared_cassettes/GET_sobjects_Custom__c_describe.yaml +242 -0
  648. cumulusci/tests/shared_cassettes/GET_sobjects_Event_describe.yaml +19 -0
  649. cumulusci/tests/shared_cassettes/GET_sobjects_Global_describe.yaml +1338 -0
  650. cumulusci/tests/shared_cassettes/GET_sobjects_Lead_describe.yaml +18 -0
  651. cumulusci/tests/shared_cassettes/GET_sobjects_OpportunityContactRole_describe.yaml +34 -0
  652. cumulusci/tests/shared_cassettes/GET_sobjects_Opportunity_describe.yaml +1261 -0
  653. cumulusci/tests/shared_cassettes/GET_sobjects_Organization.yaml +49 -0
  654. cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfoList_xml.tpl +15 -0
  655. cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfo_xml.tpl +13 -0
  656. cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_insert_xml.tpl +24 -0
  657. cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_upsert_xml.tpl +25 -0
  658. cumulusci/tests/test_entry_points.py +20 -0
  659. cumulusci/tests/test_integration_infrastructure.py +131 -0
  660. cumulusci/tests/test_main.py +9 -0
  661. cumulusci/tests/test_schema.py +32 -0
  662. cumulusci/tests/test_utils.py +657 -0
  663. cumulusci/tests/test_vcr_serializer.py +134 -0
  664. cumulusci/tests/uncompressed_cassette.yaml +83 -0
  665. cumulusci/tests/util.py +344 -0
  666. cumulusci/utils/__init__.py +731 -0
  667. cumulusci/utils/classutils.py +9 -0
  668. cumulusci/utils/collections.py +32 -0
  669. cumulusci/utils/deprecation.py +11 -0
  670. cumulusci/utils/encryption.py +31 -0
  671. cumulusci/utils/fileutils.py +295 -0
  672. cumulusci/utils/git.py +142 -0
  673. cumulusci/utils/http/multi_request.py +214 -0
  674. cumulusci/utils/http/requests_utils.py +103 -0
  675. cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +32 -0
  676. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_composite_parallel_salesforce.yaml +65 -0
  677. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_errors.yaml +24 -0
  678. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_reference_ids.yaml +49 -0
  679. cumulusci/utils/http/tests/test_multi_request.py +255 -0
  680. cumulusci/utils/iterators.py +21 -0
  681. cumulusci/utils/logging.py +128 -0
  682. cumulusci/utils/metaprogramming.py +10 -0
  683. cumulusci/utils/options.py +138 -0
  684. cumulusci/utils/parallel/queries_in_parallel/run_queries_in_parallel.py +29 -0
  685. cumulusci/utils/parallel/queries_in_parallel/tests/test_run_queries_in_parallel.py +50 -0
  686. cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +238 -0
  687. cumulusci/utils/parallel/task_worker_queues/parallel_worker_queue.py +243 -0
  688. cumulusci/utils/parallel/task_worker_queues/tests/test_parallel_worker.py +353 -0
  689. cumulusci/utils/salesforce/count_sobjects.py +46 -0
  690. cumulusci/utils/salesforce/soql.py +17 -0
  691. cumulusci/utils/salesforce/tests/cassettes/ManualEdit_TestCountSObjects.test_count_sobjects__network_errors.yaml +23 -0
  692. cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects__errors.yaml +33 -0
  693. cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects_simple.yaml +29 -0
  694. cumulusci/utils/salesforce/tests/test_count_sobjects.py +29 -0
  695. cumulusci/utils/salesforce/tests/test_soql.py +30 -0
  696. cumulusci/utils/tests/cassettes/ManualEditTestDescribeOrg.test_minimal_schema.yaml +36 -0
  697. cumulusci/utils/tests/cassettes/ManualEdit_test_describe_to_sql.yaml +191 -0
  698. cumulusci/utils/tests/test_fileutils.py +284 -0
  699. cumulusci/utils/tests/test_git.py +85 -0
  700. cumulusci/utils/tests/test_logging.py +70 -0
  701. cumulusci/utils/tests/test_option_parsing.py +188 -0
  702. cumulusci/utils/tests/test_org_schema.py +691 -0
  703. cumulusci/utils/tests/test_org_schema_models.py +79 -0
  704. cumulusci/utils/tests/test_waiting.py +25 -0
  705. cumulusci/utils/version_strings.py +391 -0
  706. cumulusci/utils/waiting.py +42 -0
  707. cumulusci/utils/xml/__init__.py +91 -0
  708. cumulusci/utils/xml/metadata_tree.py +299 -0
  709. cumulusci/utils/xml/robot_xml.py +114 -0
  710. cumulusci/utils/xml/salesforce_encoding.py +100 -0
  711. cumulusci/utils/xml/test/test_metadata_tree.py +251 -0
  712. cumulusci/utils/xml/test/test_salesforce_encoding.py +173 -0
  713. cumulusci/utils/yaml/cumulusci_yml.py +401 -0
  714. cumulusci/utils/yaml/model_parser.py +156 -0
  715. cumulusci/utils/yaml/safer_loader.py +74 -0
  716. cumulusci/utils/yaml/tests/bad_cci.yml +5 -0
  717. cumulusci/utils/yaml/tests/cassettes/TestCumulusciYml.test_validate_url__with_errors.yaml +20 -0
  718. cumulusci/utils/yaml/tests/test_cumulusci_yml.py +286 -0
  719. cumulusci/utils/yaml/tests/test_model_parser.py +175 -0
  720. cumulusci/utils/yaml/tests/test_safer_loader.py +88 -0
  721. cumulusci/utils/ziputils.py +61 -0
  722. cumulusci/vcs/base.py +143 -0
  723. cumulusci/vcs/bootstrap.py +272 -0
  724. cumulusci/vcs/github/__init__.py +24 -0
  725. cumulusci/vcs/github/adapter.py +689 -0
  726. cumulusci/vcs/github/release_notes/generator.py +219 -0
  727. cumulusci/vcs/github/release_notes/parser.py +151 -0
  728. cumulusci/vcs/github/release_notes/provider.py +143 -0
  729. cumulusci/vcs/github/service.py +569 -0
  730. cumulusci/vcs/github/tests/test_adapter.py +138 -0
  731. cumulusci/vcs/github/tests/test_service.py +408 -0
  732. cumulusci/vcs/models.py +586 -0
  733. cumulusci/vcs/tests/conftest.py +41 -0
  734. cumulusci/vcs/tests/dummy_service.py +241 -0
  735. cumulusci/vcs/tests/test_vcs_base.py +687 -0
  736. cumulusci/vcs/tests/test_vcs_bootstrap.py +727 -0
  737. cumulusci/vcs/utils/__init__.py +31 -0
  738. cumulusci/vcs/vcs_source.py +287 -0
  739. cumulusci_plus-5.0.0.dist-info/METADATA +145 -0
  740. cumulusci_plus-5.0.0.dist-info/RECORD +744 -0
  741. cumulusci_plus-5.0.0.dist-info/WHEEL +4 -0
  742. cumulusci_plus-5.0.0.dist-info/entry_points.txt +3 -0
  743. cumulusci_plus-5.0.0.dist-info/licenses/AUTHORS.rst +41 -0
  744. cumulusci_plus-5.0.0.dist-info/licenses/LICENSE +30 -0
@@ -0,0 +1,721 @@
1
+ """
2
+ python interface to the Salesforce Metadata API
3
+ based on mrbelvedere/mpinstaller/mdapi.py
4
+ """
5
+
6
+ # TO DO
7
+ # - add docstrings
8
+ # - look at https://github.com/rholder/retrying
9
+
10
+ import base64
11
+ import http.client
12
+ import io
13
+ import re
14
+ import time
15
+ from collections import defaultdict
16
+ from xml.sax.saxutils import escape
17
+ from zipfile import ZipFile
18
+
19
+ import requests
20
+ from defusedxml.minidom import parseString
21
+ from requests.adapters import HTTPAdapter
22
+ from requests.packages.urllib3.util.retry import Retry
23
+
24
+ from cumulusci.core.exceptions import ApexTestException, CumulusCIException
25
+ from cumulusci.salesforce_api import soap_envelopes
26
+ from cumulusci.salesforce_api.exceptions import (
27
+ MetadataApiError,
28
+ MetadataComponentFailure,
29
+ MetadataParseError,
30
+ )
31
+ from cumulusci.utils import parse_api_datetime, zip_subfolder
32
+
33
+ # If pyOpenSSL is installed, make sure it's not used for requests
34
+ # (it's not needed in the verisons of Python we support)
35
+ try:
36
+ from urllib3.contrib import pyopenssl
37
+ except ImportError:
38
+ pass
39
+ else:
40
+ pyopenssl.extract_from_urllib3()
41
+
42
+ INVALID_CROSS_REF_ERROR = "INVALID_CROSS_REFERENCE_KEY: No package named"
43
+
44
+ retry_policy = Retry(backoff_factor=0.3)
45
+
46
+
47
+ class BaseMetadataApiCall(object):
48
+ check_interval = 1
49
+ soap_envelope_start = None
50
+ soap_envelope_status = None
51
+ soap_envelope_result = None
52
+ soap_action_start = None
53
+ soap_action_status = None
54
+ soap_action_result = None
55
+
56
+ def __init__(self, task, api_version=None):
57
+ # the cumulusci context object contains logger, oauth, ID, secret, etc
58
+ self.task = task
59
+ self.status = None
60
+ self.check_num = 1
61
+ self.api_version = (
62
+ api_version
63
+ if api_version
64
+ else task.project_config.project__package__api_version
65
+ )
66
+
67
+ def __call__(self):
68
+ self.task.logger.info("Pending")
69
+ response = self._get_response()
70
+ if self.status != "Failed":
71
+ try:
72
+ return self._process_response(response)
73
+ except Exception as e:
74
+ raise MetadataParseError(
75
+ f"Could not process MDAPI response: {str(e)}", response=response
76
+ )
77
+ else:
78
+ raise MetadataApiError(response.text, response)
79
+
80
+ def _build_endpoint_url(self):
81
+ org_id = self.task.org_config.org_id
82
+ instance_url = self.task.org_config.instance_url
83
+ endpoint = f"{instance_url}/services/Soap/m/{self.api_version}/{org_id}"
84
+ return endpoint
85
+
86
+ def _build_envelope_result(self):
87
+ if self.soap_envelope_result:
88
+ return self.soap_envelope_result.format(process_id=self.process_id)
89
+
90
+ def _build_envelope_start(self):
91
+ assert self.soap_envelope_start, "soap_envelope_start should be supplied"
92
+ return self.soap_envelope_start.format(api_version=self.api_version)
93
+
94
+ def _build_envelope_status(self):
95
+ if self.soap_envelope_status:
96
+ return self.soap_envelope_status.format(process_id=self.process_id)
97
+
98
+ def _build_headers(self, action, message):
99
+ return {
100
+ "Content-Type": "text/xml; charset=UTF-8",
101
+ "Content-Length": str(len(message)),
102
+ "SOAPAction": action,
103
+ }
104
+
105
+ def _call_mdapi(self, headers, envelope, refresh=None):
106
+ # Insert the session id
107
+ session_id = self.task.org_config.access_token
108
+ auth_envelope = envelope.replace("###SESSION_ID###", session_id)
109
+ session = requests.Session()
110
+ http_adapter = HTTPAdapter(max_retries=retry_policy)
111
+ session.mount("https://", http_adapter)
112
+ response = session.post(
113
+ self._build_endpoint_url(),
114
+ headers=headers,
115
+ data=auth_envelope.encode("utf-8"),
116
+ )
117
+ faultcode = parseString(response.content).getElementsByTagName("faultcode")
118
+ # refresh = False can be passed to prevent a loop if refresh fails
119
+ if refresh is None:
120
+ refresh = True
121
+ if faultcode:
122
+ return self._handle_soap_error(headers, envelope, refresh, response)
123
+ return response
124
+
125
+ def _get_element_value(self, dom, tag):
126
+ result = dom.getElementsByTagName(tag)
127
+ if result and result[0].firstChild:
128
+ return result[0].firstChild.nodeValue
129
+
130
+ def _get_check_interval(self):
131
+ return self.check_interval * ((self.check_num // 3) + 1)
132
+
133
+ def _get_response(self):
134
+ if not self.soap_envelope_start:
135
+ raise NotImplementedError("No soap_start template was provided")
136
+ # Start the call
137
+ envelope = self._build_envelope_start()
138
+ headers = self._build_headers(self.soap_action_start, envelope)
139
+ response = self._call_mdapi(headers, envelope)
140
+ # If no status envelope is configured, return the response directly
141
+ if not self.soap_envelope_status:
142
+ return response
143
+ # Process the response to set self.process_id with the process id
144
+ # started
145
+ response = self._process_response_start(response)
146
+ # Check the status if configured
147
+ if self.soap_envelope_status:
148
+ while self.status not in ["Done", "Failed"]:
149
+ # Check status in a loop until done
150
+ envelope = self._build_envelope_status()
151
+ headers = self._build_headers(self.soap_action_status, envelope)
152
+ response = self._call_mdapi(headers, envelope)
153
+ response = self._process_response_status(response)
154
+
155
+ # start increasing the check interval progressively to handle long pending jobs
156
+ check_interval = self._get_check_interval()
157
+ self.check_num += 1
158
+
159
+ time.sleep(check_interval)
160
+ # Fetch the final result and return
161
+ if self.soap_envelope_result:
162
+ envelope = self._build_envelope_result()
163
+ headers = self._build_headers(self.soap_action_result, envelope)
164
+ response = self._call_mdapi(headers, envelope)
165
+ else:
166
+ return response
167
+ return response
168
+
169
+ def _handle_soap_error(self, headers, envelope, refresh, response):
170
+ resp_xml = parseString(response.content)
171
+ faultcode = resp_xml.getElementsByTagName("faultcode")
172
+ if faultcode:
173
+ faultcode = faultcode[0].firstChild.nodeValue
174
+ faultstring = resp_xml.getElementsByTagName("faultstring")
175
+ if faultstring:
176
+ faultstring = faultstring[0].firstChild.nodeValue
177
+ else:
178
+ faultstring = response.text
179
+ if (
180
+ faultcode == "sf:INVALID_SESSION_ID"
181
+ and self.task.org_config
182
+ and self.task.org_config.refresh_token
183
+ ):
184
+ # Attempt to refresh token and recall request
185
+ if refresh:
186
+ self.task.org_config.refresh_oauth_token(
187
+ self.task.project_config.keychain
188
+ )
189
+ return self._call_mdapi(headers, envelope, refresh=False)
190
+ # Log the error
191
+ message = f"{faultcode}: {faultstring}"
192
+ self._set_status("Failed", message)
193
+ raise MetadataApiError(message, response)
194
+
195
+ def _process_response(self, response):
196
+ return response.text
197
+
198
+ def _process_response_start(self, response):
199
+ if response.status_code == http.client.INTERNAL_SERVER_ERROR:
200
+ raise MetadataApiError(
201
+ f"HTTP ERROR {response.status_code}: {response.text}", response
202
+ )
203
+ ids = parseString(response.content).getElementsByTagName("id")
204
+ if ids:
205
+ self.process_id = ids[0].firstChild.nodeValue
206
+ return response
207
+
208
+ def _process_response_status(self, response):
209
+ if response.status_code == http.client.INTERNAL_SERVER_ERROR:
210
+ raise MetadataApiError(
211
+ "HTTP ERROR {}: {}".format(response.status_code, response.text),
212
+ response,
213
+ )
214
+ resp_xml = parseString(response.content)
215
+ done = resp_xml.getElementsByTagName("done")
216
+ if done:
217
+ if done[0].firstChild.nodeValue == "true":
218
+ errorMessage = resp_xml.getElementsByTagName("errorMessage")
219
+ if errorMessage:
220
+ self._set_status(
221
+ "Failed",
222
+ errorMessage[0].firstChild.nodeValue,
223
+ response=response,
224
+ )
225
+ else:
226
+ self._set_status("Done")
227
+ else:
228
+ state_detail = resp_xml.getElementsByTagName("stateDetail")
229
+ if state_detail:
230
+ log = state_detail[0].firstChild.nodeValue
231
+ self._set_status("InProgress", log)
232
+ self.check_num = 1
233
+ elif self.status == "InProgress":
234
+ self.check_num = 1
235
+ self._set_status(
236
+ "InProgress",
237
+ f"next check in {self._get_check_interval()} seconds",
238
+ )
239
+ else:
240
+ self._set_status(
241
+ "Pending", f"next check in {self._get_check_interval()} seconds"
242
+ )
243
+ else:
244
+ # If no done element was in the xml, fail logging the entire SOAP
245
+ # envelope as the log
246
+ self._set_status("Failed", response.text, response=response)
247
+ return response
248
+
249
+ def _set_status(self, status, log=None, level=None, response=None):
250
+ if not level:
251
+ level = "info"
252
+ if status == "Failed":
253
+ level = "error"
254
+ logger = getattr(self.task.logger, level)
255
+ self.status = status
256
+ if log:
257
+ logger(f"[{status}]: {log}")
258
+ else:
259
+ logger(f"[{status}]")
260
+
261
+
262
+ class ApiRetrieveUnpackaged(BaseMetadataApiCall):
263
+ check_interval = 1
264
+ soap_envelope_start = soap_envelopes.RETRIEVE_UNPACKAGED
265
+ soap_envelope_status = soap_envelopes.CHECK_STATUS
266
+ soap_envelope_result = soap_envelopes.CHECK_RETRIEVE_STATUS
267
+ soap_action_start = "retrieve"
268
+ soap_action_status = "checkStatus"
269
+ soap_action_result = "checkRetrieveStatus"
270
+
271
+ def __init__(self, task, package_xml, api_version):
272
+ super(ApiRetrieveUnpackaged, self).__init__(task, api_version)
273
+ self.package_xml = package_xml
274
+ self._clean_package_xml()
275
+
276
+ def _clean_package_xml(self):
277
+ self.package_xml = re.sub(r"<\?xml.*\?>", "", self.package_xml)
278
+ self.package_xml = re.sub("<Package.*>", "", self.package_xml, count=1)
279
+ self.package_xml = re.sub("</Package>", "", self.package_xml, count=1)
280
+ self.package_xml = re.sub("\n", "", self.package_xml)
281
+ self.package_xml = re.sub(" +<", "<", self.package_xml)
282
+
283
+ def _build_envelope_start(self):
284
+ return self.soap_envelope_start.format(
285
+ api_version=self.api_version, package_xml=self.package_xml
286
+ )
287
+
288
+ def _process_response(self, response):
289
+ # Parse the metadata zip file from the response
290
+ zipstr = parseString(response.content).getElementsByTagName("zipFile")
291
+ if zipstr:
292
+ zipstr = zipstr[0].firstChild.nodeValue
293
+ zipstringio = io.BytesIO(base64.b64decode(zipstr))
294
+ zipfile = ZipFile(zipstringio, "r")
295
+ zipfile = zip_subfolder(zipfile, "unpackaged")
296
+ return zipfile
297
+
298
+
299
+ class ApiRetrieveInstalledPackages(BaseMetadataApiCall):
300
+ check_interval = 1
301
+ soap_envelope_start = soap_envelopes.RETRIEVE_INSTALLEDPACKAGE
302
+ soap_envelope_status = soap_envelopes.CHECK_STATUS
303
+ soap_envelope_result = soap_envelopes.CHECK_RETRIEVE_STATUS
304
+ soap_action_start = "retrieve"
305
+ soap_action_status = "checkStatus"
306
+ soap_action_result = "checkRetrieveStatus"
307
+
308
+ def __init__(self, task, api_version=None):
309
+ super(ApiRetrieveInstalledPackages, self).__init__(task, api_version)
310
+ self.packages = {}
311
+
312
+ def _process_response(self, response):
313
+ # Parse the metadata zip file from the response
314
+ zipstr = parseString(response.content).getElementsByTagName("zipFile")
315
+ if zipstr:
316
+ zipstr = zipstr[0].firstChild.nodeValue
317
+ else:
318
+ return self.packages
319
+ zipstringio = io.BytesIO(base64.b64decode(zipstr))
320
+ zipfile = ZipFile(zipstringio, "r")
321
+ # Loop through all files in the zip skipping anything other than
322
+ # InstalledPackages
323
+ for path in zipfile.namelist():
324
+ if not path.endswith(".installedPackage"):
325
+ continue
326
+ namespace = path.split("/")[-1].split(".")[0]
327
+ version = parseString(zipfile.open(path).read()).getElementsByTagName(
328
+ "versionNumber"
329
+ )
330
+ if version:
331
+ version = version[0].firstChild.nodeValue
332
+ self.packages[namespace] = version
333
+ return self.packages
334
+
335
+
336
+ class ApiRetrievePackaged(BaseMetadataApiCall):
337
+ check_interval = 1
338
+ soap_envelope_start = soap_envelopes.RETRIEVE_PACKAGED
339
+ soap_envelope_status = soap_envelopes.CHECK_STATUS
340
+ soap_envelope_result = soap_envelopes.CHECK_RETRIEVE_STATUS
341
+ soap_action_start = "retrieve"
342
+ soap_action_status = "checkStatus"
343
+ soap_action_result = "checkRetrieveStatus"
344
+
345
+ def __init__(self, task, package_name, api_version):
346
+ super(ApiRetrievePackaged, self).__init__(task, api_version)
347
+ self.package_name = package_name
348
+
349
+ def _build_envelope_start(self):
350
+ return self.soap_envelope_start.format(
351
+ api_version=self.api_version, package_name=escape(self.package_name)
352
+ )
353
+
354
+ def _process_response(self, response):
355
+ if INVALID_CROSS_REF_ERROR in response.content.decode("utf-8"):
356
+ raise CumulusCIException(
357
+ f"No package found in org with name: {self.package_name}"
358
+ )
359
+
360
+ # Parse the metadata zip file from the response
361
+ zipstr = parseString(response.content).getElementsByTagName("zipFile")
362
+ if zipstr:
363
+ zipstr = zipstr[0].firstChild.nodeValue
364
+ zipstringio = io.BytesIO(base64.b64decode(zipstr))
365
+ zipfile = ZipFile(zipstringio, "r")
366
+ return zipfile
367
+
368
+
369
+ class ApiDeploy(BaseMetadataApiCall):
370
+ soap_envelope_start = soap_envelopes.DEPLOY
371
+ soap_envelope_status = soap_envelopes.CHECK_DEPLOY_STATUS
372
+ soap_action_start = "deploy"
373
+ soap_action_status = "checkDeployStatus"
374
+
375
+ def __init__(
376
+ self,
377
+ task,
378
+ package_zip,
379
+ purge_on_delete=None,
380
+ api_version=None,
381
+ check_only=False,
382
+ test_level=None,
383
+ run_tests=None,
384
+ ):
385
+ super(ApiDeploy, self).__init__(task, api_version)
386
+ assert package_zip, "Package zip should not be None"
387
+ if purge_on_delete is None:
388
+ purge_on_delete = True
389
+ self._set_purge_on_delete(purge_on_delete)
390
+ self.check_only = "true" if check_only else "false"
391
+ self.test_level = test_level
392
+ self.package_zip = package_zip
393
+ self.run_tests = run_tests or []
394
+
395
+ def _set_purge_on_delete(self, purge_on_delete):
396
+ if not purge_on_delete or purge_on_delete == "false":
397
+ self.purge_on_delete = "false"
398
+ else:
399
+ self.purge_on_delete = "true"
400
+ # Disable purge on delete entirely for non sandbox or DE orgs as it is
401
+ # not allowed
402
+ org_type = self.task.org_config.org_type
403
+ is_sandbox = self.task.org_config.is_sandbox
404
+ if org_type != "Developer Edition" and not is_sandbox:
405
+ self.purge_on_delete = "false"
406
+
407
+ def _build_envelope_start(self):
408
+ test_level = (
409
+ f"<testLevel>{self.test_level}</testLevel>" if self.test_level else ""
410
+ )
411
+ run_tests = (
412
+ "\n".join(f"<runTests>{x}</runTests>" for x in self.run_tests)
413
+ if self.test_level == "RunSpecifiedTests"
414
+ else ""
415
+ )
416
+ return self.soap_envelope_start.format(
417
+ package_zip=self.package_zip,
418
+ check_only=self.check_only,
419
+ purge_on_delete=self.purge_on_delete,
420
+ test_level=test_level,
421
+ run_tests=run_tests,
422
+ api_version=self.api_version,
423
+ )
424
+
425
+ def _process_response(self, response):
426
+ resp_xml = parseString(response.content)
427
+ status = resp_xml.getElementsByTagName("status")
428
+ if status:
429
+ status = status[0].firstChild.nodeValue
430
+ else:
431
+ # If no status element is in the result xml, return fail and log
432
+ # the entire SOAP envelope in the log
433
+ self._set_status("Failed", response.text)
434
+ return self.status
435
+ # Only done responses should be passed so we need to handle any status
436
+ # related to done
437
+ if status in ["Succeeded", "SucceededPartial"]:
438
+ self._set_status("Success", status)
439
+ else:
440
+ # If failed, parse out the problem text and raise appropriate exception
441
+ messages = []
442
+
443
+ component_failures = resp_xml.getElementsByTagName("componentFailures")
444
+ for component_failure in component_failures:
445
+ problems = component_failure.getElementsByTagName("problem")
446
+ problem_types = component_failure.getElementsByTagName("problemType")
447
+ failure_info = {
448
+ "component_type": None,
449
+ "file_name": None,
450
+ "line_num": None,
451
+ "column_num": None,
452
+ "problem": problems[0].firstChild.nodeValue
453
+ if problems
454
+ else "Unknown problem",
455
+ "problem_type": problem_types[0].firstChild.nodeValue
456
+ if problem_types
457
+ else "Error",
458
+ }
459
+ failure_info["component_type"] = self._get_element_value(
460
+ component_failure, "componentType"
461
+ )
462
+ full_name = self._get_element_value(component_failure, "fullName")
463
+ file_name = self._get_element_value(component_failure, "fileName")
464
+ failure_info["file_name"] = full_name or file_name
465
+ failure_info["line_num"] = self._get_element_value(
466
+ component_failure, "lineNumber"
467
+ )
468
+ failure_info["column_num"] = self._get_element_value(
469
+ component_failure, "columnNumber"
470
+ )
471
+
472
+ created = (
473
+ component_failure.getElementsByTagName("created")[
474
+ 0
475
+ ].firstChild.nodeValue
476
+ == "true"
477
+ )
478
+ deleted = (
479
+ component_failure.getElementsByTagName("deleted")[
480
+ 0
481
+ ].firstChild.nodeValue
482
+ == "true"
483
+ )
484
+ failure_info["action"] = self._get_action(created, deleted)
485
+
486
+ if failure_info["file_name"] and failure_info["line_num"]:
487
+ messages.append(
488
+ "{action} of {component_type} {file_name}: {problem_type} on line {line_num}, col {column_num}: {problem}".format(
489
+ **failure_info
490
+ )
491
+ )
492
+ elif failure_info["file_name"]:
493
+ messages.append(
494
+ "{action} of {component_type} {file_name}: {problem_type}: {problem}".format(
495
+ **failure_info
496
+ )
497
+ )
498
+ else:
499
+ messages.append(
500
+ "{action} of {component_type}: {problem_type}: {problem}".format(
501
+ **failure_info
502
+ )
503
+ )
504
+
505
+ if messages:
506
+ # Deploy failures due to a component failure should raise MetadataComponentFailure
507
+ log = "\n\n".join(messages)
508
+ self._set_status("Failed", log)
509
+ raise MetadataComponentFailure(log, response)
510
+
511
+ else:
512
+ problems = resp_xml.getElementsByTagName("problem")
513
+ for problem in problems:
514
+ messages.append(problem.firstChild.nodeValue)
515
+ errorMessages = resp_xml.getElementsByTagName("errorMessage")
516
+ for errorMessage in errorMessages:
517
+ messages.append(errorMessage.firstChild.nodeValue)
518
+ if messages:
519
+ log = "\n\n".join(messages)
520
+ raise MetadataApiError(log, response)
521
+
522
+ # Parse out any failure text (from test failures in production
523
+ # deployments) and add to log
524
+ failures = resp_xml.getElementsByTagName("failures")
525
+ for failure in failures:
526
+ # Get needed values from subelements
527
+ namespace = self._get_element_value(failure, "namespace")
528
+ stacktrace = self._get_element_value(failure, "stackTrace")
529
+ message = ["Apex Test Failure: "]
530
+ if namespace:
531
+ message.append(f"from namespace {namespace}: ")
532
+ if stacktrace:
533
+ message.append(stacktrace)
534
+ messages.append("".join(message))
535
+
536
+ if messages:
537
+ # Deploy failures due to a component failure should raise MetadataComponentFailure
538
+ log = "\n\n".join(messages)
539
+ self._set_status("Failed", log)
540
+ raise ApexTestException(log)
541
+ else:
542
+ log = response.text
543
+ self._set_status("Failed", log)
544
+ raise MetadataApiError(log, response)
545
+
546
+ return self.status
547
+
548
+ def _get_action(self, created, deleted):
549
+ if created:
550
+ return "Create"
551
+ elif deleted:
552
+ return "Delete"
553
+ return "Update"
554
+
555
+
556
+ class ApiListMetadata(BaseMetadataApiCall):
557
+ soap_envelope_start = soap_envelopes.LIST_METADATA
558
+ soap_action_start = "listMetadata"
559
+
560
+ def __init__(
561
+ self, task, metadata_type, metadata=None, folder=None, as_of_version=None
562
+ ):
563
+ super(ApiListMetadata, self).__init__(task)
564
+ self.metadata_type = metadata_type
565
+ self.metadata = metadata
566
+ self.folder = folder
567
+ self.as_of_version = (
568
+ as_of_version
569
+ if as_of_version
570
+ else task.project_config.project__package__api_version
571
+ )
572
+ self.api_version = self.as_of_version
573
+ if self.metadata is None:
574
+ self.metadata = defaultdict(list)
575
+
576
+ def _build_envelope_start(self):
577
+ folder = self.folder
578
+ folder = f"\n <folder>{folder}</folder>" if folder is not None else ""
579
+ return self.soap_envelope_start.format(
580
+ metadata_type=self.metadata_type,
581
+ folder=folder,
582
+ as_of_version=self.as_of_version,
583
+ )
584
+
585
+ def _process_response(self, response):
586
+ metadata = []
587
+ tags = [
588
+ "createdById",
589
+ "createdByName",
590
+ "createdDate",
591
+ "fileName",
592
+ "fullName",
593
+ "id",
594
+ "lastModifiedById",
595
+ "lastModifiedByName",
596
+ "lastModifiedDate",
597
+ "manageableState",
598
+ "namespacePrefix",
599
+ "type",
600
+ ]
601
+ # These tags will be interpreted into dates
602
+ parse_dates = ["createdDate", "lastModifiedDate"]
603
+ for result in parseString(response.content).getElementsByTagName("result"):
604
+ result_data = {}
605
+ # Parse fields
606
+ for tag in tags:
607
+ result_data[tag] = self._get_element_value(result, tag)
608
+ # Parse dates
609
+ for key in parse_dates:
610
+ if result_data[key]:
611
+ try:
612
+ result_data[key] = parse_api_datetime(result_data[key])
613
+ except Exception as e:
614
+ raise MetadataParseError(
615
+ f"Could not parse a datetime in the MDAPI response: {str(e)}, {str(result)}",
616
+ response=response,
617
+ )
618
+ metadata.append(result_data)
619
+ self.metadata[self.metadata_type].extend(metadata)
620
+ return self.metadata
621
+
622
+
623
+ class ApiNewProfile(BaseMetadataApiCall):
624
+ check_interval = 1
625
+ soap_envelope_start = soap_envelopes.CREATE_PROFILE
626
+ soap_action_start = "create"
627
+ API_VERSION = "53.0"
628
+
629
+ def __init__(
630
+ self,
631
+ task,
632
+ api_version=None,
633
+ name: str = "",
634
+ description: str = "",
635
+ license_id: str = "",
636
+ ):
637
+ super(ApiNewProfile, self).__init__(task, api_version)
638
+
639
+ self.name = name
640
+ self.description = description
641
+ self.license_id = license_id
642
+
643
+ if int(float(self.api_version)) < 53:
644
+ raise MetadataApiError(
645
+ "Creating a blank profile via this API requires a Winter '22 org or later.",
646
+ None,
647
+ )
648
+
649
+ def _build_endpoint_url(self):
650
+ org_id = self.task.org_config.org_id
651
+ instance_url = self.task.org_config.instance_url
652
+ # Overwrite to call the Partner WSDL endpoint
653
+ endpoint = f"{instance_url}/services/Soap/u/{self.API_VERSION}/{org_id}"
654
+ return endpoint
655
+
656
+ def _build_envelope_start(self):
657
+ return self.soap_envelope_start.format(
658
+ name=escape(self.name),
659
+ description=escape(self.description),
660
+ license_id=escape(self.license_id),
661
+ )
662
+
663
+ def _process_response(self, response):
664
+ resp_xml = parseString(response.content)
665
+ # Return id of newly created profile.
666
+ profile_id_text = resp_xml.getElementsByTagName("id")[0].firstChild
667
+ if profile_id_text:
668
+ return profile_id_text.nodeValue
669
+ # Handle errors
670
+ errors = resp_xml.getElementsByTagName("errors")
671
+ if errors:
672
+ raise MetadataApiError(
673
+ "\n".join(
674
+ node.getElementsByTagName("message")[0].firstChild.nodeValue
675
+ for node in errors
676
+ ),
677
+ response,
678
+ )
679
+ # Unknown response
680
+ raise MetadataApiError(f"Unexpected response: {response.text}", response)
681
+
682
+
683
+ class ApiListMetadataTypes(BaseMetadataApiCall):
684
+ check_interval = 1
685
+ soap_envelope_start = soap_envelopes.DESCRIBE_METADATA
686
+ soap_action_start = "describemetadatatypes"
687
+
688
+ def __init__(self, task, api_version=None):
689
+ super(ApiListMetadataTypes, self).__init__(task)
690
+ self.metadata_types = []
691
+ self.api_version = (
692
+ api_version
693
+ if api_version
694
+ else task.project_config.project__package__api_version
695
+ )
696
+
697
+ def _build_envelope_start(self):
698
+
699
+ return self.soap_envelope_start.format(
700
+ api_version=self.api_version,
701
+ )
702
+
703
+ def _process_response(self, response):
704
+ self.metadata_types = []
705
+ metaobjects = parseString(response.content).getElementsByTagName(
706
+ "metadataObjects"
707
+ )
708
+
709
+ for metadataobject in metaobjects:
710
+ self.metadata_types.append(
711
+ self._get_element_value(metadataobject, "xmlName")
712
+ )
713
+ child_elements = metadataobject.getElementsByTagName("childXmlNames")
714
+ child_xml_names = [
715
+ element.firstChild.nodeValue for element in child_elements
716
+ ]
717
+ self.metadata_types += child_xml_names
718
+ self.metadata_types.sort()
719
+ self.status = "Done"
720
+ self.task.logger.info(self.status)
721
+ return self.metadata_types