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()