Skip to content

Commit dd39d53

Browse files
Merge pull request #3882 from SFDO-Tooling/Bugs_Check_Components
Fixed the mdapi issue for Check Components
2 parents df58663 + 5a8e936 commit dd39d53

3 files changed

Lines changed: 251 additions & 4 deletions

File tree

cumulusci/tasks/metadata/package.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,19 @@ def process_common_components(response_messages: List, components: Dict):
4545
"""Compare compoents in the api responce object with list of components and return common common components"""
4646
if not response_messages or not components:
4747
return components
48-
4948
for message in response_messages:
49+
5050
message_list = message.firstChild.nextSibling.firstChild.nodeValue.split("'")
5151
if len(message_list) > 1:
5252
component_type = message_list[1]
5353
message_txt = message_list[2]
54-
5554
if "is not available in this organization" in message_txt:
5655
del components[component_type]
56+
elif "is unknown" in message_txt:
57+
component_type = message_list[0].split(" ")
58+
components[component_type[0]].remove(message_list[1])
59+
if len(components[component_type]) == 0:
60+
del components[component_type]
5761
else:
5862
component_name = message_list[3]
5963
if component_name in components[component_type]:

cumulusci/tasks/salesforce/check_components.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import shutil
44
import tempfile
55
from collections import defaultdict
6+
from itertools import chain
67
from xml.etree.ElementTree import ParseError
78

89
from defusedxml.minidom import parseString
@@ -60,6 +61,7 @@ def _run_task(self):
6061
for component_type, component_names in components.items():
6162
self.logger.debug(f"{component_type}: {', '.join(component_names)}")
6263
# check common components
64+
components.pop("Settings", None)
6365
existing_components = process_common_components(
6466
api_retrieve_unpackaged_response, components
6567
)
@@ -102,12 +104,34 @@ def get_repo_existing_components(self, plan_or_flow_name, paths=""):
102104
# Temp dir to copy all deploy paths from task options
103105
temp_dir = tempfile.mkdtemp()
104106
self.logger.info(f"Temporary deploy directory created: {temp_dir}")
105-
107+
mdapi_components = {}
108+
mdapi_response_messages = []
106109
for path in self.deploy_paths:
107110
full_path = os.path.join(self.project_config.repo_root, path)
108111
if not os.path.exists(full_path):
109112
self.logger.info(f"Skipping path: '{path}' - path doesn't exist")
110113
continue
114+
elif "package.xml" in os.listdir(full_path):
115+
package_xml_path = os.path.join(full_path, "package.xml")
116+
source_xml_tree = metadata_tree.parse(package_xml_path)
117+
components = metadata_tree.parse_package_xml_types(
118+
"name", source_xml_tree
119+
)
120+
response_messages = self._get_api_object_responce(
121+
package_xml_path, source_xml_tree.version.text
122+
)
123+
merged = {}
124+
for key in set(components).union(mdapi_components):
125+
merged[key] = list(
126+
set(
127+
chain(
128+
components.get(key, []), mdapi_components.get(key, [])
129+
)
130+
)
131+
)
132+
mdapi_components = merged
133+
mdapi_response_messages.extend(response_messages)
134+
continue
111135
self._copy_to_tempdir(path, temp_dir)
112136

