diff --git a/cumulusci/cumulusci.yml b/cumulusci/cumulusci.yml index 3714013e8a..6a3bf98422 100644 --- a/cumulusci/cumulusci.yml +++ b/cumulusci/cumulusci.yml @@ -477,6 +477,10 @@ tasks: options: path: packaged group: Salesforce Metadata + describe_metadatatypes: + class_path: cumulusci.tasks.salesforce.DescribeMetadataTypes + description: Retrieves the metadata types supported by the org based on the api version + group: Salesforce Metadata retrieve_src: description: Retrieves the packaged metadata into the src directory class_path: cumulusci.tasks.salesforce.RetrievePackaged diff --git a/cumulusci/salesforce_api/metadata.py b/cumulusci/salesforce_api/metadata.py index 9c13e56656..8ef8c013bc 100644 --- a/cumulusci/salesforce_api/metadata.py +++ b/cumulusci/salesforce_api/metadata.py @@ -678,3 +678,44 @@ def _process_response(self, response): ) # Unknown response raise MetadataApiError(f"Unexpected response: {response.text}", response) + + +class ApiListMetadataTypes(BaseMetadataApiCall): + check_interval = 1 + soap_envelope_start = soap_envelopes.DESCRIBE_METADATA + soap_action_start = "describemetadatatypes" + + def __init__(self, task, api_version=None): + super(ApiListMetadataTypes, self).__init__(task) + self.metadata_types = [] + self.api_version = ( + api_version + if api_version + else task.project_config.project__package__api_version + ) + + def _build_envelope_start(self): + + return self.soap_envelope_start.format( + api_version=self.api_version, + ) + + def _process_response(self, response): + self.metadata_types = [] + metaobjects = parseString(response.content).getElementsByTagName( + "metadataObjects" + ) + + for metadataobject in metaobjects: + self.metadata_types.append( + self._get_element_value(metadataobject, "xmlName") + ) + child_elements = metadataobject.getElementsByTagName("childXmlNames") + child_xml_names = [ + element.firstChild.nodeValue for element in child_elements + ] + self.metadata_types += child_xml_names + self.metadata_types.sort() + self.status = "Done" + self.task.logger.info(self.status) + return self.metadata_types diff --git a/cumulusci/salesforce_api/soap_envelopes.py b/cumulusci/salesforce_api/soap_envelopes.py index a685628342..ae6e8ec816 100644 --- a/cumulusci/salesforce_api/soap_envelopes.py +++ b/cumulusci/salesforce_api/soap_envelopes.py @@ -161,3 +161,17 @@ """ + +DESCRIBE_METADATA = """ + + + + ###SESSION_ID### + + + + + {api_version} + + +""" diff --git a/cumulusci/salesforce_api/tests/metadata_test_strings.py b/cumulusci/salesforce_api/tests/metadata_test_strings.py index 8ab145a752..977e76a295 100644 --- a/cumulusci/salesforce_api/tests/metadata_test_strings.py +++ b/cumulusci/salesforce_api/tests/metadata_test_strings.py @@ -19,3 +19,6 @@ status_envelope = '\n\n \n \n ###SESSION_ID###\n \n \n \n \n {process_id}\n \n \n' deploy_status_envelope = '\n\n \n \n ###SESSION_ID###\n \n \n \n \n {process_id}\n true\n \n \n' + +list_metadata_types_envelope = '\n\n \n \n ###SESSION_ID###\n \n \n \n \n {api_version}\n \n \n' +list_metadata_types_result = 'WorkflowFieldUpdateworkflowsfalsefalseworkflowWorkflowtruefalse' diff --git a/cumulusci/salesforce_api/tests/test_metadata.py b/cumulusci/salesforce_api/tests/test_metadata.py index 7e578a34bb..9df439f67e 100644 --- a/cumulusci/salesforce_api/tests/test_metadata.py +++ b/cumulusci/salesforce_api/tests/test_metadata.py @@ -19,6 +19,7 @@ from cumulusci.salesforce_api.metadata import ( ApiDeploy, ApiListMetadata, + ApiListMetadataTypes, ApiRetrieveInstalledPackages, ApiRetrievePackaged, ApiRetrieveUnpackaged, @@ -36,6 +37,8 @@ list_metadata_result, list_metadata_result_bad_val, list_metadata_start_envelope, + list_metadata_types_envelope, + list_metadata_types_result, result_envelope, retrieve_packaged_start_envelope, retrieve_result, @@ -843,6 +846,42 @@ def test_bad_date_somehow(self): api() +class TestApiListMetadataTypes(TestBaseTestMetadataApi): + api_class = ApiListMetadataTypes + envelope_start = list_metadata_types_envelope + + def setup_method(self): + super().setup_method() + self.metadata_types = None + self.api_version = self.project_config.project__package__api_version + + def _response_call_success_result(self, response_result): + return list_metadata_types_result + + def _expected_call_success_result(self, response_result=None): + metadata_types = ["Workflow", "WorkflowFieldUpdate"] + return metadata_types + + def _create_instance(self, task, api_version=None): + return super()._create_instance(task, api_version) + + @responses.activate + def test_call_success(self): + org_config = { + "instance_url": "https://na12.salesforce.com", + "id": "https://login.salesforce.com/id/00D000000000000ABC/005000000000000ABC", + "access_token": "0123456789", + } + task = self._create_task(org_config=org_config) + api = self._create_instance(task) + if not self.api_class.soap_envelope_start: + api.soap_envelope_start = "{api_version}" + self._mock_call_mdapi(api, list_metadata_types_result) + + metadata_types = api() + assert metadata_types == self._expected_call_success_result() + + class TestApiRetrieveUnpackaged(TestBaseTestMetadataApi): maxDiff = None api_class = ApiRetrieveUnpackaged diff --git a/cumulusci/tasks/salesforce/DescribeMetadataTypes.py b/cumulusci/tasks/salesforce/DescribeMetadataTypes.py new file mode 100644 index 0000000000..49c605c37d --- /dev/null +++ b/cumulusci/tasks/salesforce/DescribeMetadataTypes.py @@ -0,0 +1,26 @@ +from cumulusci.salesforce_api.metadata import ApiListMetadataTypes +from cumulusci.tasks.salesforce import BaseRetrieveMetadata + + +class DescribeMetadataTypes(BaseRetrieveMetadata): + api_class = ApiListMetadataTypes + task_options = { + "api_version": { + "description": "Override the API version used to list metadatatypes" + }, + } + + def _init_options(self, kwargs): + super(DescribeMetadataTypes, self)._init_options(kwargs) + if "api_version" not in self.options: + self.options[ + "api_version" + ] = self.project_config.project__package__api_version + + def _get_api(self): + return self.api_class(self, self.options.get("api_version")) + + def _run_task(self): + api_object = self._get_api() + metadata_list = api_object() + self.logger.info("Metadata Types supported by org:\n" + str(metadata_list)) diff --git a/cumulusci/tasks/salesforce/__init__.py b/cumulusci/tasks/salesforce/__init__.py index f81c25d557..670c556600 100644 --- a/cumulusci/tasks/salesforce/__init__.py +++ b/cumulusci/tasks/salesforce/__init__.py @@ -30,6 +30,7 @@ "PublishCommunity": "cumulusci.tasks.salesforce.PublishCommunity", "RetrievePackaged": "cumulusci.tasks.salesforce.RetrievePackaged", "RetrieveReportsAndDashboards": "cumulusci.tasks.salesforce.RetrieveReportsAndDashboards", + "DescribeMetadataTypes": "cumulusci.tasks.salesforce.DescribeMetadataTypes", "RetrieveUnpackaged": "cumulusci.tasks.salesforce.RetrieveUnpackaged", "SOQLQuery": "cumulusci.tasks.salesforce.SOQLQuery", "SetTDTMHandlerStatus": "cumulusci.tasks.salesforce.trigger_handlers", diff --git a/cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py b/cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py new file mode 100644 index 0000000000..9715786b39 --- /dev/null +++ b/cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py @@ -0,0 +1,18 @@ +from unittest import mock + +from cumulusci.tasks.salesforce import DescribeMetadataTypes + +from .util import create_task + + +class TestRetrieveMetadataTypes: + def test_run_task(self): + task = create_task(DescribeMetadataTypes) + task._get_api = mock.Mock() + task() + task._get_api.assert_called_once() + + def test_run_task_with_apiversion(self): + task = create_task(DescribeMetadataTypes, {"api_version": 8.0}) + assert task.options.get("api_version") == 8.0 + task._get_api()