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,782 @@
1
+ import json
2
+ import os
3
+ import pathlib
4
+ import re
5
+ import sys
6
+ import types
7
+ from configparser import ConfigParser
8
+ from contextlib import contextmanager
9
+ from io import StringIO
10
+ from itertools import chain
11
+ from pathlib import Path
12
+ from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Union
13
+
14
+ from cumulusci.core.config.base_config import BaseConfig
15
+ from cumulusci.core.debug import get_debug_mode
16
+ from cumulusci.core.versions import PackageVersionNumber
17
+ from cumulusci.plugins.plugin_loader import load_plugins
18
+ from cumulusci.utils.version_strings import LooseVersion
19
+
20
+ API_VERSION_RE = re.compile(r"^\d\d+\.0$")
21
+
22
+ from pydantic import ValidationError
23
+
24
+ from cumulusci.core.config import FlowConfig, TaskConfig
25
+ from cumulusci.core.config.base_task_flow_config import BaseTaskFlowConfig
26
+ from cumulusci.core.exceptions import (
27
+ ConfigError,
28
+ CumulusCIException,
29
+ KeychainNotFound,
30
+ NamespaceNotFoundError,
31
+ NotInProject,
32
+ ProjectConfigNotFound,
33
+ VcsException,
34
+ )
35
+ from cumulusci.core.source import LocalFolderSource, NullSource
36
+ from cumulusci.core.utils import merge_config
37
+ from cumulusci.utils.fileutils import FSResource, open_fs_resource
38
+ from cumulusci.utils.git import current_branch, generic_parse_repo_url, git_path
39
+ from cumulusci.utils.yaml.cumulusci_yml import (
40
+ LocalFolderSourceModel,
41
+ VCSSourceModel,
42
+ cci_safe_load,
43
+ )
44
+ from cumulusci.vcs.models import AbstractRepo
45
+ from cumulusci.vcs.vcs_source import VCSSource
46
+
47
+ sys.modules.setdefault(
48
+ "tasks", types.ModuleType("tasks", "Synthetic package for all repo tasks")
49
+ )
50
+ import tasks
51
+
52
+ tasks.__path__ = []
53
+
54
+ if TYPE_CHECKING:
55
+ from cumulusci.core.config.universal_config import UniversalConfig
56
+ from cumulusci.core.keychain.base_project_keychain import BaseProjectKeychain
57
+ from cumulusci.vcs.base import VCSService
58
+
59
+
60
+ class ProjectConfigPropertiesMixin(BaseConfig):
61
+ """Mixin for shared properties used by ProjectConfigs and UniversalConfigs"""
62
+
63
+ cli: dict
64
+ services: dict
65
+ project: dict
66
+ cumulusci: dict
67
+ orgs: dict
68
+ minimum_cumulusci_version: str
69
+ sources: dict
70
+ flows: dict
71
+ plans: dict
72
+ tasks: dict
73
+ plugins: dict
74
+ dev_config: dict # this is not documented and should be deprecated
75
+
76
+
77
+ class BaseProjectConfig(BaseTaskFlowConfig, ProjectConfigPropertiesMixin):
78
+ """Base class for a project's configuration which extends the global config"""
79
+
80
+ config_filename = "cumulusci.yml"
81
+ universal_config_obj: "UniversalConfig"
82
+ keychain: Optional["BaseProjectKeychain"]
83
+ _repo_info: Dict[str, Any]
84
+ config_project: dict
85
+ config_project_local: dict
86
+ config_additional_yaml: dict
87
+ config_plugins_yaml: dict
88
+ additional_yaml: Optional[str]
89
+ source: Union[NullSource, VCSSource, LocalFolderSource]
90
+ _cache_dir: Optional[Path]
91
+ included_sources: Dict[
92
+ Union[VCSSourceModel, LocalFolderSourceModel],
93
+ "BaseProjectConfig",
94
+ ]
95
+
96
+ def __init__(
97
+ self,
98
+ universal_config_obj: "UniversalConfig",
99
+ config: Optional[dict] = None,
100
+ cache_dir: Optional[Path] = None,
101
+ *args,
102
+ **kwargs,
103
+ ):
104
+ self.universal_config_obj = universal_config_obj
105
+ self.keychain = None
106
+
107
+ # optionally pass in a repo_info dict
108
+ self._repo_info = kwargs.pop("repo_info", None)
109
+
110
+ if not config:
111
+ config = {}
112
+
113
+ # Initialize the dictionaries for the individual configs
114
+ self.config_project = {}
115
+ self.config_project_local = {}
116
+ self.config_additional_yaml = {}
117
+ self.config_plugins_yaml = {}
118
+
119
+ # optionally pass in a kwarg named 'additional_yaml' that will
120
+ # be added to the YAML merge stack.
121
+ # Called from MetaCI in metaci/cumulusci/config.py
122
+ # https://github.com/SFDO-Tooling/MetaCI/blob/36a0f4654/metaci/cumulusci/config.py#L8-L11
123
+ self.additional_yaml = None
124
+ if "additional_yaml" in kwargs:
125
+ self.additional_yaml = kwargs.pop("additional_yaml")
126
+
127
+ # initialize map of project configs referenced from an external source
128
+ self.source = NullSource()
129
+ self.included_sources = kwargs.pop("included_sources", {})
130
+
131
+ # Store requested cache directory, which may be our parent's if we are a subproject
132
+ self._cache_dir = cache_dir
133
+
134
+ super().__init__(config=config)
135
+
136
+ @property
137
+ def config_project_local_path(self) -> Optional[str]:
138
+ path = Path(self.project_local_dir) / self.config_filename
139
+ if path.is_file():
140
+ return str(path)
141
+
142
+ def _load_config(self):
143
+ """Loads the configuration from YAML, if no override config was passed in initially."""
144
+
145
+ if (
146
+ self.config
147
+ ): # any config being pre-set at init will short circuit out, but not a plain {}
148
+ return
149
+
150
+ # Verify that we're in a project
151
+ repo_root = self.repo_root
152
+ if not repo_root:
153
+ raise NotInProject(
154
+ "No git repository was found in the current path. You must be in a git repository to set up and use CCI for a project."
155
+ )
156
+
157
+ # Verify that the project's root has a config file
158
+ if not self.config_project_path:
159
+ raise ProjectConfigNotFound(
160
+ f"The file {self.config_filename} was not found in the repo root: {repo_root}. Are you in a CumulusCI Project directory?"
161
+ )
162
+
163
+ # Load the project's yaml config file
164
+ project_config = cci_safe_load(self.config_project_path, logger=self.logger)
165
+
166
+ if project_config:
167
+ self.config_project.update(project_config)
168
+
169
+ # Load the local project yaml config file if it exists
170
+ if self.config_project_local_path:
171
+ local_config = cci_safe_load(
172
+ self.config_project_local_path, logger=self.logger
173
+ )
174
+ if local_config:
175
+ self.config_project_local.update(local_config)
176
+
177
+ # merge in any additional yaml that was passed along
178
+ if self.additional_yaml:
179
+ additional_yaml_config = cci_safe_load(
180
+ StringIO(self.additional_yaml),
181
+ self.config_project_path,
182
+ logger=self.logger,
183
+ )
184
+ if additional_yaml_config:
185
+ self.config_additional_yaml.update(additional_yaml_config)
186
+
187
+ # Loading plugins as classes are loaded and available.
188
+ plugins = load_plugins(self.logger)
189
+
190
+ # Load the plugin yaml config file if it exists
191
+ for plugin in plugins:
192
+ if plugin.plugin_project_config:
193
+ self.config_plugins_yaml.update(plugin.plugin_project_config)
194
+ self.logger.info(
195
+ f"Loaded plugin: {plugin.name} ({plugin.api_name}) v{plugin.version}"
196
+ )
197
+
198
+ plugin.teardown() # clean up the plugin
199
+
200
+ self.config = merge_config(
201
+ {
202
+ "universal_config": self.config_universal,
203
+ "global_config": self.config_global,
204
+ "project_config": self.config_project,
205
+ "project_local_config": self.config_project_local,
206
+ "additional_yaml": self.config_additional_yaml,
207
+ "plugins_config": self.config_plugins_yaml,
208
+ }
209
+ )
210
+
211
+ self._validate_config()
212
+
213
+ def _validate_config(self):
214
+ """Performs validation checks on the configuration"""
215
+ self._validate_package_api_format()
216
+
217
+ def _validate_package_api_format(self):
218
+ api_version = str(self.project__package__api_version)
219
+
220
+ if not API_VERSION_RE.match(api_version):
221
+ message = (
222
+ f"Package API Version must be in the form 'XX.0', found: {api_version}"
223
+ )
224
+ raise ConfigError(message)
225
+
226
+ @property
227
+ def config_global(self) -> dict:
228
+ return self.universal_config_obj.config_global
229
+
230
+ @property
231
+ def config_universal(self) -> dict:
232
+ return self.universal_config_obj.config_universal
233
+
234
+ @property
235
+ def repo_info(self) -> Dict[str, Any]:
236
+ if self._repo_info is not None:
237
+ return self._repo_info
238
+
239
+ # Detect if we are running in a CI environment and get repo info
240
+ # from env vars for the environment instead of .git files
241
+ info = {"ci": None}
242
+
243
+ # Make sure that the CUMULUSCI_AUTO_DETECT environment variable is
244
+ # set before trying to auto-detect anything from the environment
245
+ if not os.environ.get("CUMULUSCI_AUTO_DETECT"):
246
+ self._repo_info = info
247
+ return self._repo_info
248
+
249
+ # Heroku CI
250
+ heroku_ci = os.environ.get("HEROKU_TEST_RUN_ID")
251
+ if heroku_ci:
252
+ info = {
253
+ "branch": os.environ.get("HEROKU_TEST_RUN_BRANCH"),
254
+ "commit": os.environ.get("HEROKU_TEST_RUN_COMMIT_VERSION"),
255
+ "ci": "heroku",
256
+ "root": "/app",
257
+ }
258
+
259
+ # Other CI environment implementations can be implemented here...
260
+
261
+ self._apply_repo_env_var_overrides(info)
262
+
263
+ if info["ci"]:
264
+ self._validate_required_git_info(info)
265
+
266
+ if len(info) > 1:
267
+ self._log_detected_overrides_as_warning(info)
268
+
269
+ self._repo_info = info
270
+ return self._repo_info
271
+
272
+ def _apply_repo_env_var_overrides(self, info: Dict[str, Any]):
273
+ """Apply CUMULUSCI_REPO_* environment variables last so they can
274
+ override and fill in missing values from the CI environment"""
275
+ self._override_repo_env_var("CUMULUSCI_REPO_BRANCH", "branch", info)
276
+ self._override_repo_env_var("CUMULUSCI_REPO_COMMIT", "commit", info)
277
+ self._override_repo_env_var("CUMULUSCI_REPO_ROOT", "root", info)
278
+
279
+ repo_url = os.environ.get("CUMULUSCI_REPO_URL")
280
+ if repo_url:
281
+ if repo_url != info.get("url"):
282
+ self.logger.info(
283
+ "CUMULUSCI_REPO_URL found, using its value as the repo url, owner, and name"
284
+ )
285
+
286
+ url_info = {}
287
+ (
288
+ url_info["owner"],
289
+ url_info["name"],
290
+ url_info["domain"],
291
+ ) = generic_parse_repo_url(repo_url)
292
+ url_info["url"] = repo_url
293
+ info.update(url_info)
294
+
295
+ def get_repo_owner_host_from_url(self, repo_url) -> List[str]:
296
+ """Returns the owner, repo_name, and host from the repository URL.
297
+ The method should return a list containing the owner, repo_name and host."""
298
+ try:
299
+ vcs_service = self.get_service_type_for_repo(repo_url)
300
+ parsed_url = vcs_service.parse_repo_url()
301
+ except Exception:
302
+ # Fallback to generic parsing if the service does not support it
303
+ parsed_url = generic_parse_repo_url(repo_url)
304
+
305
+ if len(parsed_url) < 3:
306
+ raise CumulusCIException("Parsed repository URL is not in expected format.")
307
+
308
+ return [parsed_url[0], parsed_url[1], parsed_url[2]]
309
+
310
+ def _override_repo_env_var(
311
+ self, repo_env_var: str, local_var: str, info: Dict[str, Any]
312
+ ):
313
+ env_value: Optional[str] = os.environ.get(repo_env_var)
314
+ if env_value:
315
+ if env_value != info.get(local_var):
316
+ self.logger.info(
317
+ f"{repo_env_var} found, using its value for configuration."
318
+ )
319
+ info[local_var] = env_value
320
+
321
+ def _validate_required_git_info(self, info: Dict[str, Any]):
322
+ """Ensures that we have the required git info or throw a ConfigError"""
323
+ validate = {
324
+ # <key>: <env var to manually override>
325
+ "branch": "CUMULUSCI_REPO_BRANCH",
326
+ "commit": "CUMULUSCI_REPO_COMMIT",
327
+ "name": "CUMULUSCI_REPO_URL",
328
+ "owner": "CUMULUSCI_REPO_URL",
329
+ "root": "CUMULUSCI_REPO_ROOT",
330
+ "url": "CUMULUSCI_REPO_URL",
331
+ }
332
+ for key, env_var in list(validate.items()):
333
+ if key not in info or not info[key]:
334
+ message = f"Detected CI on {info['ci']} but could not determine the repo {key}"
335
+ if env_var:
336
+ message += f". You can manually pass in the {key} "
337
+ message += f" with the {env_var} environment variable."
338
+ raise ConfigError(message)
339
+
340
+ def _log_detected_overrides_as_warning(self, info: Dict[str, Any]):
341
+ self.logger.info("")
342
+ self.logger.warning("Using environment variables to override repo info:")
343
+ keys = list(info.keys())
344
+ keys.sort()
345
+ for key in keys:
346
+ self.logger.warning(f" {key}: {info[key]}")
347
+ self.logger.info("")
348
+
349
+ def git_config_remote_origin_url(self) -> Optional[str]:
350
+ """Returns the url under the [remote origin]
351
+ section of the .git/config file. Returns None
352
+ if .git/config file not present or no matching
353
+ line is found."""
354
+ config = ConfigParser(strict=False)
355
+ try:
356
+ config.read(git_path(self.repo_root, "config"))
357
+ url = config['remote "origin"']["url"]
358
+ except (KeyError, TypeError):
359
+ url = None
360
+ return url
361
+
362
+ @property
363
+ def repo_root(self) -> Optional[str]:
364
+ path = self.repo_info.get("root")
365
+ if path:
366
+ return path
367
+
368
+ path = Path.cwd().resolve()
369
+ paths = chain((path,), path.parents)
370
+ for path in paths:
371
+ if (path / ".git").is_dir():
372
+ return str(path)
373
+
374
+ @property
375
+ def server_domain(self) -> Optional[str]:
376
+ domain = self.repo_info.get("domain")
377
+
378
+ if domain:
379
+ return domain
380
+
381
+ if not self.repo_root:
382
+ return
383
+
384
+ url_line = self.git_config_remote_origin_url()
385
+ if url_line:
386
+ return self.get_repo_owner_host_from_url(url_line)[2]
387
+
388
+ @property
389
+ def repo_name(self) -> Optional[str]:
390
+ name = self.repo_info.get("name")
391
+ if name:
392
+ return name
393
+
394
+ if not self.repo_root:
395
+ return
396
+
397
+ url_line = self.git_config_remote_origin_url()
398
+ if url_line:
399
+ return self.get_repo_owner_host_from_url(url_line)[1]
400
+
401
+ @property
402
+ def repo_url(self) -> Optional[str]:
403
+ url = self.repo_info.get("url")
404
+ if url:
405
+ return url
406
+
407
+ if not self.repo_root:
408
+ return
409
+
410
+ url = self.git_config_remote_origin_url()
411
+ return url
412
+
413
+ @property
414
+ def repo_owner(self) -> Optional[str]:
415
+ owner = self.repo_info.get("owner")
416
+ if owner:
417
+ return owner
418
+
419
+ if not self.repo_root:
420
+ return
421
+
422
+ url_line = self.git_config_remote_origin_url()
423
+
424
+ if url_line:
425
+ return self.get_repo_owner_host_from_url(url_line)[0]
426
+
427
+ @property
428
+ def repo_branch(self) -> Optional[str]:
429
+ branch = self.repo_info.get("branch")
430
+ if branch:
431
+ return branch
432
+
433
+ if not self.repo_root:
434
+ return
435
+
436
+ return current_branch(self.repo_root)
437
+
438
+ @property
439
+ def repo_commit(self) -> Optional[str]:
440
+ commit = self.repo_info.get("commit")
441
+ if commit:
442
+ return commit
443
+
444
+ if not self.repo_root:
445
+ return
446
+
447
+ branch = self.repo_branch
448
+ if branch:
449
+ commit_file_path = pathlib.Path(self.repo_root) / ".git" / "refs" / "heads"
450
+ commit_file_path = commit_file_path.joinpath(*branch.split("/"))
451
+ else:
452
+ # We're in detached HEAD mode; .git/HEAD contains the SHA
453
+ commit_file_path = pathlib.Path(self.repo_root) / ".git" / "HEAD"
454
+
455
+ if commit_file_path.exists() and commit_file_path.is_file():
456
+ return commit_file_path.read_text().strip()
457
+ else:
458
+ if branch:
459
+ packed_refs_path = os.path.join(self.repo_root, ".git", "packed-refs")
460
+ with open(packed_refs_path, "r") as f:
461
+ for line in f:
462
+ parts = line.split(" ")
463
+ if len(parts) == 1:
464
+ # Skip lines showing the commit sha of a tag on the
465
+ # preceeding line
466
+ continue
467
+ if (
468
+ parts[1].replace("refs/remotes/origin/", "").strip()
469
+ == branch
470
+ ):
471
+ return parts[0]
472
+
473
+ def get_repo(self) -> AbstractRepo:
474
+ repo = self.repo_service.get_repository()
475
+ if repo is None:
476
+ raise VcsException(
477
+ f"VCS repository not found or not authorized. ({self.repo_url})"
478
+ )
479
+ return repo
480
+
481
+ def get_latest_tag(self, beta: bool = False) -> str:
482
+ """Query Github Releases to find the latest production or beta tag"""
483
+ from cumulusci.vcs.bootstrap import get_latest_tag
484
+
485
+ repo = self.get_repo()
486
+ return get_latest_tag(repo, beta)
487
+
488
+ def get_latest_version(self, beta: bool = False) -> Optional[LooseVersion]:
489
+ """Query Github Releases to find the latest production or beta release"""
490
+ tag = self.get_latest_tag(beta)
491
+ version = self.get_version_for_tag(tag)
492
+ if version is not None:
493
+ return LooseVersion(version)
494
+
495
+ def get_previous_version(self) -> Optional[LooseVersion]:
496
+ """Query GitHub releases to find the previous production release"""
497
+ from cumulusci.vcs.bootstrap import find_previous_release
498
+
499
+ repo = self.get_repo()
500
+ release = find_previous_release(repo, self.project__git__prefix_release)
501
+ if release is not None:
502
+ return LooseVersion(self.get_version_for_tag(release.tag_name))
503
+
504
+ @property
505
+ def config_project_path(self) -> Optional[str]:
506
+ if not self.repo_root:
507
+ return
508
+ path = Path(self.repo_root) / self.config_filename
509
+ if path.is_file():
510
+ return str(path)
511
+
512
+ @property
513
+ def project_local_dir(self) -> str:
514
+ """location of the user local directory for the project
515
+ e.g., ~/.cumulusci/NPSP-Extension-Test/"""
516
+
517
+ # depending on where we are in bootstrapping the UniversalConfig
518
+ # the canonical projectname could be located in one of two places
519
+ if self.project__name:
520
+ name = self.project__name
521
+ else:
522
+ name = self.config_project.get("project", {}).get("name", "")
523
+
524
+ path = str(self.universal_config_obj.cumulusci_config_dir / name)
525
+ if not os.path.isdir(path):
526
+ os.makedirs(path)
527
+ return path
528
+
529
+ @property
530
+ def default_package_path(self) -> Path:
531
+ if self.project__source_format == "sfdx":
532
+ relpath = "force-app"
533
+ for pkg in self.sfdx_project_config.get("packageDirectories", []):
534
+ if pkg.get("default"):
535
+ relpath = pkg["path"]
536
+ else:
537
+ relpath = "src"
538
+ return Path(self.repo_root, relpath).resolve()
539
+
540
+ @property
541
+ def sfdx_project_config(self) -> Dict[str, Any]:
542
+ with open(
543
+ Path(self.repo_root) / "sfdx-project.json", "r", encoding="utf-8"
544
+ ) as f:
545
+ config = json.load(f)
546
+ return config
547
+
548
+ @property
549
+ def allow_remote_code(self) -> bool:
550
+ return self.source.allow_remote_code
551
+
552
+ @property
553
+ def repo_service(self):
554
+ vcs_service = self.repo_info.get("vcs_service", None)
555
+ if vcs_service:
556
+ return vcs_service
557
+
558
+ vcs_service = self.get_service_type_for_repo(self.repo_url)
559
+
560
+ if vcs_service is None:
561
+ raise VcsException("Provider class for not found in config")
562
+
563
+ if self._repo_info:
564
+ self._repo_info["vcs_service"] = vcs_service
565
+
566
+ return vcs_service
567
+
568
+ @repo_service.setter
569
+ def repo_service(self, vcs_service: "VCSService"):
570
+ """Set the VCS service for this project config."""
571
+ from cumulusci.vcs.base import VCSService
572
+
573
+ if not isinstance(vcs_service, VCSService):
574
+ raise TypeError("repo_service must be an instance of VCSService")
575
+
576
+ self._repo_info["vcs_service"] = vcs_service
577
+
578
+ def get_service_type_for_repo(
579
+ self, url: str, service_alias: Optional[str] = None
580
+ ) -> "VCSService":
581
+ from cumulusci.vcs.bootstrap import get_service_for_repo_url
582
+
583
+ vcs_service = get_service_for_repo_url(self, url, service_alias=service_alias)
584
+ vcs_service.logger = self.logger
585
+ return vcs_service
586
+
587
+ def get_tag_for_version(self, prefix: str, version: str) -> str:
588
+ """Given a prefix and version, returns the appropriate tag name to use."""
589
+ try:
590
+ return PackageVersionNumber.parse(version).format_tag(prefix)
591
+ except ValueError:
592
+ return f"{prefix}{version}"
593
+
594
+ def get_version_for_tag(
595
+ self,
596
+ tag: str,
597
+ prefix_beta: Optional[str] = None,
598
+ prefix_release: Optional[str] = None,
599
+ ) -> Optional[str]:
600
+ try:
601
+ return PackageVersionNumber.parse_tag(
602
+ tag,
603
+ prefix_beta or self.project__git__prefix_beta,
604
+ prefix_release or self.project__git__prefix_release,
605
+ ).format()
606
+ except ValueError:
607
+ pass
608
+
609
+ def set_keychain(self, keychain: "BaseProjectKeychain"):
610
+ self.keychain = keychain
611
+
612
+ def _check_keychain(self):
613
+ if not self.keychain:
614
+ raise KeychainNotFound(
615
+ "Could not find config.keychain. You must call "
616
+ + "config.set_keychain(keychain) before accessing orgs"
617
+ )
618
+
619
+ def get_repo_from_url(self, url: str) -> Optional[AbstractRepo]:
620
+ from cumulusci.vcs.bootstrap import get_repo_from_url
621
+
622
+ repo = get_repo_from_url(self, url)
623
+ repo.logger = self.logger
624
+ return repo
625
+
626
+ def get_task(self, name: str) -> TaskConfig:
627
+ """Get a TaskConfig by task name
628
+
629
+ If the name has a colon, look for it in a different project config.
630
+ """
631
+ if ":" in name:
632
+ ns, name = name.split(":")
633
+ other_config = self.get_namespace(ns)
634
+ task_config = other_config.get_task(name)
635
+ task_config.project_config = other_config
636
+ else:
637
+ task_config = super().get_task(name)
638
+ task_config.project_config = self
639
+ return task_config
640
+
641
+ def get_flow(self, name) -> FlowConfig:
642
+ """Get a FlowConfig by flow name
643
+
644
+ If the name has a colon, look for it in a different project config.
645
+ """
646
+ if ":" in name:
647
+ ns, name = name.split(":")
648
+ other_config = self.get_namespace(ns)
649
+ flow_config = other_config.get_flow(name)
650
+ flow_config.name = name
651
+ flow_config.project_config = other_config
652
+ else:
653
+ flow_config = super().get_flow(name)
654
+ flow_config.name = name
655
+ flow_config.project_config = self
656
+ return flow_config
657
+
658
+ def get_namespace(self, ns: str) -> "BaseProjectConfig":
659
+ """Look up another project config by its name in the `sources` config.
660
+
661
+ Also makes sure the project has been fetched, if it's from an external source.
662
+ """
663
+ spec = self.lookup(f"sources__{ns}")
664
+ if spec is None:
665
+ raise NamespaceNotFoundError(f"Namespace not found: {ns}")
666
+
667
+ return self.include_source(spec)
668
+
669
+ def include_source(
670
+ self,
671
+ spec: Union[VCSSourceModel, LocalFolderSourceModel, dict],
672
+ ) -> "BaseProjectConfig":
673
+ """Make sure a project has been fetched from its source.
674
+
675
+ This either fetches the project code and constructs its project config,
676
+ or returns a project config that was previously loaded with the same spec.
677
+ """
678
+
679
+ if isinstance(spec, dict):
680
+ parsed_spec = None
681
+ source_models = VCSSource.registered_source_models()
682
+ source_models.append(LocalFolderSourceModel)
683
+
684
+ for model_class in source_models:
685
+ try:
686
+ parsed_spec = model_class(**spec)
687
+ except ValidationError:
688
+ pass
689
+ except TypeError:
690
+ pass
691
+ else:
692
+ break
693
+
694
+ if not parsed_spec:
695
+ raise ValueError(f"Invalid source spec: {spec}")
696
+
697
+ spec = parsed_spec
698
+
699
+ if spec in self.included_sources:
700
+ project_config = self.included_sources[spec]
701
+ else:
702
+ if isinstance(spec, VCSSourceModel):
703
+ source = VCSSource.create(self, spec)
704
+ elif isinstance(spec, LocalFolderSourceModel):
705
+ source = LocalFolderSource(self, spec)
706
+
707
+ self.logger.info(f"Fetching from {source}")
708
+ project_config = source.fetch()
709
+ project_config.set_keychain(self.keychain)
710
+ project_config.source = source
711
+ self.included_sources[spec] = project_config
712
+
713
+ # If I can't load remote code, make sure that my
714
+ # included repos can't either.
715
+ if not self.allow_remote_code:
716
+ spec.allow_remote_code = False
717
+ else:
718
+ project_config._add_tasks_directory_to_python_path()
719
+
720
+ return project_config
721
+
722
+ def _add_tasks_directory_to_python_path(self):
723
+ # https://stackoverflow.com/a/2700924/113477
724
+ if not self.allow_remote_code:
725
+ return False
726
+
727
+ directory = str(Path(self.repo_root) / "tasks")
728
+ if directory not in tasks.__path__:
729
+ self.logger.debug(f"Adding {directory} to tasks.__path__")
730
+ tasks.__path__.append(directory)
731
+ if get_debug_mode():
732
+ spec = getattr(self.source, "spec", ".")
733
+ self.logger.debug(
734
+ f"After importing {spec}: tasks.__path__ {tasks.__path__}"
735
+ )
736
+
737
+ def construct_subproject_config(self, **kwargs) -> "BaseProjectConfig":
738
+ """Construct another project config for an external source"""
739
+ return self.__class__(
740
+ self.universal_config_obj,
741
+ included_sources=self.included_sources,
742
+ cache_dir=self.cache_dir,
743
+ **kwargs,
744
+ )
745
+
746
+ def relpath(self, path: str) -> str:
747
+ """Convert path to be relative to the project repo root."""
748
+ return os.path.relpath(os.path.join(self.repo_root, path))
749
+
750
+ @property
751
+ def cache_dir(self) -> Path:
752
+ "A project cache which is on the local filesystem. Prefer open_cache where possible."
753
+ if self._cache_dir:
754
+ return self._cache_dir
755
+
756
+ assert self.repo_root
757
+ cache_dir = Path(self.repo_root, ".cci")
758
+ cache_dir.mkdir(exist_ok=True)
759
+
760
+ return cache_dir
761
+
762
+ @contextmanager
763
+ def open_cache(self, cache_name: str) -> Iterable[FSResource]:
764
+ "A context managed PyFilesystem-based cache which could theoretically be on any filesystem."
765
+ with open_fs_resource(self.cache_dir / cache_name) as cache_dir:
766
+ cache_dir.mkdir(exist_ok=True, parents=True)
767
+ yield cache_dir
768
+
769
+ @classmethod
770
+ def get_package_data(cls, config: "BaseProjectConfig"):
771
+ namespace = config.project__package__namespace
772
+ package_name = (
773
+ config.project__package__name_managed
774
+ or config.project__package__name
775
+ or "Package"
776
+ )
777
+
778
+ return package_name, namespace
779
+
780
+
781
+ class RemoteProjectConfig(ProjectConfigPropertiesMixin):
782
+ pass