Skip to content

Commit

Permalink
Merge pull request #3882 from SFDO-Tooling/Bugs_Check_Components
Browse files Browse the repository at this point in the history
Fixed the mdapi issue for Check Components
  • Loading branch information
jain-naman-sf authored Feb 19, 2025
2 parents df58663 + 5a8e936 commit dd39d53
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 4 deletions.
8 changes: 6 additions & 2 deletions cumulusci/tasks/metadata/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down
41 changes: 40 additions & 1 deletion cumulusci/tasks/salesforce/check_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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)

(
Expand All @@ -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):
Expand Down
206 changes: 205 additions & 1 deletion cumulusci/tasks/salesforce/tests/test_check_components.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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="""
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>Delivery</members>
<name>ApexClass</name>
</types>
<types>
<members>Delivery__c</members>
<name>CustomObject</name>
</types>
<version>58.0</version>
</Package>
""",
)
@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="""
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>Delivery</members>
<name>ApexClass</name>
</types>
<types>
<members>Delivery__c</members>
<name>CustomObject</name>
</types>
<version>58.0</version>
</Package>
""",
)
@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)
Expand Down

0 comments on commit dd39d53

Please sign in to comment.