diff --git a/cumulusci/tasks/metadata/package.py b/cumulusci/tasks/metadata/package.py
index a1e546ae3b..d7689d8eb0 100644
--- a/cumulusci/tasks/metadata/package.py
+++ b/cumulusci/tasks/metadata/package.py
@@ -45,15 +45,19 @@ def process_common_components(response_messages: List, components: Dict):
"""Compare compoents in the api responce object with list of components and return common common components"""
if not response_messages or not components:
return components
-
for message in response_messages:
+
message_list = message.firstChild.nextSibling.firstChild.nodeValue.split("'")
if len(message_list) > 1:
component_type = message_list[1]
message_txt = message_list[2]
-
if "is not available in this organization" in message_txt:
del components[component_type]
+ elif "is unknown" in message_txt:
+ component_type = message_list[0].split(" ")
+ components[component_type[0]].remove(message_list[1])
+ if len(components[component_type]) == 0:
+ del components[component_type]
else:
component_name = message_list[3]
if component_name in components[component_type]:
diff --git a/cumulusci/tasks/salesforce/check_components.py b/cumulusci/tasks/salesforce/check_components.py
index 9ec3aa6922..c59f3c7583 100644
--- a/cumulusci/tasks/salesforce/check_components.py
+++ b/cumulusci/tasks/salesforce/check_components.py
@@ -3,6 +3,7 @@
import shutil
import tempfile
from collections import defaultdict
+from itertools import chain
from xml.etree.ElementTree import ParseError
from defusedxml.minidom import parseString
@@ -60,6 +61,7 @@ def _run_task(self):
for component_type, component_names in components.items():
self.logger.debug(f"{component_type}: {', '.join(component_names)}")
# check common components
+ components.pop("Settings", None)
existing_components = process_common_components(
api_retrieve_unpackaged_response, components
)
@@ -102,12 +104,34 @@ def get_repo_existing_components(self, plan_or_flow_name, paths=""):
# Temp dir to copy all deploy paths from task options
temp_dir = tempfile.mkdtemp()
self.logger.info(f"Temporary deploy directory created: {temp_dir}")
-
+ mdapi_components = {}
+ mdapi_response_messages = []
for path in self.deploy_paths:
full_path = os.path.join(self.project_config.repo_root, path)
if not os.path.exists(full_path):
self.logger.info(f"Skipping path: '{path}' - path doesn't exist")
continue
+ elif "package.xml" in os.listdir(full_path):
+ package_xml_path = os.path.join(full_path, "package.xml")
+ source_xml_tree = metadata_tree.parse(package_xml_path)
+ components = metadata_tree.parse_package_xml_types(
+ "name", source_xml_tree
+ )
+ response_messages = self._get_api_object_responce(
+ package_xml_path, source_xml_tree.version.text
+ )
+ merged = {}
+ for key in set(components).union(mdapi_components):
+ merged[key] = list(
+ set(
+ chain(
+ components.get(key, []), mdapi_components.get(key, [])
+ )
+ )
+ )
+ mdapi_components = merged
+ mdapi_response_messages.extend(response_messages)
+ continue
self._copy_to_tempdir(path, temp_dir)
(
@@ -117,6 +141,21 @@ def get_repo_existing_components(self, plan_or_flow_name, paths=""):
# remove temp dir
shutil.rmtree(temp_dir)
+ merged = {}
+ if components:
+ for key in set(components).union(mdapi_components):
+ merged[key] = list(
+ set(chain(components.get(key, []), mdapi_components.get(key, [])))
+ )
+ components = merged
+ else:
+ components = mdapi_components
+
+ if api_retrieve_unpackaged_response:
+ api_retrieve_unpackaged_response.extend(mdapi_response_messages)
+ else:
+ api_retrieve_unpackaged_response = mdapi_response_messages
+
return [components, api_retrieve_unpackaged_response]
def _copy_to_tempdir(self, src_dir, temp_dir):
diff --git a/cumulusci/tasks/salesforce/tests/test_check_components.py b/cumulusci/tasks/salesforce/tests/test_check_components.py
index 549275be99..b7f963cab0 100644
--- a/cumulusci/tasks/salesforce/tests/test_check_components.py
+++ b/cumulusci/tasks/salesforce/tests/test_check_components.py
@@ -1,4 +1,4 @@
-from unittest.mock import ANY, MagicMock, mock_open, patch
+from unittest.mock import ANY, MagicMock, Mock, mock_open, patch
import pytest
@@ -11,6 +11,210 @@
class TestCheckComponents:
+ @patch("os.path.exists", return_value=True)
+ @patch("os.remove")
+ @patch("os.path.isdir", return_value=True)
+ @patch("os.listdir", return_value=["package.xml"])
+ @patch("os.path.join", side_effect=lambda *args: "/".join(args))
+ @patch("cumulusci.core.sfdx.convert_sfdx_source")
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._is_plan",
+ return_value=False,
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._freeze_steps",
+ return_value=[],
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._collect_components_from_paths",
+ return_value=[{"Type1": ["Comp1"]}, []],
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._get_api_object_responce",
+ return_value=[],
+ )
+ @patch(
+ "builtins.open",
+ new_callable=mock_open,
+ read_data="""
+
+
+ Delivery
+ ApexClass
+
+
+ Delivery__c
+ CustomObject
+
+ 58.0
+
+ """,
+ )
+ @patch("cumulusci.utils.xml.metadata_tree.parse")
+ @patch(
+ "cumulusci.utils.xml.metadata_tree.parse_package_xml_types",
+ return_value={"Type2": ["Comp2"]},
+ )
+ def test_get_repo_existing_components(
+ self,
+ mock_metadata_parse,
+ mock_open_file,
+ mock_convert_sfdx_source,
+ mock_path_join,
+ mock_listdir,
+ mock_isdir,
+ mock_remove,
+ mock_path_exists,
+ mock_is_plan,
+ mock_freeze_steps,
+ mock_get_api_object,
+ mock_parse,
+ mock_collect_components,
+ ):
+ org_config = Mock(scratch=True, config={})
+ org_config.username = "test_user"
+ org_config.org_id = "test_org_id"
+ self.org_config = Mock(return_value=("test", org_config))
+ project_config = create_project_config()
+ flow_config = {
+ "test": {
+ "steps": {
+ 1: {
+ "flow": "test2",
+ }
+ }
+ },
+ "test2": {
+ "steps": {
+ 1: {
+ "task": "deploy",
+ "options": {"path": "force-app/main/default"},
+ }
+ }
+ },
+ }
+ plan_config = {
+ "title": "Test Install",
+ "slug": "install",
+ "tier": "primary",
+ "steps": {1: {"flow": "test"}},
+ }
+ project_config.config["plans"] = {
+ "Test Install": plan_config,
+ }
+ project_config.config["flows"] = flow_config
+
+ task = create_task(CheckComponents, {"name": "test2"})
+ task.deploy_paths = ["test"]
+
+ (components, response_messages) = task.get_repo_existing_components("test2")
+ assert "Type1" in components
+ assert "Type2" in components
+ assert "Comp1" in components["Type1"]
+ assert "Comp2" in components["Type2"]
+
+ @patch("os.path.exists", return_value=True)
+ @patch("os.remove")
+ @patch("os.path.isdir", return_value=True)
+ @patch("os.listdir", return_value=["package.xml"])
+ @patch("os.path.join", side_effect=lambda *args: "/".join(args))
+ @patch("cumulusci.core.sfdx.convert_sfdx_source")
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._is_plan",
+ return_value=False,
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._freeze_steps",
+ return_value=[],
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._collect_components_from_paths",
+ return_value=[{"Type1": ["Comp1"]}, []],
+ )
+ @patch(
+ "cumulusci.tasks.salesforce.check_components.CheckComponents._get_api_object_responce",
+ return_value=[],
+ )
+ @patch(
+ "builtins.open",
+ new_callable=mock_open,
+ read_data="""
+
+
+ Delivery
+ ApexClass
+
+
+ Delivery__c
+ CustomObject
+
+ 58.0
+
+ """,
+ )
+ @patch("cumulusci.utils.xml.metadata_tree.parse")
+ @patch(
+ "cumulusci.utils.xml.metadata_tree.parse_package_xml_types",
+ return_value={"Type2": ["Comp2"]},
+ )
+ def test_get_repo_existing_components_paths_paramter(
+ self,
+ mock_metadata_parse,
+ mock_open_file,
+ mock_convert_sfdx_source,
+ mock_path_join,
+ mock_listdir,
+ mock_isdir,
+ mock_remove,
+ mock_path_exists,
+ mock_is_plan,
+ mock_freeze_steps,
+ mock_get_api_object,
+ mock_parse,
+ mock_collect_components,
+ ):
+ org_config = Mock(scratch=True, config={})
+ org_config.username = "test_user"
+ org_config.org_id = "test_org_id"
+ self.org_config = Mock(return_value=("test", org_config))
+ project_config = create_project_config()
+ flow_config = {
+ "test": {
+ "steps": {
+ 1: {
+ "flow": "test2",
+ }
+ }
+ },
+ "test2": {
+ "steps": {
+ 1: {
+ "task": "deploy",
+ "options": {"path": "force-app/main/default"},
+ }
+ }
+ },
+ }
+ plan_config = {
+ "title": "Test Install",
+ "slug": "install",
+ "tier": "primary",
+ "steps": {1: {"flow": "test"}},
+ }
+ project_config.config["plans"] = {
+ "Test Install": plan_config,
+ }
+ project_config.config["flows"] = flow_config
+
+ task = create_task(CheckComponents, {"name": "test2"})
+ task.deploy_paths = ["test"]
+
+ (components, response_messages) = task.get_repo_existing_components("", "src")
+ assert "Type1" in components
+ assert "Type2" in components
+ assert "Comp1" in components["Type1"]
+ assert "Comp2" in components["Type2"]
+
@patch("os.path.exists", return_value=True)
@patch("os.remove")
@patch("os.path.isdir", return_value=True)