113137
(
@@ -117,6 +141,21 @@ def get_repo_existing_components(self, plan_or_flow_name, paths=""):
117141

118142
# remove temp dir
119143
shutil.rmtree(temp_dir)
144+
merged = {}
145+
if components:
146+
for key in set(components).union(mdapi_components):
147+
merged[key] = list(
148+
set(chain(components.get(key, []), mdapi_components.get(key, [])))
149+
)
150+
components = merged
151+
else:
152+
components = mdapi_components
153+
154+
if api_retrieve_unpackaged_response:
155+
api_retrieve_unpackaged_response.extend(mdapi_response_messages)
156+
else:
157+
api_retrieve_unpackaged_response = mdapi_response_messages
158+
120159
return [components, api_retrieve_unpackaged_response]
121160

122161
def _copy_to_tempdir(self, src_dir, temp_dir):

cumulusci/tasks/salesforce/tests/test_check_components.py

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from unittest.mock import ANY, MagicMock, mock_open, patch
1+
from unittest.mock import ANY, MagicMock, Mock, mock_open, patch
22

33
import pytest
44

@@ -11,6 +11,210 @@
1111

1212

1313
class TestCheckComponents:
14+
@patch("os.path.exists", return_value=True)
15+
@patch("os.remove")
16+
@patch("os.path.isdir", return_value=True)
17+
@patch("os.listdir", return_value=["package.xml"])
18+
@patch("os.path.join", side_effect=lambda *args: "/".join(args))
19+
@patch("cumulusci.core.sfdx.convert_sfdx_source")
20+
@patch(
21+
"cumulusci.tasks.salesforce.check_components.CheckComponents._is_plan",
22+
return_value=False,
23+
)
24+
@patch(
25+
"cumulusci.tasks.salesforce.check_components.CheckComponents._freeze_steps",
26+
return_value=[],
27+
)
28+
@patch(
29+
"cumulusci.tasks.salesforce.check_components.CheckComponents._collect_components_from_paths",
30+
return_value=[{"Type1": ["Comp1"]}, []],
31+
)
32+
@patch(
33+
"cumulusci.tasks.salesforce.check_components.CheckComponents._get_api_object_responce",
34+
return_value=[],
35+
)
36+
@patch(
37+
"builtins.open",
38+
new_callable=mock_open,
39+
read_data="""
40+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
41+
<types>
42+
<members>Delivery</members>
43+
<name>ApexClass</name>
44+
</types>
45+
<types>
46+
<members>Delivery__c</members>
47+
<name>CustomObject</name>
48+
</types>
49+
<version>58.0</version>
50+
</Package>
51+
""",
52+
)
53+
@patch("cumulusci.utils.xml.metadata_tree.parse")
54+
@patch(
55+
"cumulusci.utils.xml.metadata_tree.parse_package_xml_types",
56+
return_value={"Type2": ["Comp2"]},
57+
)
58+
def test_get_repo_existing_components(
59+
self,
60+
mock_metadata_parse,
61+
mock_open_file,
62+
mock_convert_sfdx_source,
63+
mock_path_join,
64+
mock_listdir,
65+
mock_isdir,
66+
mock_remove,
67+
mock_path_exists,
68+
mock_is_plan,
69+
mock_freeze_steps,
70+
mock_get_api_object,
71+
mock_parse,
72+
mock_collect_components,
73+
):
74+
org_config = Mock(scratch=True, config={})
75+
org_config.username = "test_user"
76+
org_config.org_id = "test_org_id"
77+
self.org_config = Mock(return_value=("test", org_config))
78+
project_config = create_project_config()
79+
flow_config = {
80+
"test": {
81+
"steps": {
82+
1: {
83+
"flow": "test2",
84+
}
85+
}
86+
},
87+
"test2": {
88+
"steps": {
89+
1: {
90+
"task": "deploy",
91+
"options": {"path": "force-app/main/default"},
92+
}
93+
}
94+
},
95+
}
96+
plan_config = {
97+
"title": "Test Install",
98+
"slug": "install",
99+
"tier": "primary",
100+
"steps": {1: {"flow": "test"}},
101+
}
102+
project_config.config["plans"] = {
103+
"Test Install": plan_config,
104+
}
105+
project_config.config["flows"] = flow_config
106+
107+
task = create_task(CheckComponents, {"name": "test2"})
108+
task.deploy_paths = ["test"]
109+
110+
(components, response_messages) = task.get_repo_existing_components("test2")
111+
assert "Type1" in components
112+
assert "Type2" in components
113+
assert "Comp1" in components["Type1"]
114+
assert "Comp2" in components["Type2"]
115+
116+
@patch("os.path.exists", return_value=True)
117+
@patch("os.remove")
118+
@patch("os.path.isdir", return_value=True)
119+
@patch("os.listdir", return_value=["package.xml"])
120+
@patch("os.path.join", side_effect=lambda *args: "/".join(args))
121+
@patch("cumulusci.core.sfdx.convert_sfdx_source")
122+
@patch(
123+
"cumulusci.tasks.salesforce.check_components.CheckComponents._is_plan",
124+
return_value=False,
125+
)
126+
@patch(
127+
"cumulusci.tasks.salesforce.check_components.CheckComponents._freeze_steps",
128+
return_value=[],
129+
)
130+
@patch(
131+
"cumulusci.tasks.salesforce.check_components.CheckComponents._collect_components_from_paths",
132+
return_value=[{"Type1": ["Comp1"]}, []],
133+
)
134+
@patch(
135+
"cumulusci.tasks.salesforce.check_components.CheckComponents._get_api_object_responce",
136+
return_value=[],
137+
)
138+
@patch(
139+
"builtins.open",
140+
new_callable=mock_open,
141+
read_data="""
142+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
143+
<types>
144+
<members>Delivery</members>
145+
<name>ApexClass</name>
146+
</types>
147+
<types>
148+
<members>Delivery__c</members>
149+
<name>CustomObject</name>
150+
</types>
151+
<version>58.0</version>
152+
</Package>
153+
""",
154+
)
155+
@patch("cumulusci.utils.xml.metadata_tree.parse")
156+
@patch(
157+
"cumulusci.utils.xml.metadata_tree.parse_package_xml_types",
158+
return_value={"Type2": ["Comp2"]},
159+
)
160+
def test_get_repo_existing_components_paths_paramter(
161+
self,
162+
mock_metadata_parse,
163+
mock_open_file,
164+
mock_convert_sfdx_source,
165+
mock_path_join,
166+
mock_listdir,
167+
mock_isdir,
168+
mock_remove,
169+
mock_path_exists,
170+
mock_is_plan,
171+
mock_freeze_steps,
172+
mock_get_api_object,
173+
mock_parse,
174+
mock_collect_components,
175+
):
176+
org_config = Mock(scratch=True, config={})
177+
org_config.username = "test_user"
178+
org_config.org_id = "test_org_id"
179+
self.org_config = Mock(return_value=("test", org_config))
180+
project_config = create_project_config()
181+
flow_config = {
182+
"test": {
183+
"steps": {
184+
1: {
185+
"flow": "test2",
186+
}
187+
}
188+
},
189+
"test2": {
190+
"steps": {
191+
1: {
192+
"task": "deploy",
193+
"options": {"path": "force-app/main/default"},
194+
}
195+
}
196+
},
197+
}
198+
plan_config = {
199+
"title": "Test Install",
200+
"slug": "install",
201+
"tier": "primary",
202+
"steps": {1: {"flow": "test"}},
203+
}
204+
project_config.config["plans"] = {
205+
"Test Install": plan_config,
206+
}
207+
project_config.config["flows"] = flow_config
208+
209+
task = create_task(CheckComponents, {"name": "test2"})
210+
task.deploy_paths = ["test"]
211+
212+
(components, response_messages) = task.get_repo_existing_components("", "src")
213+
assert "Type1" in components
214+
assert "Type2" in components
215+
assert "Comp1" in components["Type1"]
216+
assert "Comp2" in components["Type2"]
217+
14218
@patch("os.path.exists", return_value=True)
15219
@patch("os.remove")
16220
@patch("os.path.isdir", return_value=True)

0 commit comments

Comments
 (0)