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,401 @@
1
+ """
2
+ Pydantic models for validating cumulusci.yml
3
+
4
+ Note: If you change the model here, you should run `make schema`
5
+ to update the JSON Schema version in cumulusci.jsonschema.json
6
+ """
7
+
8
+ from logging import getLogger
9
+ from pathlib import Path
10
+ from typing import Any, Dict, List, Optional, Sequence, Union
11
+
12
+ from pydantic import Field, root_validator, validator
13
+ from pydantic.types import DirectoryPath
14
+ from typing_extensions import Literal, TypedDict
15
+
16
+ from cumulusci.core.enums import StrEnum
17
+ from cumulusci.utils.fileutils import DataInput, load_from_source
18
+ from cumulusci.utils.yaml.model_parser import CCIDictModel, HashableBaseModel
19
+ from cumulusci.utils.yaml.safer_loader import load_yaml_data
20
+
21
+ default_logger = getLogger(__name__)
22
+
23
+
24
+ # type aliases
25
+ PythonClassPath = str
26
+ URL = str
27
+
28
+
29
+ # additionalProperties here works around an
30
+ # incompatibility with VSCode's Red Hat YAML validator
31
+ # Can probably remove it at some future date if the
32
+ # bug/incompatibilty is fixed elsewhere in the stack
33
+ VSCodeFriendlyDict = Field({}, additionalProperties=True)
34
+
35
+
36
+ class PreflightCheck(CCIDictModel):
37
+ when: str = None
38
+ action: str = None
39
+ message: str = None
40
+
41
+
42
+ class Step(CCIDictModel):
43
+ task: str = None
44
+ flow: str = None
45
+ ignore_failure: bool = False
46
+ when: str = None # is this allowed?
47
+ options: Dict[str, Any] = VSCodeFriendlyDict
48
+ ui_options: Dict[str, Any] = VSCodeFriendlyDict
49
+ checks: List[PreflightCheck] = []
50
+ description: str = None
51
+
52
+ @root_validator()
53
+ def _check(cls, values):
54
+ has_task = values.get("task") and values["task"] != "None"
55
+ has_flow = values.get("flow") and values["flow"] != "None"
56
+ assert not (
57
+ has_task and has_flow
58
+ ), "Steps must have either task or flow but not both"
59
+ return values
60
+
61
+
62
+ class Task(CCIDictModel):
63
+ class_path: str = None
64
+ description: str = None
65
+ group: str = None
66
+ # additionalProperties here works around an
67
+ # incompatibility with VSCode's Red Hat YAML validator
68
+ options: Dict[str, Any] = VSCodeFriendlyDict
69
+ ui_options: Dict[str, Any] = VSCodeFriendlyDict
70
+ name: str = None # get rid of this???
71
+
72
+
73
+ class Flow(CCIDictModel):
74
+ description: str = None
75
+ steps: Dict[str, Step] = None
76
+ group: str = None
77
+
78
+
79
+ class Package(CCIDictModel):
80
+ name: Optional[str] = None
81
+ name_managed: Optional[str] = None
82
+ namespace: Optional[str] = None
83
+ install_class: str = None
84
+ uninstall_class: str = None
85
+ api_version: str = None
86
+ metadata_package_id: str = None
87
+
88
+
89
+ class Test(CCIDictModel):
90
+ name_match: str
91
+
92
+
93
+ class ReleaseNotesParser(CCIDictModel):
94
+ class_path: PythonClassPath
95
+ title: str
96
+
97
+
98
+ class ReleaseNotes(CCIDictModel):
99
+ parsers: Union[
100
+ Dict[str, Dict[int, ReleaseNotesParser]], Dict[int, ReleaseNotesParser]
101
+ ]
102
+
103
+
104
+ class Git(CCIDictModel):
105
+ repo_url: str = None
106
+ default_branch: str = None
107
+ prefix_feature: str = None
108
+ prefix_beta: str = None
109
+ prefix_release: str = None
110
+ push_prefix_sandbox: str = None
111
+ push_prefix_production: str = None
112
+ release_notes: ReleaseNotes = None
113
+ two_gp_context: str = Field(None, alias="2gp_context")
114
+ unlocked_context: Optional[str] = None
115
+
116
+
117
+ class Plan(CCIDictModel): # MetaDeploy plans
118
+ title: str = None
119
+ description: str = None
120
+ tier: Literal["primary", "secondary", "additional"] = "primary"
121
+ slug: str = None
122
+ is_listed: bool = True
123
+ steps: Dict[str, Step] = None
124
+ checks: List[PreflightCheck] = []
125
+ error_message: str = None
126
+ post_install_message: str = None
127
+ preflight_message: str = None
128
+ allowed_org_providers: List[Literal["devhub", "user"]] = ["user"]
129
+
130
+
131
+ class DependencyResolutions(CCIDictModel):
132
+ production: str = None
133
+ preproduction: str = None
134
+ resolution_strategies: Dict[str, List[str]] = None
135
+
136
+
137
+ class Project(CCIDictModel):
138
+ name: Optional[str] = None
139
+ package: Optional[Package] = None
140
+ test: Optional[Test] = None
141
+ git: Optional[Git] = None
142
+ dependencies: Optional[List[Dict[str, str]]] = None
143
+ dependency_resolutions: Optional[DependencyResolutions] = None
144
+ dependency_pins: Optional[List[Dict[str, str]]]
145
+ source_format: Literal["sfdx", "mdapi"] = "mdapi"
146
+ custom: Optional[Dict] = None
147
+
148
+
149
+ class ScratchOrg(CCIDictModel):
150
+ config_file: Path = None
151
+ days: int = None
152
+ namespaced: str = None
153
+ setup_flow: str = None
154
+ noancestors: bool = None
155
+ release: Literal["preview", "previous"] = None
156
+
157
+
158
+ class Orgs(CCIDictModel):
159
+ scratch: Dict[str, ScratchOrg] = None
160
+
161
+
162
+ class ServiceAttribute(CCIDictModel):
163
+ description: str = None
164
+ required: bool = None
165
+ default_factory: PythonClassPath = None
166
+ default: str = None
167
+ sensitive: bool = False
168
+
169
+
170
+ class Service(CCIDictModel):
171
+ description: str = None
172
+ class_path: Optional[str]
173
+ attributes: Dict[str, ServiceAttribute] = None
174
+ validator: PythonClassPath = None
175
+
176
+
177
+ class Plugin(CCIDictModel):
178
+ name: Optional[str]
179
+ version: Optional[str]
180
+ author: Optional[str]
181
+ description: Optional[str]
182
+ config: Dict[str, Any] = {}
183
+
184
+ @root_validator()
185
+ def _check_name_version(cls, values):
186
+ has_name = values.get("name") is not None
187
+ has_version = values.get("version") is not None
188
+
189
+ # If one is defined, both should be defined
190
+ if (has_name and not has_version) or (has_version and not has_name):
191
+ raise ValueError("Plugin Name and Version must be defined.")
192
+
193
+ return values
194
+
195
+
196
+ class CumulusCIConfig(CCIDictModel):
197
+ keychain: PythonClassPath
198
+
199
+
200
+ class VCSSourceRelease(StrEnum):
201
+ LATEST = "latest"
202
+ PREVIOUS = "previous"
203
+ LATEST_BETA = "latest_beta"
204
+
205
+
206
+ class VCSSourceModel(HashableBaseModel):
207
+ vcs: str
208
+ url: str
209
+ resolution_strategy: Optional[str]
210
+ commit: Optional[str]
211
+ ref: Optional[str]
212
+ branch: Optional[str]
213
+ tag: Optional[str]
214
+ release: Optional[VCSSourceRelease]
215
+ description: Optional[str]
216
+ allow_remote_code: Optional[bool] = False
217
+
218
+ @root_validator
219
+ def validate(cls, values):
220
+ exclusive_keys = [
221
+ "resolution_strategy",
222
+ "commit",
223
+ "ref",
224
+ "branch",
225
+ "tag",
226
+ "release",
227
+ ]
228
+ key_count = len([x for x in exclusive_keys if x in values and values[x]])
229
+ if key_count > 1:
230
+ raise ValueError(
231
+ 'Sources must use only one of "resolution_strategy", "commit", "ref", "branch", "tag", or "release".'
232
+ )
233
+ elif key_count == 0:
234
+ values["resolution_strategy"] = "production"
235
+
236
+ return values
237
+
238
+
239
+ GitHubSourceRelease = VCSSourceRelease
240
+
241
+
242
+ class GitHubSourceModel(VCSSourceModel):
243
+ """For backward compatibility."""
244
+
245
+ github: str
246
+ release: Optional[GitHubSourceRelease]
247
+ vcs: Optional[str]
248
+ url: Optional[str]
249
+
250
+ def __init__(self, **kwargs):
251
+ # For backward compatibility, we need to set the vcs and url attributes
252
+ # if they are not already set.
253
+ super().__init__(**kwargs)
254
+ self.vcs = "github"
255
+ self.url = kwargs.get("github", None)
256
+
257
+
258
+ class LocalFolderSourceModel(HashableBaseModel):
259
+ path: DirectoryPath
260
+ allow_remote_code: Optional[bool] = False
261
+
262
+
263
+ class CumulusCLIConfig(CCIDictModel):
264
+ show_stacktraces: bool = False
265
+ plain_output: bool = None
266
+
267
+
268
+ class CumulusCIRoot(CCIDictModel):
269
+ tasks: Dict[str, Task] = {}
270
+ flows: Dict[str, Flow] = {}
271
+ project: Project = {}
272
+ orgs: Orgs = {}
273
+ services: Dict[str, Service] = {}
274
+ cumulusci: CumulusCIConfig = None
275
+ plans: Dict[str, Plan] = {}
276
+ minimum_cumulusci_version: str = None
277
+ sources: Dict[
278
+ str, Union[LocalFolderSourceModel, VCSSourceModel, GitHubSourceModel]
279
+ ] = {}
280
+ cli: CumulusCLIConfig = None
281
+ plugins: Dict[str, Plugin] = {}
282
+
283
+ @validator("plans")
284
+ def validate_plan_tiers(cls, plans):
285
+ existing_tiers = [plan.tier for plan in plans.values()]
286
+ has_duplicate_tiers = any(
287
+ existing_tiers.count(tier) > 1 for tier in ("primary", "secondary")
288
+ )
289
+ if has_duplicate_tiers:
290
+ raise ValueError("Only one plan can be defined as 'primary' or 'secondary'")
291
+ return plans
292
+
293
+
294
+ class CumulusCIFile(CCIDictModel):
295
+ __root__: Union[CumulusCIRoot, None]
296
+
297
+
298
+ def parse_from_yaml(source) -> dict:
299
+ "Parse from a path, url, path-like or file-like"
300
+ return CumulusCIFile.parse_from_yaml(source) or {}
301
+
302
+
303
+ def validate_data(
304
+ data: Union[dict, list],
305
+ context: str = None,
306
+ on_error: callable = None,
307
+ ):
308
+ """Validate data which has already been loaded into a dictionary or list.
309
+
310
+ context is a string that will be used to give context to error messages.
311
+ on_error will be called for any validation errors with a dictionary in Pydantic error format
312
+
313
+ https://pydantic-docs.helpmanual.io/usage/models/#error-handling
314
+ """
315
+ return CumulusCIFile.validate_data(data, context=context, on_error=on_error)
316
+
317
+
318
+ class ErrorDict(TypedDict):
319
+ "The structure of a Pydantic error dictionary. Google TypedDict if its new to you."
320
+ loc: Sequence[Union[str, int]]
321
+ msg: str
322
+ type: str
323
+
324
+
325
+ def _log_yaml_errors(logger, errors: List[ErrorDict]):
326
+ "Format and log a Pydantic-style error dictionary"
327
+ # global has_shown_yaml_error_message
328
+ plural = "" if len(errors) <= 1 else "s"
329
+ logger.warning(f"CumulusCI Configuration Warning{plural}:")
330
+ for error in errors:
331
+ loc = " -> ".join(repr(x) for x in error["loc"] if x != "__root__")
332
+ logger.warning(" %s\n %s", loc, error["msg"])
333
+
334
+
335
+ def cci_safe_load(
336
+ source: DataInput, context: str = None, on_error: callable = None, logger=None
337
+ ) -> dict:
338
+ """Load a CumulusCI.yml file and issue warnings for unknown structures."""
339
+ errors = []
340
+ assert not (
341
+ on_error and logger
342
+ ), "Please specify either on_error or logger but not both"
343
+ on_error = on_error or errors.append
344
+
345
+ logger = logger or default_logger
346
+
347
+ with load_from_source(source) as (data_stream, filename):
348
+ data = load_yaml_data(data_stream, filename)
349
+ context = context or filename
350
+
351
+ try:
352
+ validate_data(data, context=context, on_error=on_error)
353
+ if errors:
354
+ _log_yaml_errors(logger, errors)
355
+ except Exception as e:
356
+ # should never be executed
357
+ print(f"Error validating cumulusci.yml {e}")
358
+ if on_error:
359
+ on_error(
360
+ {
361
+ "loc": (context,),
362
+ "msg": f"Error validating cumulusci.yml {e}",
363
+ "type": "exception",
364
+ }
365
+ )
366
+ pass
367
+ return data or {}
368
+
369
+
370
+ def _validate_files(globs):
371
+ "Validate YML files from Dev CLI for smoke testing"
372
+
373
+ from glob import glob
374
+
375
+ errors = []
376
+ for g in globs:
377
+ print(g)
378
+ filenames = glob(g, recursive=True)
379
+ for filename in filenames:
380
+ print("Validating", filename)
381
+
382
+ cci_safe_load(filename, filename, on_error=errors.append)
383
+ return errors
384
+
385
+
386
+ def _validate_url(url): # pragma: no cover
387
+ "Validate YML URL from Dev CLI for smoke testing"
388
+ errors = []
389
+ cci_safe_load(url, url, on_error=errors.append)
390
+ return errors
391
+
392
+
393
+ # validate YML files as a CLI for smoke testing
394
+ if __name__ == "__main__": # pragma: no cover
395
+ import sys
396
+ from pprint import pprint
397
+
398
+ if sys.argv[1].startswith("http"):
399
+ pprint(_validate_url(sys.argv[1]))
400
+ else:
401
+ pprint(_validate_files(sys.argv[1:]))
@@ -0,0 +1,156 @@
1
+ from pathlib import Path
2
+ from typing import IO, Sequence, Union
3
+
4
+ from pydantic import BaseModel, ValidationError
5
+ from pydantic.error_wrappers import ErrorWrapper
6
+
7
+ from cumulusci.utils.yaml.safer_loader import load_from_source, load_yaml_data
8
+
9
+
10
+ class CCIModel(BaseModel):
11
+ # Base class for CumulusCI's Pydantic models
12
+
13
+ _magic_fields = ["fields"]
14
+
15
+ @classmethod
16
+ def parse_from_yaml(cls, source: Union[str, Path, IO]):
17
+ "Parse from a path, url, path-like or file-like"
18
+ with load_from_source(source) as (f, path):
19
+ data = load_yaml_data(f)
20
+ obj = cls.parse_obj(data, path)
21
+ return getattr(obj, "__root__", obj)
22
+
23
+ @classmethod
24
+ def parse_obj(cls, data: Union[dict, list], path: str = None):
25
+ "Parse a structured dict or list into Model objects"
26
+ try:
27
+ return super().parse_obj(data)
28
+ except ValidationError as e:
29
+ _add_filenames(e, path)
30
+ raise e
31
+
32
+ @classmethod
33
+ def validate_data(
34
+ cls, data: Union[dict, list], context: str = None, on_error: callable = None
35
+ ):
36
+ """Validate data which has already been loaded into a dictionary or list.
37
+
38
+ context is a string that will be used to give context to error messages.
39
+ on_error will be called for any validation errors with a dictionary in Pydantic error format
40
+
41
+ https://pydantic-docs.helpmanual.io/usage/models/#error-handling
42
+ """
43
+ try:
44
+ cls.parse_obj(data, context)
45
+ return True
46
+ except ValidationError as e:
47
+ if on_error:
48
+ for error in e.errors():
49
+ on_error(error)
50
+
51
+ return False
52
+
53
+ def _alias_for_field(self, name):
54
+ "Find the name that we renamed a field to, to avoid Pydantic name clash"
55
+ for field in self.__fields__.values():
56
+ if field.alias == name:
57
+ return field.name
58
+
59
+ @property
60
+ def fields(self):
61
+ "Override deprecated Pydantic behaviour"
62
+ fields_alias = self._alias_for_field("fields")
63
+ if fields_alias:
64
+ return getattr(self, fields_alias)
65
+ else:
66
+ raise AttributeError
67
+
68
+ # @property.setter does not work because baseclass.__setattr__
69
+ # takes precedence (shrug emoji)
70
+ def __setattr__(self, name, value):
71
+ "Override deprecated Pydantic behaviour for .fields"
72
+ if name in self._magic_fields:
73
+ name = self._alias_for_field(name)
74
+ return super().__setattr__(name, value)
75
+
76
+ def copy(self, *args, **kwargs):
77
+ """Copy with a default behaviour similar to Python's.
78
+
79
+ If you supply arguments, you get Pydantic copy behaviour.
80
+ https://pydantic-docs.helpmanual.io/usage/exporting_models/#modelcopy
81
+ """
82
+ if not args and not kwargs:
83
+ return self.__class__(**self.__dict__)
84
+ else:
85
+ return super().copy(self, *args, **kwargs)
86
+
87
+ class Config:
88
+ """Pydantic Config
89
+
90
+ If you replace this config class in a sub-class, make sure you replace
91
+ the parameter below too.
92
+
93
+ https://pydantic-docs.helpmanual.io/usage/model_config/
94
+ """
95
+
96
+ extra = "forbid"
97
+
98
+
99
+ class CCIDictModel(CCIModel):
100
+ # A base class that acts as both a model and a dict. For transitioning from
101
+ # one to the other.
102
+
103
+ def __getitem__(self, name):
104
+ """Pretend to a do my_dict[name]"""
105
+ try:
106
+ return getattr(self, name)
107
+ except AttributeError:
108
+ raise IndexError(name)
109
+
110
+ def __setitem__(self, name, value):
111
+ """Pretend to a do my_dict[name] = X"""
112
+ setattr(self, name, value)
113
+
114
+ def __contains__(self, name):
115
+ "Support 'x in my_dict' syntax."
116
+ if name not in self._magic_fields:
117
+ return name in self.__dict__
118
+ else:
119
+ return self._alias_for_field(name) in self.__dict__
120
+
121
+ def get(self, name, default=None):
122
+ "Emulate dict.get()."
123
+ if name in self._magic_fields:
124
+ name = self._alias_for_field(name)
125
+
126
+ return self.__dict__.get(name, default)
127
+
128
+ def __delitem__(self, name):
129
+ if name in self._magic_fields:
130
+ name = self._alias_for_field(name)
131
+ del self.__dict__[name]
132
+
133
+
134
+ def _add_filenames(e: ValidationError, filename):
135
+ def _recursively_add_filenames(val):
136
+ processed = False
137
+ if isinstance(val, Sequence):
138
+ for e in val:
139
+ _recursively_add_filenames(e)
140
+ processed = True
141
+ elif isinstance(val, ErrorWrapper):
142
+ val._loc = (filename, val._loc)
143
+
144
+ processed = True
145
+ assert processed, f"Should have processed by now {val}, {repr(val)}"
146
+
147
+ _recursively_add_filenames(e.raw_errors)
148
+
149
+
150
+ class HashableBaseModel(CCIModel):
151
+ # Base Pydantic model class that has a functional `hash()` method.
152
+ # Requires that model can be converted to JSON.
153
+
154
+ # See https://github.com/samuelcolvin/pydantic/issues/1303
155
+ def __hash__(self):
156
+ return hash((type(self),) + tuple(self.json()))
@@ -0,0 +1,74 @@
1
+ import re
2
+ import typing as T
3
+ from io import StringIO
4
+ from logging import getLogger
5
+ from pathlib import Path
6
+
7
+ import yaml
8
+ from yaml.error import MarkedYAMLError
9
+
10
+ from cumulusci.core.exceptions import YAMLParseException
11
+ from cumulusci.utils.fileutils import FSResource, load_from_source
12
+
13
+ NBSP = "\u00A0"
14
+
15
+ pattern = re.compile(r"^\s*[\u00A0]+\s*", re.MULTILINE)
16
+
17
+ logger = getLogger(__name__)
18
+
19
+
20
+ def _replace_nbsp(origdata, filename):
21
+ """Replace nbsp characters in leading whitespace in a YAML file."""
22
+ counter = 0
23
+
24
+ def _replacer_func(matchobj):
25
+ nonlocal counter
26
+ counter += 1
27
+ string = matchobj.group(0)
28
+ rc = string.replace(NBSP, " ")
29
+ return rc
30
+
31
+ data = pattern.sub(_replacer_func, origdata)
32
+
33
+ if counter:
34
+ plural = "s were" if counter > 1 else " was"
35
+ logger.warning(
36
+ f"Note: {counter} lines with non-breaking space character{plural} detected in {filename}.\n"
37
+ "Perhaps you cut and pasted from a Web page?\n"
38
+ "Future versions of CumulusCI may disallow these characters.\n"
39
+ )
40
+ return data
41
+
42
+
43
+ def load_yaml_data(
44
+ source: T.Union[str, T.IO[T.Text], Path, FSResource], context: str = None
45
+ ):
46
+ """Load a file, convert NBSP->space and parse it in YAML.
47
+
48
+ Raises YAMLParseException with a nicely formatted error message
49
+ if an error occurs while parsing.
50
+
51
+ If you use this method directly (or, heaven forbid, yaml.safe_load)
52
+ consider making a CCIModel subclass instead.
53
+ """
54
+ with load_from_source(source) as (f_config, filename):
55
+ if filename == "<stream>":
56
+ filename = "a yaml file"
57
+ context = context or filename
58
+ data = _replace_nbsp(f_config.read(), context)
59
+ try:
60
+ rc = yaml.safe_load(StringIO(data))
61
+ except MarkedYAMLError as e:
62
+ line_num = e.problem_mark.line + 1
63
+ column_num = e.problem_mark.column
64
+ message = (
65
+ f"An error occurred parsing yaml file at line {line_num}, column {column_num}.\n"
66
+ + f"{filename}:{line_num}:{column_num}\n"
67
+ + f"Error message: {e.problem}."
68
+ )
69
+ raise YAMLParseException(message)
70
+ except Exception as e:
71
+ message = f"An error occurred parsing {filename}.\nError message: {e}"
72
+ raise YAMLParseException(message)
73
+
74
+ return rc
@@ -0,0 +1,5 @@
1
+ foo:
2
+
3
+ bar:
4
+
5
+ baz:
@@ -0,0 +1,20 @@
1
+ interactions:
2
+ - request:
3
+ body: null
4
+ headers:
5
+ Request-Headers:
6
+ - Elided
7
+ method: GET
8
+ uri: https://raw.githubusercontent.com/SFDO-Tooling/CumulusCI/8b8d1eb9a1593503bf625030fa702b6d4651cb55/cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.load.yml
9
+ response:
10
+ body:
11
+ string: "- sf_object: Account\n api: bulk\n"
12
+ headers:
13
+ Response-Headers:
14
+ Content-Type:
15
+ - text/plain; charset=utf-8
16
+ Others: Elided
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ version: 1